mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-23 23:02:17 +10:00
343 lines
10 KiB
TypeScript
343 lines
10 KiB
TypeScript
import type { SemanticNodeKind } from "../types";
|
|
import { SEMANTIC_NODE_KINDS } from "./semantic";
|
|
|
|
export type PropertyDefinition = {
|
|
category:
|
|
| "flexbox"
|
|
| "layout"
|
|
| "dimension"
|
|
| "color"
|
|
| "text"
|
|
| "image"
|
|
| "spacing"
|
|
| "border"
|
|
| "transform"
|
|
| "structural";
|
|
inheritable: boolean;
|
|
appliesTo: readonly SemanticNodeKind[];
|
|
values: readonly string[];
|
|
units: readonly string[];
|
|
};
|
|
|
|
export type PropertyRegistry = Readonly<Record<string, PropertyDefinition | undefined>>;
|
|
|
|
export const SEMANTIC_CSS_CSS_WIDE_KEYWORDS_V1 = ["inherit", "initial", "revert", "unset"] as const;
|
|
export const SEMANTIC_CSS_LENGTH_UNITS_V1 = ["pt", "px", "in", "mm", "cm", "%", "vw", "vh", "em", "rem"] as const;
|
|
export const SEMANTIC_CSS_BORDER_STYLE_VALUES_V1 = ["dotted", "dashed", "solid"] as const;
|
|
export const SEMANTIC_CSS_LENGTH_VALUE_KEYWORDS_V1 = [
|
|
"auto",
|
|
"none",
|
|
"normal",
|
|
"max-content",
|
|
"min-content",
|
|
"fit-content",
|
|
"thin",
|
|
"medium",
|
|
"thick",
|
|
] as const;
|
|
export const SEMANTIC_CSS_LENGTH_PROPERTIES_V1 = [
|
|
"bottom",
|
|
"border-bottom-left-radius",
|
|
"border-bottom-right-radius",
|
|
"border-bottom-width",
|
|
"border-left-width",
|
|
"border-radius",
|
|
"border-right-width",
|
|
"border-top-left-radius",
|
|
"border-top-right-radius",
|
|
"border-top-width",
|
|
"border-width",
|
|
"column-gap",
|
|
"flex-basis",
|
|
"font-size",
|
|
"gap",
|
|
"height",
|
|
"left",
|
|
"letter-spacing",
|
|
"margin-bottom",
|
|
"margin-left",
|
|
"margin-right",
|
|
"margin-top",
|
|
"max-height",
|
|
"max-width",
|
|
"min-height",
|
|
"min-width",
|
|
"padding-bottom",
|
|
"padding-left",
|
|
"padding-right",
|
|
"padding-top",
|
|
"right",
|
|
"row-gap",
|
|
"text-indent",
|
|
"top",
|
|
"width",
|
|
"-resume-min-presence-ahead",
|
|
"-resume-shadow-width",
|
|
] as const;
|
|
|
|
const containerNodes = [
|
|
"page",
|
|
"region",
|
|
"header",
|
|
"contact-list",
|
|
"contact-item",
|
|
"section",
|
|
"section-heading",
|
|
"section-items",
|
|
"item",
|
|
"item-header",
|
|
"rich-text",
|
|
"list",
|
|
"list-item",
|
|
"horizontal-rule",
|
|
"template-part",
|
|
] as const satisfies readonly SemanticNodeKind[];
|
|
|
|
const textNodes = [
|
|
"name",
|
|
"headline",
|
|
"section-heading",
|
|
"combined-text",
|
|
"field",
|
|
"rich-heading",
|
|
"blockquote",
|
|
"paragraph",
|
|
"list-item-content",
|
|
"list-marker",
|
|
"strong",
|
|
"emphasis",
|
|
"underline",
|
|
"strike",
|
|
"code",
|
|
"text-span",
|
|
"mark",
|
|
"hard-break",
|
|
] as const satisfies readonly SemanticNodeKind[];
|
|
|
|
const linkContainerNodes = [...containerNodes, "link"] as SemanticNodeKind[];
|
|
const textAndLinkNodes = [...textNodes, "link"] as SemanticNodeKind[];
|
|
const colorNodes = [...containerNodes, ...textNodes, "link", "icon", "level"] as SemanticNodeKind[];
|
|
const spacingNodes = [...containerNodes, ...textNodes, "link", "picture"] as SemanticNodeKind[];
|
|
const structuralNodes = [...SEMANTIC_NODE_KINDS.filter((kind) => kind !== "resume")] as SemanticNodeKind[];
|
|
const lengthProperties = new Set<string>(SEMANTIC_CSS_LENGTH_PROPERTIES_V1);
|
|
const numericLengthUnits = SEMANTIC_CSS_LENGTH_UNITS_V1.filter((unit) => unit !== "%");
|
|
const borderStyleProperties = /^(?:border-style|border-(?:top|right|bottom|left)-style)$/;
|
|
const borderShorthandProperties = /^(?:border|border-(?:top|right|bottom|left))$/;
|
|
const propertyValueHints = {
|
|
"align-content": ["flex-start", "flex-end", "center", "stretch", "space-between", "space-around", "space-evenly"],
|
|
"align-items": ["flex-start", "flex-end", "center", "stretch", "baseline"],
|
|
"align-self": ["auto", "flex-start", "flex-end", "center", "stretch", "baseline"],
|
|
flex: ["none", "auto"],
|
|
"flex-direction": ["row", "row-reverse", "column", "column-reverse"],
|
|
"flex-wrap": ["nowrap", "wrap", "wrap-reverse"],
|
|
"flex-flow": ["row", "row-reverse", "column", "column-reverse", "nowrap", "wrap", "wrap-reverse"],
|
|
"justify-content": ["flex-start", "flex-end", "center", "space-between", "space-around", "space-evenly"],
|
|
display: ["flex", "none"],
|
|
position: ["absolute", "relative", "static"],
|
|
overflow: ["hidden"],
|
|
direction: ["ltr", "rtl"],
|
|
"font-style": ["normal", "italic"],
|
|
"font-weight": [
|
|
"thin",
|
|
"hairline",
|
|
"ultralight",
|
|
"extralight",
|
|
"light",
|
|
"normal",
|
|
"medium",
|
|
"semibold",
|
|
"demibold",
|
|
"bold",
|
|
"ultrabold",
|
|
"extrabold",
|
|
"heavy",
|
|
"black",
|
|
],
|
|
"line-height": ["normal"],
|
|
"text-align": ["left", "right", "center", "justify"],
|
|
"text-decoration": ["none", "underline", "line-through", "line-through underline", "underline line-through"],
|
|
"text-overflow": ["ellipsis"],
|
|
"text-transform": ["none", "capitalize", "lowercase", "uppercase", "upperfirst"],
|
|
"vertical-align": ["sub", "super"],
|
|
"object-fit": ["contain", "cover", "fill", "none", "scale-down"],
|
|
"object-position": ["left", "right", "top", "bottom", "center"],
|
|
"transform-origin": ["left", "right", "top", "bottom", "center"],
|
|
"break-before": ["auto", "page"],
|
|
"break-inside": ["auto", "avoid"],
|
|
size: ["A4", "letter"],
|
|
"-resume-fixed": ["true", "false", "0", "1"],
|
|
} as const satisfies Readonly<Record<string, readonly string[]>>;
|
|
|
|
function propertyValues(name: string): readonly string[] {
|
|
const values = borderStyleProperties.test(name)
|
|
? SEMANTIC_CSS_BORDER_STYLE_VALUES_V1
|
|
: borderShorthandProperties.test(name)
|
|
? SEMANTIC_CSS_BORDER_STYLE_VALUES_V1.map((style) => `1pt ${style}`)
|
|
: (propertyValueHints[name as keyof typeof propertyValueHints] ?? []);
|
|
return [...SEMANTIC_CSS_CSS_WIDE_KEYWORDS_V1, ...values];
|
|
}
|
|
|
|
function propertyUnits(name: string): readonly string[] {
|
|
if (name === "size" || name === "-resume-min-presence-ahead") return numericLengthUnits;
|
|
return lengthProperties.has(name) || name === "line-height" ? SEMANTIC_CSS_LENGTH_UNITS_V1 : [];
|
|
}
|
|
|
|
function entries(
|
|
names: readonly string[],
|
|
definition: Omit<PropertyDefinition, "units" | "values">,
|
|
): Readonly<Record<string, PropertyDefinition | undefined>> {
|
|
return Object.fromEntries(
|
|
names.map((name) => [
|
|
name,
|
|
{
|
|
...definition,
|
|
appliesTo: [...new Set(definition.appliesTo)],
|
|
values: propertyValues(name),
|
|
units: propertyUnits(name),
|
|
},
|
|
]),
|
|
);
|
|
}
|
|
|
|
const properties = {
|
|
...entries(
|
|
[
|
|
"align-content",
|
|
"align-items",
|
|
"align-self",
|
|
"flex",
|
|
"flex-direction",
|
|
"flex-wrap",
|
|
"flex-flow",
|
|
"flex-grow",
|
|
"flex-shrink",
|
|
"flex-basis",
|
|
"justify-content",
|
|
"gap",
|
|
"row-gap",
|
|
"column-gap",
|
|
],
|
|
{ category: "flexbox", inheritable: false, appliesTo: linkContainerNodes },
|
|
),
|
|
...entries(["aspect-ratio", "bottom"], {
|
|
category: "layout",
|
|
inheritable: false,
|
|
appliesTo: linkContainerNodes,
|
|
}),
|
|
...entries(["display"], {
|
|
category: "layout",
|
|
inheritable: false,
|
|
appliesTo: [...linkContainerNodes, "list-item-content", "list-marker"],
|
|
}),
|
|
...entries(["left", "position", "right", "top", "overflow", "z-index"], {
|
|
category: "layout",
|
|
inheritable: false,
|
|
appliesTo: linkContainerNodes,
|
|
}),
|
|
...entries(["width", "height", "min-width", "min-height", "max-width", "max-height"], {
|
|
category: "dimension",
|
|
inheritable: false,
|
|
appliesTo: [...linkContainerNodes, "picture"],
|
|
}),
|
|
...entries(["color"], { category: "color", inheritable: true, appliesTo: colorNodes }),
|
|
...entries(["background-color"], { category: "color", inheritable: false, appliesTo: linkContainerNodes }),
|
|
...entries(["opacity"], { category: "color", inheritable: false, appliesTo: colorNodes }),
|
|
...entries(["direction"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
|
...entries(["font-size"], {
|
|
category: "text",
|
|
inheritable: true,
|
|
appliesTo: [...textAndLinkNodes, "icon", "level"],
|
|
}),
|
|
...entries(["font-style", "font-weight", "letter-spacing", "line-height"], {
|
|
category: "text",
|
|
inheritable: true,
|
|
appliesTo: textAndLinkNodes,
|
|
}),
|
|
...entries(["max-lines"], { category: "text", inheritable: false, appliesTo: textAndLinkNodes }),
|
|
...entries(["text-align"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
|
...entries(["text-decoration", "text-decoration-color", "text-decoration-style"], {
|
|
category: "text",
|
|
inheritable: false,
|
|
appliesTo: textAndLinkNodes,
|
|
}),
|
|
...entries(["text-indent"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
|
...entries(["text-overflow"], { category: "text", inheritable: false, appliesTo: textAndLinkNodes }),
|
|
...entries(["text-transform"], { category: "text", inheritable: true, appliesTo: textAndLinkNodes }),
|
|
...entries(["vertical-align"], { category: "text", inheritable: false, appliesTo: textAndLinkNodes }),
|
|
...entries(["object-fit", "object-position"], { category: "image", inheritable: false, appliesTo: ["picture"] }),
|
|
...entries(["-resume-shadow-color", "-resume-shadow-width"], {
|
|
category: "image",
|
|
inheritable: false,
|
|
appliesTo: ["picture"],
|
|
}),
|
|
...entries(
|
|
[
|
|
"margin",
|
|
"margin-top",
|
|
"margin-right",
|
|
"margin-bottom",
|
|
"margin-left",
|
|
"margin-horizontal",
|
|
"margin-vertical",
|
|
"padding",
|
|
"padding-top",
|
|
"padding-right",
|
|
"padding-bottom",
|
|
"padding-left",
|
|
"padding-horizontal",
|
|
"padding-vertical",
|
|
],
|
|
{ category: "spacing", inheritable: false, appliesTo: spacingNodes },
|
|
),
|
|
...entries(
|
|
[
|
|
"border",
|
|
"border-color",
|
|
"border-style",
|
|
"border-width",
|
|
"border-top",
|
|
"border-right",
|
|
"border-bottom",
|
|
"border-left",
|
|
"border-top-color",
|
|
"border-top-style",
|
|
"border-top-width",
|
|
"border-right-color",
|
|
"border-right-style",
|
|
"border-right-width",
|
|
"border-bottom-color",
|
|
"border-bottom-style",
|
|
"border-bottom-width",
|
|
"border-left-color",
|
|
"border-left-style",
|
|
"border-left-width",
|
|
"border-radius",
|
|
"border-top-left-radius",
|
|
"border-top-right-radius",
|
|
"border-bottom-right-radius",
|
|
"border-bottom-left-radius",
|
|
],
|
|
{ category: "border", inheritable: false, appliesTo: [...linkContainerNodes, "picture"] },
|
|
),
|
|
...entries(["transform", "transform-origin"], {
|
|
category: "transform",
|
|
inheritable: false,
|
|
appliesTo: [...linkContainerNodes, "picture"],
|
|
}),
|
|
...entries(["order", "break-before", "break-inside"], {
|
|
category: "structural",
|
|
inheritable: false,
|
|
appliesTo: structuralNodes,
|
|
}),
|
|
...entries(["orphans", "widows"], { category: "structural", inheritable: false, appliesTo: textNodes }),
|
|
...entries(["size"], { category: "structural", inheritable: false, appliesTo: ["page"] }),
|
|
...entries(["-resume-fixed"], { category: "structural", inheritable: false, appliesTo: structuralNodes }),
|
|
...entries(["-resume-min-presence-ahead"], {
|
|
category: "structural",
|
|
inheritable: false,
|
|
appliesTo: structuralNodes,
|
|
}),
|
|
} satisfies PropertyRegistry;
|
|
|
|
export const PROPERTY_REGISTRY_V1: PropertyRegistry = properties;
|