mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-24 07:12:18 +10:00
87 lines
3.4 KiB
TypeScript
87 lines
3.4 KiB
TypeScript
import type { Style } from "@react-pdf/types";
|
|
import type { ResolvedNodeStyle, ResolvedPageSize } from "@reactive-resume/resume/stylesheet";
|
|
|
|
type ResolvedPdfPageSize = ResolvedPageSize;
|
|
|
|
export type ResolvedPdfNodePresentation = {
|
|
style?: Style;
|
|
size?: ResolvedPdfPageSize;
|
|
break?: boolean;
|
|
wrap?: boolean;
|
|
fixed?: boolean;
|
|
minPresenceAhead?: number;
|
|
orphans?: number;
|
|
widows?: number;
|
|
};
|
|
|
|
export type ResolvedPdfFlowProps = Omit<ResolvedPdfNodePresentation, "style" | "size" | "orphans" | "widows">;
|
|
export type ResolvedPdfTextProps = Omit<ResolvedPdfNodePresentation, "style" | "size">;
|
|
|
|
export const resolvedPdfFlowProps = ({
|
|
break: breakBefore,
|
|
wrap,
|
|
fixed,
|
|
minPresenceAhead,
|
|
}: ResolvedPdfNodePresentation): ResolvedPdfFlowProps => ({
|
|
...(breakBefore === undefined ? {} : { break: breakBefore }),
|
|
...(wrap === undefined ? {} : { wrap }),
|
|
...(fixed === undefined ? {} : { fixed }),
|
|
...(minPresenceAhead === undefined ? {} : { minPresenceAhead }),
|
|
});
|
|
|
|
export const resolvedPdfTextProps = ({
|
|
orphans,
|
|
widows,
|
|
...presentation
|
|
}: ResolvedPdfNodePresentation): ResolvedPdfTextProps => ({
|
|
...resolvedPdfFlowProps(presentation),
|
|
...(orphans === undefined ? {} : { orphans }),
|
|
...(widows === undefined ? {} : { widows }),
|
|
});
|
|
|
|
const toReactPdfProperty = (property: string) => {
|
|
if (property === "-resume-shadow-color") return "shadowColor";
|
|
if (property === "-resume-shadow-width") return "shadowWidth";
|
|
return property.replace(/-([a-z])/g, (_match, letter: string) => letter.toUpperCase());
|
|
};
|
|
|
|
const styleDelta = (resolved: ResolvedNodeStyle, base: ResolvedNodeStyle["style"] | undefined): Style | undefined => {
|
|
const specified = new Set(resolved.specifiedStyleProperties);
|
|
const hostBase = new Set(resolved.hostBaseStyleProperties);
|
|
const entries: [string, string | number | undefined][] =
|
|
base === undefined
|
|
? Object.entries(resolved.style)
|
|
: Object.entries(resolved.style).filter(([property]) => !hostBase.has(property) && specified.has(property));
|
|
for (const property of specified) {
|
|
if (!hostBase.has(property) && !(property in resolved.style)) entries.push([property, undefined]);
|
|
}
|
|
if (entries.length === 0) return undefined;
|
|
|
|
return Object.freeze(
|
|
Object.fromEntries(entries.map(([property, value]) => [toReactPdfProperty(property), value])),
|
|
) as Style;
|
|
};
|
|
|
|
export function adaptResolvedPdfNode(
|
|
resolved: ResolvedNodeStyle,
|
|
base?: ResolvedNodeStyle,
|
|
): ResolvedPdfNodePresentation {
|
|
const style = styleDelta(resolved, base?.style);
|
|
const { structural } = resolved;
|
|
const breakBefore =
|
|
structural.breakBefore === "page" ? true : base?.structural.breakBefore === "page" ? false : undefined;
|
|
const wrap = structural.breakInside === "avoid" ? false : base?.structural.breakInside === "avoid" ? true : undefined;
|
|
const presentation = {
|
|
...(style ? { style } : {}),
|
|
...(structural.pageSize === undefined ? {} : { size: structural.pageSize }),
|
|
...(breakBefore === undefined ? {} : { break: breakBefore }),
|
|
...(wrap === undefined ? {} : { wrap }),
|
|
...(structural.fixed === undefined ? {} : { fixed: structural.fixed }),
|
|
...(structural.minPresenceAhead === undefined ? {} : { minPresenceAhead: structural.minPresenceAhead }),
|
|
...(structural.orphans === undefined ? {} : { orphans: structural.orphans }),
|
|
...(structural.widows === undefined ? {} : { widows: structural.widows }),
|
|
} satisfies ResolvedPdfNodePresentation;
|
|
|
|
return Object.freeze(presentation);
|
|
}
|