@theme-registry/refract 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/_createTheme-255ff48e.esm.js +2 -0
- package/dist/_createTheme-255ff48e.esm.js.map +1 -0
- package/dist/_createTheme-41c01033.cjs.js +2 -0
- package/dist/_createTheme-41c01033.cjs.js.map +1 -0
- package/dist/_errors-be768b25.cjs.js +2 -0
- package/dist/_errors-be768b25.cjs.js.map +1 -0
- package/dist/_errors-d75a5c74.esm.js +2 -0
- package/dist/_errors-d75a5c74.esm.js.map +1 -0
- package/dist/adapter-kit.cjs.js +2 -0
- package/dist/adapter-kit.cjs.js.map +1 -0
- package/dist/adapter-kit.d.ts +88 -0
- package/dist/adapter-kit.esm.js +2 -0
- package/dist/adapter-kit.esm.js.map +1 -0
- package/dist/build/auditCommand.d.ts +19 -0
- package/dist/build/buildCommand.d.ts +23 -0
- package/dist/build/cli.d.ts +2 -0
- package/dist/build/config.d.ts +58 -0
- package/dist/build/diff.d.ts +56 -0
- package/dist/build/diffCommand.d.ts +29 -0
- package/dist/build/emit.d.ts +20 -0
- package/dist/build/emitTheme.d.ts +39 -0
- package/dist/build/guide.d.ts +34 -0
- package/dist/build/importCommand.d.ts +42 -0
- package/dist/build/index.d.ts +33 -0
- package/dist/build/init.d.ts +32 -0
- package/dist/build/paths.d.ts +42 -0
- package/dist/build/skillsCommand.d.ts +53 -0
- package/dist/build/tokensCommand.d.ts +17 -0
- package/dist/build/vendor.d.ts +39 -0
- package/dist/build.cjs.js +2 -0
- package/dist/build.cjs.js.map +1 -0
- package/dist/build.esm.js +2 -0
- package/dist/build.esm.js.map +1 -0
- package/dist/cli.js +8250 -0
- package/dist/cli.js.map +1 -0
- package/dist/color-math.cjs.js +2 -0
- package/dist/color-math.cjs.js.map +1 -0
- package/dist/color-math.esm.js +2 -0
- package/dist/color-math.esm.js.map +1 -0
- package/dist/core/ThemeAdapter.d.ts +234 -0
- package/dist/core/createTheme.d.ts +96 -0
- package/dist/core/cssProperties.d.ts +8 -0
- package/dist/core/defineAdapter.d.ts +25 -0
- package/dist/core/derive/crossProperty.d.ts +31 -0
- package/dist/core/derive/index.d.ts +11 -0
- package/dist/core/derive/resolveTokens.d.ts +27 -0
- package/dist/core/errors.d.ts +24 -0
- package/dist/core/index.d.ts +16 -0
- package/dist/core/media/containers.d.ts +20 -0
- package/dist/core/media/defaults.d.ts +3 -0
- package/dist/core/media/descriptors.d.ts +12 -0
- package/dist/core/media/index.d.ts +11 -0
- package/dist/core/media/queries.d.ts +20 -0
- package/dist/core/model/buildModel.d.ts +116 -0
- package/dist/core/model/index.d.ts +14 -0
- package/dist/core/model/interpreted.d.ts +37 -0
- package/dist/core/model/mergeRuleSet.d.ts +68 -0
- package/dist/core/model/model.d.ts +260 -0
- package/dist/core/noopAdapter.d.ts +26 -0
- package/dist/core/normalize/index.d.ts +15 -0
- package/dist/core/normalize/properties.d.ts +20 -0
- package/dist/core/normalize/recipeResolver.d.ts +19 -0
- package/dist/core/normalize/recipes.d.ts +38 -0
- package/dist/core/normalize/responsive.d.ts +40 -0
- package/dist/core/normalize/types.d.ts +261 -0
- package/dist/core/rawTheme.d.ts +53 -0
- package/dist/core/ref.d.ts +13 -0
- package/dist/core/subsystem.d.ts +115 -0
- package/dist/core/types.d.ts +31 -0
- package/dist/core/units.d.ts +93 -0
- package/dist/dtcg/export.d.ts +48 -0
- package/dist/dtcg/import.d.ts +43 -0
- package/dist/dtcg/index.d.ts +21 -0
- package/dist/dtcg/parse.d.ts +6 -0
- package/dist/dtcg/types.d.ts +69 -0
- package/dist/dtcg.cjs.js +2 -0
- package/dist/dtcg.cjs.js.map +1 -0
- package/dist/dtcg.esm.js +2 -0
- package/dist/dtcg.esm.js.map +1 -0
- package/dist/index.cjs.js +2 -0
- package/dist/index.cjs.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.esm.js +2 -0
- package/dist/index.esm.js.map +1 -0
- package/dist/subsystems/animation/index.d.ts +13 -0
- package/dist/subsystems/animation/recipes.d.ts +20 -0
- package/dist/subsystems/animation/types.d.ts +52 -0
- package/dist/subsystems/borders/index.d.ts +10 -0
- package/dist/subsystems/borders/recipes.d.ts +29 -0
- package/dist/subsystems/borders/types.d.ts +50 -0
- package/dist/subsystems/colors/audit.d.ts +67 -0
- package/dist/subsystems/colors/colorInput.d.ts +17 -0
- package/dist/subsystems/colors/index.d.ts +12 -0
- package/dist/subsystems/colors/keywords.d.ts +9 -0
- package/dist/subsystems/colors/normalize.d.ts +26 -0
- package/dist/subsystems/colors/recipes.d.ts +21 -0
- package/dist/subsystems/colors/types.d.ts +98 -0
- package/dist/subsystems/colors/utils.d.ts +104 -0
- package/dist/subsystems/components/index.d.ts +13 -0
- package/dist/subsystems/components/recipes.d.ts +22 -0
- package/dist/subsystems/components/types.d.ts +46 -0
- package/dist/subsystems/effects/index.d.ts +9 -0
- package/dist/subsystems/effects/recipes.d.ts +24 -0
- package/dist/subsystems/effects/types.d.ts +63 -0
- package/dist/subsystems/effects/utils.d.ts +57 -0
- package/dist/subsystems/globals/index.d.ts +21 -0
- package/dist/subsystems/globals/presets.d.ts +33 -0
- package/dist/subsystems/globals/types.d.ts +48 -0
- package/dist/subsystems/index.d.ts +21 -0
- package/dist/subsystems/layout/index.d.ts +14 -0
- package/dist/subsystems/layout/normalize.d.ts +35 -0
- package/dist/subsystems/layout/recipes.d.ts +16 -0
- package/dist/subsystems/layout/structural.d.ts +37 -0
- package/dist/subsystems/layout/types.d.ts +154 -0
- package/dist/subsystems/typography/index.d.ts +9 -0
- package/dist/subsystems/typography/normalize.d.ts +17 -0
- package/dist/subsystems/typography/recipes.d.ts +21 -0
- package/dist/subsystems/typography/types.d.ts +49 -0
- package/package.json +83 -0
- package/skills/adapter-scaffold/SKILL.md +85 -0
- package/skills/adapter-usage/SKILL.md +75 -0
- package/skills/build-config/SKILL.md +77 -0
- package/skills/colors/SKILL.md +134 -0
- package/skills/consuming-the-output/SKILL.md +62 -0
- package/skills/dtcg-import/SKILL.md +76 -0
- package/skills/layout/SKILL.md +65 -0
- package/skills/overrides-and-child-themes/SKILL.md +70 -0
- package/skills/recipes-and-composition/SKILL.md +110 -0
- package/skills/theme-authoring/SKILL.md +107 -0
- package/skills/theme-foundations/SKILL.md +127 -0
- package/skills/troubleshooting/SKILL.md +97 -0
- package/skills/typography/SKILL.md +66 -0
- package/skills/visual-effects/SKILL.md +96 -0
- package/src/subsystems/colors/utils.ts +299 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Theme } from "../core";
|
|
2
|
+
import type { RuleSetGroup, Keyframe, ContainerModel, PropertyModel } from "../core";
|
|
3
|
+
import type { DTCGDocument } from "./types";
|
|
4
|
+
/** The refract round-trip payload stashed under {@link REFRACT_DTCG_EXTENSION}. Built IR, verbatim. */
|
|
5
|
+
export type RefractDTCGExtension = {
|
|
6
|
+
version: number;
|
|
7
|
+
/**
|
|
8
|
+
* Per-subsystem property Model verbatim (§12 Phase 2) — the lossless channel for what the portable
|
|
9
|
+
* DTCG token surface can't carry: appearance `modes` (a `PropertyOverride[]` list), `responsive`
|
|
10
|
+
* overrides, derivation metadata (`{ ref, modifiers }`), and `external` passthroughs. Reinjected on
|
|
11
|
+
* import via createTheme's `propertiesOverlay`. The standard resolved-literal tokens still emit
|
|
12
|
+
* alongside for portability; this is refract-only (other tools ignore the extension).
|
|
13
|
+
*/
|
|
14
|
+
properties?: Record<string, Record<string, PropertyModel>>;
|
|
15
|
+
ruleSets?: Record<string, Record<string, RuleSetGroup>>;
|
|
16
|
+
keyframes?: Record<string, Record<string, Keyframe>>;
|
|
17
|
+
containers?: Record<string, ContainerModel>;
|
|
18
|
+
};
|
|
19
|
+
export type ToDTCGOptions = {
|
|
20
|
+
/** Name for the DTCG document. */
|
|
21
|
+
name?: string;
|
|
22
|
+
/** Whether to include breakpoints as dimension tokens. Default: true. */
|
|
23
|
+
includeBreakpoints?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Stash the theme's built Model IR — **property tokens (incl. modes / responsive / derivation refs /
|
|
26
|
+
* external), rule-sets, keyframes, containers** — under the reverse-DNS `com.theme-registry.refract`
|
|
27
|
+
* `$extensions` key, so the document round-trips `refract → DTCG → refract` **losslessly** via
|
|
28
|
+
* {@link fromDTCGTheme} (§12 Phase 2 widened this from recipes-only to the whole Model). **Not
|
|
29
|
+
* portable** — other DTCG tools ignore the extension and see the resolved property tokens only.
|
|
30
|
+
* Default `false` (standard output stays byte-identical).
|
|
31
|
+
*/
|
|
32
|
+
includeRecipes?: boolean;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* Convert a built theme's tokens into a DTCG-compliant JSON document.
|
|
36
|
+
*
|
|
37
|
+
* **Model-first re-port:** this walks the flat, format-neutral `theme.tokens` map
|
|
38
|
+
* (`"<subsystem>.<property>[.<variant>]" -> Ref`) — the single source of truth that
|
|
39
|
+
* replaced the retired per-subsystem `theme.<sub>.tokens` shape. Each token path is
|
|
40
|
+
* resolved to a concrete literal via `theme.resolveToken` (following aliases and
|
|
41
|
+
* running `lighten` / `darken` derivations), then re-grouped into DTCG groups.
|
|
42
|
+
*
|
|
43
|
+
* DTCG carries **property tokens only** — recipes / composition are out of scope, and
|
|
44
|
+
* layout structural-config knobs (property names containing `--`) are skipped.
|
|
45
|
+
*
|
|
46
|
+
* Returns a plain object — modify it freely before writing to a file.
|
|
47
|
+
*/
|
|
48
|
+
export declare const toDTCG: (theme: Theme, options?: ToDTCGOptions) => DTCGDocument;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { DTCGDocument } from "./types";
|
|
2
|
+
import type { RefractDTCGExtension } from "./export";
|
|
3
|
+
import type { Theme, ThemeAdapter } from "../core";
|
|
4
|
+
type RawThemeInput = Record<string, unknown>;
|
|
5
|
+
export type FromDTCGOptions = {
|
|
6
|
+
/**
|
|
7
|
+
* How to map DTCG groups to refract subsystems.
|
|
8
|
+
* Default: auto-detect from $type and group name.
|
|
9
|
+
*/
|
|
10
|
+
groupMapping?: Record<string, "colors" | "typography" | "effects" | "borders" | "layout" | "ignore">;
|
|
11
|
+
/**
|
|
12
|
+
* Breakpoints as { name: pixelValue } — DTCG has no breakpoint type,
|
|
13
|
+
* so these must be provided separately or mapped from dimension tokens.
|
|
14
|
+
*/
|
|
15
|
+
breakpoints?: Record<string, number>;
|
|
16
|
+
/**
|
|
17
|
+
* DTCG group path to use as breakpoints source (e.g. "breakpoint").
|
|
18
|
+
* Dimension values are parsed to pixels.
|
|
19
|
+
*/
|
|
20
|
+
breakpointGroup?: string;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Convert a DTCG token document into a `createTheme` raw input.
|
|
24
|
+
*
|
|
25
|
+
* Returns a plain object — modify it freely before passing to `createTheme`.
|
|
26
|
+
*/
|
|
27
|
+
export declare const fromDTCG: (doc: DTCGDocument, options?: FromDTCGOptions) => RawThemeInput;
|
|
28
|
+
/**
|
|
29
|
+
* Read the refract round-trip payload from a DTCG document's top-level `$extensions`, or `undefined`
|
|
30
|
+
* when it carries none. `parseDTCGDocument` intentionally drops top-level `$extensions`, so this reads
|
|
31
|
+
* `doc.$extensions` directly. Throws on a payload from a newer, unreadable schema version.
|
|
32
|
+
*/
|
|
33
|
+
export declare const readRefractExtension: (doc: DTCGDocument) => RefractDTCGExtension | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Lossless `DTCG → refract` round-trip entry: {@link fromDTCG} for the property tokens, plus the
|
|
36
|
+
* recipes / keyframes / containers the document stashed under `com.theme-registry.refract` reinjected
|
|
37
|
+
* through createTheme's overlay. A plain DTCG document (no refract extension) round-trips to a
|
|
38
|
+
* recipe-less theme — identical to `createTheme(fromDTCG(doc), { adapter })`.
|
|
39
|
+
*/
|
|
40
|
+
export declare const fromDTCGTheme: (doc: DTCGDocument, options: FromDTCGOptions & {
|
|
41
|
+
adapter: ThemeAdapter;
|
|
42
|
+
}) => Theme;
|
|
43
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Design Token Community Group (DTCG / W3C) interop — a **data-interchange** surface,
|
|
3
|
+
* NOT an output adapter. It reads/writes the standard `tokens.json` format so a theme
|
|
4
|
+
* can round-trip through Figma / Style Dictionary / other DTCG tooling.
|
|
5
|
+
*
|
|
6
|
+
* - `fromDTCG(doc, opts?) -> raw` — a DTCG document → a `createTheme` raw input.
|
|
7
|
+
* - `toDTCG(theme, opts?) -> doc` — a built theme's flat `theme.tokens` → a DTCG document.
|
|
8
|
+
* - `parseDTCGDocument(doc)` — the low-level walker (resolves `{ref}` chains → resolved tokens).
|
|
9
|
+
* - `fromDTCGTheme(doc, { adapter })` — the lossless `refract → DTCG → refract` round-trip entry.
|
|
10
|
+
*
|
|
11
|
+
* Model-first: `toDTCG` walks the flat `theme.tokens` map + `theme.resolveToken` + the Model's
|
|
12
|
+
* breakpoints. The interoperable surface is **property tokens only** — recipes / composition are out
|
|
13
|
+
* of standard DTCG scope. Opt-in `toDTCG(theme, { includeRecipes: true })` stashes the built rule-set
|
|
14
|
+
* IR under the reverse-DNS `com.theme-registry.refract` `$extensions` key so a document round-trips
|
|
15
|
+
* back through `fromDTCGTheme`; other DTCG tools ignore that key. DTCG does not go through the
|
|
16
|
+
* `ThemeAdapter` contract.
|
|
17
|
+
*/
|
|
18
|
+
export * from "./types";
|
|
19
|
+
export * from "./parse";
|
|
20
|
+
export * from "./import";
|
|
21
|
+
export * from "./export";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { DTCGDocument, ResolvedDTCGToken } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Walk a DTCG document and extract all tokens with resolved types and paths.
|
|
4
|
+
* References (`{path.to.token}`) are resolved recursively.
|
|
5
|
+
*/
|
|
6
|
+
export declare const parseDTCGDocument: (doc: DTCGDocument) => ResolvedDTCGToken[];
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* W3C Design Tokens Community Group (DTCG) format types.
|
|
3
|
+
* Based on Second Editors' Draft (2024).
|
|
4
|
+
*/
|
|
5
|
+
export type DTCGColorValue = string;
|
|
6
|
+
export type DTCGDimensionValue = string;
|
|
7
|
+
export type DTCGFontFamilyValue = string | string[];
|
|
8
|
+
export type DTCGFontWeightValue = number | string;
|
|
9
|
+
export type DTCGDurationValue = string;
|
|
10
|
+
export type DTCGCubicBezierValue = [number, number, number, number];
|
|
11
|
+
export type DTCGNumberValue = number;
|
|
12
|
+
export type DTCGTypographyValue = {
|
|
13
|
+
fontFamily: string | string[];
|
|
14
|
+
fontSize: string;
|
|
15
|
+
fontWeight: number | string;
|
|
16
|
+
lineHeight: number | string;
|
|
17
|
+
letterSpacing?: string;
|
|
18
|
+
};
|
|
19
|
+
export type DTCGShadowLayerValue = {
|
|
20
|
+
offsetX: string;
|
|
21
|
+
offsetY: string;
|
|
22
|
+
blur: string;
|
|
23
|
+
spread: string;
|
|
24
|
+
color: string;
|
|
25
|
+
inset?: boolean;
|
|
26
|
+
};
|
|
27
|
+
export type DTCGShadowValue = DTCGShadowLayerValue | DTCGShadowLayerValue[];
|
|
28
|
+
export type DTCGBorderValue = {
|
|
29
|
+
color: string;
|
|
30
|
+
width: string;
|
|
31
|
+
style: string;
|
|
32
|
+
};
|
|
33
|
+
export type DTCGTransitionValue = {
|
|
34
|
+
duration: string;
|
|
35
|
+
delay?: string;
|
|
36
|
+
timingFunction: DTCGCubicBezierValue;
|
|
37
|
+
};
|
|
38
|
+
export type DTCGTokenType = "color" | "dimension" | "fontFamily" | "fontWeight" | "duration" | "cubicBezier" | "number" | "typography" | "shadow" | "border" | "transition" | "strokeStyle" | "gradient";
|
|
39
|
+
export type DTCGToken = {
|
|
40
|
+
$value: unknown;
|
|
41
|
+
$type?: DTCGTokenType;
|
|
42
|
+
$description?: string;
|
|
43
|
+
$extensions?: Record<string, unknown>;
|
|
44
|
+
};
|
|
45
|
+
export type DTCGGroup = {
|
|
46
|
+
$type?: DTCGTokenType;
|
|
47
|
+
$description?: string;
|
|
48
|
+
$extensions?: Record<string, unknown>;
|
|
49
|
+
[key: string]: DTCGToken | DTCGGroup | DTCGTokenType | string | Record<string, unknown> | undefined;
|
|
50
|
+
};
|
|
51
|
+
export type DTCGDocument = DTCGGroup & {
|
|
52
|
+
$name?: string;
|
|
53
|
+
};
|
|
54
|
+
export type ResolvedDTCGToken = {
|
|
55
|
+
path: string[];
|
|
56
|
+
type: DTCGTokenType;
|
|
57
|
+
value: unknown;
|
|
58
|
+
description?: string;
|
|
59
|
+
extensions?: Record<string, unknown>;
|
|
60
|
+
};
|
|
61
|
+
/**
|
|
62
|
+
* The reverse-DNS `$extensions` key under which `toDTCG(theme, { includeRecipes: true })` stashes the
|
|
63
|
+
* built rule-set / keyframe / container IR so a document round-trips `refract → DTCG → refract` without
|
|
64
|
+
* loss. Standard DTCG tools ignore unknown extensions, so the payload is **refract-specific and not
|
|
65
|
+
* portable** — property tokens are the interoperable surface; recipes ride here.
|
|
66
|
+
*/
|
|
67
|
+
export declare const REFRACT_DTCG_EXTENSION = "com.theme-registry.refract";
|
|
68
|
+
/** The payload schema version under {@link REFRACT_DTCG_EXTENSION}; bumped on a breaking shape change. */
|
|
69
|
+
export declare const REFRACT_DTCG_EXTENSION_VERSION = 1;
|
package/dist/dtcg.cjs.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";var e=require("./_errors-be768b25.cjs.js"),t=require("./_createTheme-41c01033.cjs.js"),n=require("./color-math.cjs.js");const o="com.theme-registry.refract",s=e=>"object"==typeof e&&null!==e&&"$value"in e,r=e=>{const t=[],n=new Map,o=(e,r,i)=>{var a,c,l;const u=null!==(a=e.$type)&&void 0!==a?a:i;for(const[i,a]of Object.entries(e)){if(i.startsWith("$"))continue;if("object"!=typeof a||null===a)continue;const e=[...r,i];if(s(a)){const o=a,s={path:e,type:null!==(l=null!==(c=o.$type)&&void 0!==c?c:u)&&void 0!==l?l:"color",value:o.$value,description:o.$description,extensions:o.$extensions};t.push(s),n.set(e.join("."),s)}else o(a,e,u)}};o(e,[]);for(const e of t)e.value=a(e.value,n);return t},i=/^\{([^}]+)\}$/,a=(t,n,o=new Set)=>{if("string"==typeof t){const s=t.match(i);if(s){const r=s[1];if(o.has(r))throw new e.RefractError("REFRACT_E_CYCLE",`Circular token reference: ${r}`);const i=n.get(r);return i?(o.add(r),a(i.value,n,o)):t}return t}if(Array.isArray(t))return t.map(e=>a(e,n,new Set(o)));if("object"==typeof t&&null!==t){const e={};for(const[s,r]of Object.entries(t))e[s]=a(r,n,new Set(o));return e}return t},c=(e,t)=>{var n,o,s;const i=r(e),a=null!==(n=null==t?void 0:t.groupMapping)&&void 0!==n?n:{},c={},u={},f={},d={},h={};let b=null!==(o=null==t?void 0:t.breakpoints)&&void 0!==o?o:{};const m=new Map;for(const e of i){const t=e.path[0];m.has(t)||m.set(t,[]),m.get(t).push(e)}const j=null==t?void 0:t.breakpointGroup;if(j&&m.has(j)){b={};for(const e of m.get(j)){b[e.path[e.path.length-1]]=x(e.value)}m.delete(j)}for(const[e,t]of m){const n=null!==(s=a[e])&&void 0!==s?s:l(e,t);if("ignore"!==n)switch(n){case"colors":p(t,e,c);break;case"typography":y(t,e,u);break;case"effects":v(t,e,f);break;case"borders":g(t,e,d);break;case"layout":k(t,e,h)}}const $={};return Object.keys(b).length&&($.breakpoints=b),Object.keys(c).length&&($.colors=c),Object.keys(u).length&&($.typography=u),Object.keys(f).length&&($.effects=f),Object.keys(d).length&&($.borders=d),Object.keys(h).length&&($.layout=h),$},l=(e,t)=>{var n;const o=null===(n=t[0])||void 0===n?void 0:n.type;if("color"===o)return"colors";if("typography"===o)return"typography";if("shadow"===o)return"effects";if("border"===o)return"borders";if("strokeStyle"===o)return"borders";if("transition"===o)return"effects";const s=e.toLowerCase();if(s.includes("color")||s.includes("palette"))return"colors";if(s.includes("font")||s.includes("typo")||s.includes("text"))return"typography";if(s.includes("spacing")||s.includes("space")||s.includes("gutter"))return"layout";if(s.includes("radius")||s.includes("border")||s.includes("outline"))return"borders";if(s.includes("shadow")||s.includes("blur")||s.includes("opacity")||s.includes("z-index")||s.includes("zindex")||s.includes("transition")||s.includes("effect"))return"effects";if("dimension"===o){if(s.includes("spacing")||s.includes("gap"))return"layout";if(s.includes("radius")||s.includes("border"))return"borders";if(s.includes("font")||s.includes("size"))return"typography"}return"ignore"},u=/^\{([^}]+)\}$/,f=e=>{if("string"!=typeof e)return;const t=e.match(u);if(!t)return;const n=t[1],o=n.indexOf("."),s=o<0?n:n.slice(0,o),r=o<0?"":n.slice(o+1),i="color"===s?"colors":s;return r?`${i}.${r}`:i},p=(e,t,n)=>{var o;const s=new Map,r=[];for(const t of e)if(t.path.length<=2)r.push(t);else{const e=t.path[1];s.has(e)||s.set(e,[]),s.get(e).push(t)}for(const e of r){const t=e.path[e.path.length-1];if(!n[t]){const o=f(e.value);n[t]=o?{external:o}:{base:String(e.value)}}}for(const[e,t]of s)if(1===t.length){const o=t[0],s=o.path[o.path.length-1];s===e?n[e]={base:String(o.value)}:(n[e]||(n[e]={base:String(t[0].value)}),n[e].variants={[s]:String(o.value)})}else{const s=null!==(o=t.find(e=>{const t=e.path[e.path.length-1];return"base"===t||"default"===t||"500"===t}))&&void 0!==o?o:t[0],r={};for(const e of t){if(e===s)continue;r[e.path.slice(2).join("-")]=String(e.value)}n[e]={base:String(s.value),...Object.keys(r).length?{variants:r}:{}}}},d={fontfamily:"fontFamily",fontsize:"fontSize",fontweight:"fontWeight",lineheight:"lineHeight",letterspacing:"letterSpacing",fontstyle:"fontStyle",texttransform:"textTransform",textdecoration:"textDecoration",textalign:"textAlign"},y=(e,t,n)=>{for(const o of e)if("typography"===o.type){const e=o.value,t=o.path.slice(1).join("-")||o.path[o.path.length-1];e.fontFamily&&h(n,"fontFamily",Array.isArray(e.fontFamily)?e.fontFamily.join(", "):e.fontFamily,t),e.fontSize&&h(n,"fontSize",S(e.fontSize),t),void 0!==e.fontWeight&&h(n,"fontWeight",e.fontWeight,t),void 0!==e.lineHeight&&h(n,"lineHeight",e.lineHeight,t),e.letterSpacing&&h(n,"letterSpacing",e.letterSpacing,t)}else{const e=b(o,t);if(!e)continue;const s=o.path[o.path.length-1],r="fontFamily"===o.type&&Array.isArray(o.value)?o.value.join(", "):"dimension"===o.type?S(o.value):o.value;h(n,e,r,s)}},h=(e,t,n,o)=>{if(!e[t])return void(e[t]={base:n,variants:{}});const s=e[t];"base"===o||"default"===o||"md"===o?s.base=n:s.variants[o]=n},b=(e,t)=>{if("fontFamily"===e.type)return"fontFamily";if("fontWeight"===e.type)return"fontWeight";const n=e.path.join(".").toLowerCase();for(const[e,t]of Object.entries(d))if(n.includes(e))return t;const o=t.toLowerCase();for(const[e,t]of Object.entries(d))if(o.includes(e))return t;return null},v=(e,t,n)=>{for(const t of e){const e=t.path[t.path.length-1];switch(t.type){case"shadow":{const o=$(t.value);m(n,"shadow",o,e);break}case"transition":{const o=t.value,s=o.timingFunction?`cubic-bezier(${o.timingFunction.join(", ")})`:"ease",r=`all ${o.duration} ${s}`;m(n,"transitions",r,e);break}case"dimension":t.path.join(".").toLowerCase().includes("blur")&&m(n,"blur",S(t.value),e);break;case"number":{const o=t.path.join(".").toLowerCase();o.includes("opacity")?m(n,"opacity",t.value,e):(o.includes("z-index")||o.includes("zindex"))&&m(n,"zIndex",t.value,e);break}}}},m=(e,t,n,o)=>{if(!e[t])return void(e[t]={base:n,variants:{}});const s=e[t];"base"===o||"default"===o||"md"===o?s.base=n:s.variants[o]=n},g=(e,t,n)=>{for(const t of e){const e=t.path[t.path.length-1];switch(t.type){case"border":{const o=t.value;j(n,"width",S(o.width),e),o.style&&j(n,"style",o.style,e);break}case"strokeStyle":j(n,"style",String(t.value),e);break;case"dimension":{const o=t.path.join(".").toLowerCase();o.includes("radius")?j(n,"radius",S(t.value),e):o.includes("offset")?j(n,"offset",S(t.value),e):o.includes("width")&&j(n,"width",S(t.value),e);break}}}},j=(e,t,n,o)=>{if(!e[t])return void(e[t]={base:n,variants:{}});const s=e[t];"base"===o||"default"===o||"md"===o?s.base=n:s.variants[o]=n},k=(e,t,n)=>{for(const t of e){if("dimension"!==t.type)continue;const e=t.path[t.path.length-1],o=x(t.value);n.spacing||(n.spacing={base:o,variants:{}});const s=n.spacing;"base"===e||"default"===e||"4"===e?s.base=o:s.variants[e]=o}},$=e=>Array.isArray(e)?e.map(e=>O(e)).join(", "):O(e),O=e=>{const t=[];return e.inset&&t.push("inset"),t.push(e.offsetX,e.offsetY,e.blur,e.spread,e.color),t.join(" ")},x=e=>{if("number"==typeof e)return e;const t=parseFloat(e);return isNaN(t)?0:e.endsWith("rem")?Math.round(16*t):t},S=e=>{if("number"==typeof e)return e;const t=parseFloat(e);return isNaN(t)?e:e.endsWith("px")?t:e},w=t=>{var n;const s=null===(n=t.$extensions)||void 0===n?void 0:n[o];if(s){if(1!==s.version)throw new e.RefractError("REFRACT_E_DTCG_VERSION",`Unsupported refract DTCG extension version ${s.version} (this build reads version 1). Upgrade @theme-registry/refract to import this document's recipes.`);return s}},C=(e,t)=>void 0!==t?`${e}${t}`:e,F=e=>{const t=new Map;for(const n of Object.keys(e.tokens)){const o=n.indexOf(".");if(o<0)continue;const s=n.slice(0,o),r=n.slice(o+1),i=r.indexOf("."),a=i<0?r:r.slice(0,i),c=i<0?void 0:r.slice(i+1),l=e.tokens[n];if(void 0!==(null==l?void 0:l.external))continue;let u;if(void 0!==(null==l?void 0:l.struct))u=l.struct;else try{u=e.resolveToken(n)}catch{continue}const f=null==l?void 0:l.unit;let p=t.get(s);p||(p=new Map,t.set(s,p));let d=p.get(a);d||(d={members:{},memberUnits:{}},p.set(a,d)),void 0===c?(d.base=u,void 0!==f&&(d.baseUnit=f)):(d.members[c]=u,void 0!==f&&(d.memberUnits[c]=f))}return t},N=e=>{switch(e){case"fontFamily":return"fontFamily";case"fontWeight":return"fontWeight";case"fontSize":case"letterSpacing":return"dimension";default:return"number"}},T=(e,t)=>C(e,t),E=e=>{switch(e){case"shadow":return{groupName:"shadow",type:"shadow"};case"transitions":return{groupName:"transition",type:"transition"};case"blur":default:return{groupName:e,type:"dimension"};case"opacity":case"zIndex":return{groupName:e,type:"number"}}},A=(e,t,n,o)=>Array.isArray(t)?"transitions"===e?t.map(e=>{var t;const n=[e.property];return null==e.duration&&null==e.delay||n.push(`${null!==(t=e.duration)&&void 0!==t?t:0}ms`),e.timingFunction&&n.push(e.timingFunction),null!=e.delay&&n.push(`${e.delay}ms`),n.join(" ")}).join(", "):((e,t)=>e.map(e=>{const n=`0${(e=>{for(const t of[e.offsetX,e.offsetY,e.blur,e.spread])if(void 0!==t&&"number"!=typeof t)return t.unit;return"px"})(e)}`,o=e=>void 0===e?n:(e=>"number"==typeof e?`${e}px`:`${e.value}${e.unit}`)(e),s=[];return e.inset&&s.push("inset"),s.push(o(e.offsetX),o(e.offsetY)),null!=e.spread?s.push(o(e.blur),o(e.spread)):null!=e.blur&&s.push(o(e.blur)),e.color&&s.push(t(e.color)),s.join(" ")}).join(", "))(t,n):C(t,o),z=e=>{switch(e){case"radius":return{groupName:"radius",type:"dimension"};case"width":return{groupName:"borderWidth",type:"dimension"};case"offset":return{groupName:"outlineOffset",type:"dimension"};case"style":return{groupName:"borderStyle",type:"strokeStyle"};default:return{groupName:e,type:"dimension"}}},R=(e,t)=>C(e,t),U=(e,t)=>C(e,t);exports.REFRACT_DTCG_EXTENSION=o,exports.REFRACT_DTCG_EXTENSION_VERSION=1,exports.fromDTCG=c,exports.fromDTCGTheme=(e,n)=>{const o=c(e,n),s=w(e);return t.createTheme(o,{adapter:n.adapter,propertiesOverlay:null==s?void 0:s.properties,ruleSetsOverlay:null==s?void 0:s.ruleSets,keyframesOverlay:null==s?void 0:s.keyframes,containersOverlay:null==s?void 0:s.containers})},exports.parseDTCGDocument=r,exports.readRefractExtension=w,exports.toDTCG=(e,t)=>{var s;const r={};(null==t?void 0:t.name)&&(r.$name=t.name);const i=e.model.breakpoints;if(!1!==(null==t?void 0:t.includeBreakpoints)&&i&&Object.keys(i).length){const e={$type:"dimension"};for(const[t,n]of Object.entries(i))e[t]={$value:`${n}px`};r.breakpoint=e}const a=F(e),c=t=>{try{return String(e.resolveToken(t))}catch{return t}},l=a.get("colors");if(l){const e={$type:"color"};for(const[t,o]of l){const s={};void 0!==o.base&&(s.base={$value:n.toHexColor(String(o.base))});for(const[e,t]of Object.entries(o.members))s[e]={$value:n.toHexColor(String(t))};e[t]=s}r.color=e}const u=a.get("typography");if(u){const e={};for(const[t,n]of u){const o={$type:N(t)};void 0!==n.base&&(o.base={$value:T(n.base,n.baseUnit)});for(const[e,t]of Object.entries(n.members))o[e]={$value:T(t,n.memberUnits[e])};e[t]=o}r.typography=e}const f=a.get("effects");if(f)for(const[e,t]of f){const{groupName:n,type:o}=E(e);r[n]||(r[n]={$type:o});const s=r[n];void 0!==t.base&&(s.base={$value:A(e,t.base,c,t.baseUnit)});for(const[n,o]of Object.entries(t.members))s[n]={$value:A(e,o,c,t.memberUnits[n])}}const p=a.get("borders");if(p)for(const[e,t]of p){const{groupName:n,type:o}=z(e);r[n]||(r[n]={$type:o});const s=r[n];void 0!==t.base&&(s.base={$value:R(t.base,t.baseUnit)});for(const[e,n]of Object.entries(t.members))s[e]={$value:R(n,t.memberUnits[e])}}const d=a.get("layout");if(d)for(const[e,t]of d){if(e.includes("--"))continue;const n=e;r[n]||(r[n]={$type:"dimension"});const o=r[n];void 0!==t.base&&(o.base={$value:U(t.base,t.baseUnit)});for(const[e,n]of Object.entries(t.members))o[e]={$value:U(n,t.memberUnits[e])}}if(null==t?void 0:t.includeRecipes){const t=(e=>{const t={},n={},o={};for(const[s,r]of Object.entries(e.subsystems))r.properties&&Object.keys(r.properties).length&&(t[s]=r.properties),r.ruleSets&&Object.keys(r.ruleSets).length&&(n[s]=r.ruleSets),r.keyframes&&Object.keys(r.keyframes).length&&(o[s]=r.keyframes);const s=Object.keys(t).length>0,r=Object.keys(n).length>0,i=Object.keys(o).length>0,a=!!e.containers&&Object.keys(e.containers).length>0;if(s||r||i||a)return{version:1,...s?{properties:t}:{},...r?{ruleSets:n}:{},...i?{keyframes:o}:{},...a?{containers:e.containers}:{}}})(e.model);t&&(r.$extensions={...null!==(s=r.$extensions)&&void 0!==s?s:{},[o]:t})}return r};
|
|
2
|
+
//# sourceMappingURL=dtcg.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dtcg.cjs.js","sources":["../src/dtcg/types.ts","../src/dtcg/parse.ts","../src/dtcg/import.ts","../src/dtcg/export.ts"],"sourcesContent":["/**\n * W3C Design Tokens Community Group (DTCG) format types.\n * Based on Second Editors' Draft (2024).\n */\n\n// --- Primitive token value types ---\n\nexport type DTCGColorValue = string;\n\nexport type DTCGDimensionValue = string; // e.g. \"16px\", \"1rem\"\n\nexport type DTCGFontFamilyValue = string | string[];\n\nexport type DTCGFontWeightValue = number | string; // 400 or \"bold\"\n\nexport type DTCGDurationValue = string; // \"200ms\", \"0.3s\"\n\nexport type DTCGCubicBezierValue = [number, number, number, number];\n\nexport type DTCGNumberValue = number;\n\n// --- Composite token value types ---\n\nexport type DTCGTypographyValue = {\n fontFamily: string | string[];\n fontSize: string;\n fontWeight: number | string;\n lineHeight: number | string;\n letterSpacing?: string;\n};\n\nexport type DTCGShadowLayerValue = {\n offsetX: string;\n offsetY: string;\n blur: string;\n spread: string;\n color: string;\n inset?: boolean;\n};\n\nexport type DTCGShadowValue = DTCGShadowLayerValue | DTCGShadowLayerValue[];\n\nexport type DTCGBorderValue = {\n color: string;\n width: string;\n style: string;\n};\n\nexport type DTCGTransitionValue = {\n duration: string;\n delay?: string;\n timingFunction: DTCGCubicBezierValue;\n};\n\n// --- Token types enum ---\n\nexport type DTCGTokenType =\n | \"color\"\n | \"dimension\"\n | \"fontFamily\"\n | \"fontWeight\"\n | \"duration\"\n | \"cubicBezier\"\n | \"number\"\n | \"typography\"\n | \"shadow\"\n | \"border\"\n | \"transition\"\n | \"strokeStyle\"\n | \"gradient\";\n\n// --- Token node ---\n\nexport type DTCGToken = {\n $value: unknown;\n $type?: DTCGTokenType;\n $description?: string;\n $extensions?: Record<string, unknown>;\n};\n\nexport type DTCGGroup = {\n $type?: DTCGTokenType;\n $description?: string;\n $extensions?: Record<string, unknown>;\n [key: string]: DTCGToken | DTCGGroup | DTCGTokenType | string | Record<string, unknown> | undefined;\n};\n\nexport type DTCGDocument = DTCGGroup & {\n $name?: string;\n};\n\n// --- Resolved token (after reference resolution) ---\n\nexport type ResolvedDTCGToken = {\n path: string[];\n type: DTCGTokenType;\n value: unknown;\n description?: string;\n extensions?: Record<string, unknown>;\n};\n\n// --- refract round-trip extension ---\n\n/**\n * The reverse-DNS `$extensions` key under which `toDTCG(theme, { includeRecipes: true })` stashes the\n * built rule-set / keyframe / container IR so a document round-trips `refract → DTCG → refract` without\n * loss. Standard DTCG tools ignore unknown extensions, so the payload is **refract-specific and not\n * portable** — property tokens are the interoperable surface; recipes ride here.\n */\nexport const REFRACT_DTCG_EXTENSION = \"com.theme-registry.refract\";\n\n/** The payload schema version under {@link REFRACT_DTCG_EXTENSION}; bumped on a breaking shape change. */\nexport const REFRACT_DTCG_EXTENSION_VERSION = 1;\n","import type { DTCGDocument, DTCGTokenType, ResolvedDTCGToken } from \"./types\";\nimport { RefractError } from \"../core/errors\";\n\nconst SPEC_KEYS = new Set([\"$value\", \"$type\", \"$description\", \"$extensions\", \"$name\"]);\n\nconst isToken = (node: unknown): boolean =>\n typeof node === \"object\" && node !== null && \"$value\" in (node as Record<string, unknown>);\n\n/**\n * Walk a DTCG document and extract all tokens with resolved types and paths.\n * References (`{path.to.token}`) are resolved recursively.\n */\nexport const parseDTCGDocument = (doc: DTCGDocument): ResolvedDTCGToken[] => {\n const tokens: ResolvedDTCGToken[] = [];\n const tokensByPath = new Map<string, ResolvedDTCGToken>();\n\n // First pass: collect all tokens with their raw values\n const walk = (node: Record<string, unknown>, path: string[], inheritedType?: DTCGTokenType) => {\n const groupType = (node.$type as DTCGTokenType | undefined) ?? inheritedType;\n\n for (const [key, child] of Object.entries(node)) {\n if (key.startsWith(\"$\")) continue;\n if (typeof child !== \"object\" || child === null) continue;\n\n const childPath = [...path, key];\n\n if (isToken(child)) {\n const token = child as Record<string, unknown>;\n const resolved: ResolvedDTCGToken = {\n path: childPath,\n type: (token.$type as DTCGTokenType) ?? groupType ?? \"color\",\n value: token.$value,\n description: token.$description as string | undefined,\n extensions: token.$extensions as Record<string, unknown> | undefined,\n };\n tokens.push(resolved);\n tokensByPath.set(childPath.join(\".\"), resolved);\n } else {\n walk(child as Record<string, unknown>, childPath, groupType);\n }\n }\n };\n\n walk(doc, []);\n\n // Second pass: resolve references\n for (const token of tokens) {\n token.value = resolveReferences(token.value, tokensByPath);\n }\n\n return tokens;\n};\n\nconst REFERENCE_PATTERN = /^\\{([^}]+)\\}$/;\n\nconst resolveReferences = (\n value: unknown,\n tokensByPath: Map<string, ResolvedDTCGToken>,\n visited = new Set<string>(),\n): unknown => {\n if (typeof value === \"string\") {\n const match = value.match(REFERENCE_PATTERN);\n if (match) {\n const refPath = match[1];\n if (visited.has(refPath)) {\n throw new RefractError(\"REFRACT_E_CYCLE\", `Circular token reference: ${refPath}`);\n }\n const referenced = tokensByPath.get(refPath);\n if (!referenced) {\n return value; // unresolved reference — leave as-is\n }\n visited.add(refPath);\n return resolveReferences(referenced.value, tokensByPath, visited);\n }\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => resolveReferences(item, tokensByPath, new Set(visited)));\n }\n\n if (typeof value === \"object\" && value !== null) {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n result[k] = resolveReferences(v, tokensByPath, new Set(visited));\n }\n return result;\n }\n\n return value;\n};\n","import type { DTCGDocument, DTCGShadowLayerValue, DTCGTypographyValue, DTCGBorderValue, DTCGTransitionValue, ResolvedDTCGToken } from \"./types\";\nimport { REFRACT_DTCG_EXTENSION, REFRACT_DTCG_EXTENSION_VERSION } from \"./types\";\nimport type { RefractDTCGExtension } from \"./export\";\nimport { parseDTCGDocument } from \"./parse\";\nimport { createTheme, RefractError } from \"../core\";\nimport type { Theme, ThemeAdapter } from \"../core\";\n\ntype RawThemeInput = Record<string, unknown>;\n\nexport type FromDTCGOptions = {\n /**\n * How to map DTCG groups to refract subsystems.\n * Default: auto-detect from $type and group name.\n */\n groupMapping?: Record<string, \"colors\" | \"typography\" | \"effects\" | \"borders\" | \"layout\" | \"ignore\">;\n\n /**\n * Breakpoints as { name: pixelValue } — DTCG has no breakpoint type,\n * so these must be provided separately or mapped from dimension tokens.\n */\n breakpoints?: Record<string, number>;\n\n /**\n * DTCG group path to use as breakpoints source (e.g. \"breakpoint\").\n * Dimension values are parsed to pixels.\n */\n breakpointGroup?: string;\n};\n\n/**\n * Convert a DTCG token document into a `createTheme` raw input.\n *\n * Returns a plain object — modify it freely before passing to `createTheme`.\n */\nexport const fromDTCG = (doc: DTCGDocument, options?: FromDTCGOptions): RawThemeInput => {\n const tokens = parseDTCGDocument(doc);\n const groupMapping = options?.groupMapping ?? {};\n\n const colors: Record<string, unknown> = {};\n const typography: Record<string, unknown> = {};\n const effects: Record<string, unknown> = {};\n const borders: Record<string, unknown> = {};\n const layout: Record<string, unknown> = {};\n let breakpoints: Record<string, number> = options?.breakpoints ?? {};\n\n // Group tokens by their top-level path segment\n const grouped = new Map<string, ResolvedDTCGToken[]>();\n for (const token of tokens) {\n const topGroup = token.path[0];\n if (!grouped.has(topGroup)) grouped.set(topGroup, []);\n grouped.get(topGroup)!.push(token);\n }\n\n // Extract breakpoints if a breakpoint group is specified\n const bpGroup = options?.breakpointGroup;\n if (bpGroup && grouped.has(bpGroup)) {\n breakpoints = {};\n for (const token of grouped.get(bpGroup)!) {\n const name = token.path[token.path.length - 1];\n breakpoints[name] = parseDimension(token.value as string);\n }\n grouped.delete(bpGroup);\n }\n\n for (const [groupName, groupTokens] of grouped) {\n const mapping = groupMapping[groupName] ?? detectSubsystem(groupName, groupTokens);\n if (mapping === \"ignore\") continue;\n\n switch (mapping) {\n case \"colors\":\n mapColorTokens(groupTokens, groupName, colors);\n break;\n case \"typography\":\n mapTypographyTokens(groupTokens, groupName, typography);\n break;\n case \"effects\":\n mapEffectsTokens(groupTokens, groupName, effects);\n break;\n case \"borders\":\n mapBordersTokens(groupTokens, groupName, borders);\n break;\n case \"layout\":\n mapLayoutTokens(groupTokens, groupName, layout);\n break;\n }\n }\n\n const result: RawThemeInput = {};\n if (Object.keys(breakpoints).length) result.breakpoints = breakpoints;\n if (Object.keys(colors).length) result.colors = colors;\n if (Object.keys(typography).length) result.typography = typography;\n if (Object.keys(effects).length) result.effects = effects;\n if (Object.keys(borders).length) result.borders = borders;\n if (Object.keys(layout).length) result.layout = layout;\n\n return result;\n};\n\n// --- Auto-detection ---\n\nconst detectSubsystem = (\n groupName: string,\n tokens: ResolvedDTCGToken[],\n): \"colors\" | \"typography\" | \"effects\" | \"borders\" | \"layout\" | \"ignore\" => {\n const firstType = tokens[0]?.type;\n\n // By type\n if (firstType === \"color\") return \"colors\";\n if (firstType === \"typography\") return \"typography\";\n if (firstType === \"shadow\") return \"effects\";\n if (firstType === \"border\") return \"borders\"; // §14 — border geometry lives in `borders` now\n if (firstType === \"strokeStyle\") return \"borders\";\n if (firstType === \"transition\") return \"effects\";\n\n // By name convention\n const lower = groupName.toLowerCase();\n if (lower.includes(\"color\") || lower.includes(\"palette\")) return \"colors\";\n if (lower.includes(\"font\") || lower.includes(\"typo\") || lower.includes(\"text\")) return \"typography\";\n if (lower.includes(\"spacing\") || lower.includes(\"space\") || lower.includes(\"gutter\")) return \"layout\";\n // Borders keywords take precedence over effects (radius/border/outline moved out of effects).\n if (lower.includes(\"radius\") || lower.includes(\"border\") || lower.includes(\"outline\")) return \"borders\";\n if (lower.includes(\"shadow\") || lower.includes(\"blur\") || lower.includes(\"opacity\") ||\n lower.includes(\"z-index\") || lower.includes(\"zindex\") || lower.includes(\"transition\") ||\n lower.includes(\"effect\")) return \"effects\";\n\n // Dimension tokens: check naming\n if (firstType === \"dimension\") {\n if (lower.includes(\"spacing\") || lower.includes(\"gap\")) return \"layout\";\n if (lower.includes(\"radius\") || lower.includes(\"border\")) return \"borders\";\n if (lower.includes(\"font\") || lower.includes(\"size\")) return \"typography\";\n }\n\n return \"ignore\";\n};\n\n// --- External aliases (dec.6 / §12 Phase 2) ---\n\n/** A DTCG value left as `\"{group.token}\"` after parse — an alias whose target is ABSENT from the\n * document (`parseDTCGDocument` leaves an unresolvable reference verbatim). */\nconst UNRESOLVED_ALIAS = /^\\{([^}]+)\\}$/;\n\n/**\n * Map a genuinely-external DTCG alias (target absent from the doc) to a refract `external` token path\n * — the refract analog of \"this references a token another (parent) theme owns.\" The DTCG `color`\n * group renames to the `colors` subsystem; other groups pass through best-effort. Returns `undefined`\n * for a non-alias / resolved value (which stays a normal literal). A resolvable same-doc alias never\n * reaches here — `parseDTCGDocument` already flattened it to its literal.\n */\nconst aliasToExternalPath = (value: unknown): string | undefined => {\n if (typeof value !== \"string\") return undefined;\n const match = value.match(UNRESOLVED_ALIAS);\n if (!match) return undefined;\n const inner = match[1];\n const dot = inner.indexOf(\".\");\n const group = dot < 0 ? inner : inner.slice(0, dot);\n const rest = dot < 0 ? \"\" : inner.slice(dot + 1);\n const subsystem = group === \"color\" ? \"colors\" : group;\n return rest ? `${subsystem}.${rest}` : subsystem;\n};\n\n// --- Color mapping ---\n\nconst mapColorTokens = (tokens: ResolvedDTCGToken[], groupName: string, colors: Record<string, unknown>) => {\n // Group by second path segment (e.g. color.brand.primary → \"brand\")\n const subgroups = new Map<string, ResolvedDTCGToken[]>();\n const topLevel: ResolvedDTCGToken[] = [];\n\n for (const token of tokens) {\n if (token.path.length <= 2) {\n topLevel.push(token);\n } else {\n const sub = token.path[1];\n if (!subgroups.has(sub)) subgroups.set(sub, []);\n subgroups.get(sub)!.push(token);\n }\n }\n\n // Top-level color tokens → flat colors with base. A genuinely-external alias (absent target) →\n // a refract `external` passthrough (dec.6) rather than a literal `{ base }` (which would reject `{…}`).\n for (const token of topLevel) {\n const name = token.path[token.path.length - 1];\n if (!colors[name]) {\n const external = aliasToExternalPath(token.value);\n colors[name] = external ? { external } : { base: String(token.value) };\n }\n }\n\n // Subgroups → colors with variants\n for (const [subName, subTokens] of subgroups) {\n if (subTokens.length === 1) {\n const token = subTokens[0];\n const name = token.path[token.path.length - 1];\n if (name === subName) {\n colors[subName] = { base: String(token.value) };\n } else {\n if (!colors[subName]) colors[subName] = { base: String(subTokens[0].value) };\n (colors[subName] as Record<string, unknown>).variants = {\n [name]: String(token.value),\n };\n }\n } else {\n // Multiple tokens in subgroup → first or \"base\"/\"default\"/\"500\" is base, rest are variants\n const baseToken = subTokens.find(t => {\n const last = t.path[t.path.length - 1];\n return last === \"base\" || last === \"default\" || last === \"500\";\n }) ?? subTokens[0];\n\n const variants: Record<string, string> = {};\n for (const t of subTokens) {\n if (t === baseToken) continue;\n const variantName = t.path.slice(2).join(\"-\");\n variants[variantName] = String(t.value);\n }\n\n colors[subName] = {\n base: String(baseToken.value),\n ...(Object.keys(variants).length ? { variants } : {}),\n };\n }\n }\n};\n\n// --- Typography mapping ---\n\nconst TYPO_PROPERTY_MAP: Record<string, string> = {\n fontfamily: \"fontFamily\",\n fontsize: \"fontSize\",\n fontweight: \"fontWeight\",\n lineheight: \"lineHeight\",\n letterspacing: \"letterSpacing\",\n fontstyle: \"fontStyle\",\n texttransform: \"textTransform\",\n textdecoration: \"textDecoration\",\n textalign: \"textAlign\",\n};\n\nconst mapTypographyTokens = (tokens: ResolvedDTCGToken[], groupName: string, typography: Record<string, unknown>) => {\n for (const token of tokens) {\n if (token.type === \"typography\") {\n // Composite typography token → decompose into individual properties\n const value = token.value as DTCGTypographyValue;\n const variantName = token.path.slice(1).join(\"-\") || token.path[token.path.length - 1];\n\n if (value.fontFamily) {\n addTypographyVariant(typography, \"fontFamily\",\n Array.isArray(value.fontFamily) ? value.fontFamily.join(\", \") : value.fontFamily, variantName);\n }\n if (value.fontSize) {\n addTypographyVariant(typography, \"fontSize\", parseDimensionOrKeep(value.fontSize), variantName);\n }\n if (value.fontWeight !== undefined) {\n addTypographyVariant(typography, \"fontWeight\", value.fontWeight, variantName);\n }\n if (value.lineHeight !== undefined) {\n addTypographyVariant(typography, \"lineHeight\", value.lineHeight, variantName);\n }\n if (value.letterSpacing) {\n addTypographyVariant(typography, \"letterSpacing\", value.letterSpacing, variantName);\n }\n } else {\n // Individual token (fontFamily, fontSize, fontWeight, dimension)\n const propertyKey = detectTypoProperty(token, groupName);\n if (!propertyKey) continue;\n const variantName = token.path[token.path.length - 1];\n const value = token.type === \"fontFamily\" && Array.isArray(token.value)\n ? (token.value as string[]).join(\", \")\n : token.type === \"dimension\"\n ? parseDimensionOrKeep(token.value as string)\n : token.value;\n addTypographyVariant(typography, propertyKey, value as string | number, variantName);\n }\n }\n};\n\nconst addTypographyVariant = (\n typography: Record<string, unknown>,\n property: string,\n value: string | number,\n variantName: string,\n) => {\n if (!typography[property]) {\n typography[property] = { base: value, variants: {} };\n return;\n }\n const prop = typography[property] as { base: unknown; variants: Record<string, unknown> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"md\") {\n prop.base = value;\n } else {\n prop.variants[variantName] = value;\n }\n};\n\nconst detectTypoProperty = (token: ResolvedDTCGToken, groupName: string): string | null => {\n // Check token type\n if (token.type === \"fontFamily\") return \"fontFamily\";\n if (token.type === \"fontWeight\") return \"fontWeight\";\n\n // Check group or parent path naming\n const fullPath = token.path.join(\".\").toLowerCase();\n for (const [key, prop] of Object.entries(TYPO_PROPERTY_MAP)) {\n if (fullPath.includes(key)) return prop;\n }\n\n // Check group name\n const lower = groupName.toLowerCase();\n for (const [key, prop] of Object.entries(TYPO_PROPERTY_MAP)) {\n if (lower.includes(key)) return prop;\n }\n\n return null;\n};\n\n// --- Effects mapping ---\n\nconst mapEffectsTokens = (tokens: ResolvedDTCGToken[], groupName: string, effects: Record<string, unknown>) => {\n for (const token of tokens) {\n const variantName = token.path[token.path.length - 1];\n\n switch (token.type) {\n case \"shadow\": {\n const shadowStr = formatShadowValue(token.value);\n addEffectsVariant(effects, \"shadow\", shadowStr, variantName);\n break;\n }\n case \"transition\": {\n const transition = token.value as DTCGTransitionValue;\n const bezier = transition.timingFunction\n ? `cubic-bezier(${transition.timingFunction.join(\", \")})`\n : \"ease\";\n const transStr = `all ${transition.duration} ${bezier}`;\n addEffectsVariant(effects, \"transitions\", transStr, variantName);\n break;\n }\n case \"dimension\": {\n const lower = token.path.join(\".\").toLowerCase();\n if (lower.includes(\"blur\")) {\n addEffectsVariant(effects, \"blur\", parseDimensionOrKeep(token.value as string), variantName);\n }\n break;\n }\n case \"number\": {\n const lower = token.path.join(\".\").toLowerCase();\n if (lower.includes(\"opacity\")) {\n addEffectsVariant(effects, \"opacity\", token.value as number, variantName);\n } else if (lower.includes(\"z-index\") || lower.includes(\"zindex\")) {\n addEffectsVariant(effects, \"zIndex\", token.value as number, variantName);\n }\n break;\n }\n }\n }\n};\n\nconst addEffectsVariant = (\n effects: Record<string, unknown>,\n property: string,\n value: string | number,\n variantName: string,\n) => {\n if (!effects[property]) {\n effects[property] = { base: value, variants: {} };\n return;\n }\n const prop = effects[property] as { base: unknown; variants: Record<string, unknown> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"md\") {\n prop.base = value;\n } else {\n prop.variants[variantName] = value;\n }\n};\n\n// --- Borders mapping (§14) ---\n\nconst mapBordersTokens = (tokens: ResolvedDTCGToken[], groupName: string, borders: Record<string, unknown>) => {\n for (const token of tokens) {\n const variantName = token.path[token.path.length - 1];\n\n switch (token.type) {\n case \"border\": {\n // The DTCG `border` composite carries width + style + color; only the geometry maps to\n // borders tokens (§14.4 — color is never a borders token, so it is dropped on import).\n const border = token.value as DTCGBorderValue;\n addBordersVariant(borders, \"width\", parseDimensionOrKeep(border.width), variantName);\n if (border.style) addBordersVariant(borders, \"style\", border.style, variantName);\n break;\n }\n case \"strokeStyle\": {\n addBordersVariant(borders, \"style\", String(token.value), variantName);\n break;\n }\n case \"dimension\": {\n const lower = token.path.join(\".\").toLowerCase();\n if (lower.includes(\"radius\")) {\n addBordersVariant(borders, \"radius\", parseDimensionOrKeep(token.value as string), variantName);\n } else if (lower.includes(\"offset\")) {\n addBordersVariant(borders, \"offset\", parseDimensionOrKeep(token.value as string), variantName);\n } else if (lower.includes(\"width\")) {\n addBordersVariant(borders, \"width\", parseDimensionOrKeep(token.value as string), variantName);\n }\n break;\n }\n }\n }\n};\n\nconst addBordersVariant = (\n borders: Record<string, unknown>,\n property: string,\n value: string | number,\n variantName: string,\n) => {\n if (!borders[property]) {\n borders[property] = { base: value, variants: {} };\n return;\n }\n const prop = borders[property] as { base: unknown; variants: Record<string, unknown> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"md\") {\n prop.base = value;\n } else {\n prop.variants[variantName] = value;\n }\n};\n\n// --- Layout mapping ---\n\nconst mapLayoutTokens = (tokens: ResolvedDTCGToken[], groupName: string, layout: Record<string, unknown>) => {\n for (const token of tokens) {\n if (token.type !== \"dimension\") continue;\n const variantName = token.path[token.path.length - 1];\n const value = parseDimension(token.value as string);\n\n if (!layout.spacing) {\n layout.spacing = { base: value, variants: {} };\n }\n\n const spacing = layout.spacing as { base: number; variants: Record<string, number> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"4\") {\n spacing.base = value;\n } else {\n spacing.variants[variantName] = value;\n }\n }\n};\n\n// --- Helpers ---\n\nconst formatShadowValue = (value: unknown): string => {\n if (Array.isArray(value)) {\n return value.map(layer => formatSingleShadow(layer as DTCGShadowLayerValue)).join(\", \");\n }\n return formatSingleShadow(value as DTCGShadowLayerValue);\n};\n\nconst formatSingleShadow = (layer: DTCGShadowLayerValue): string => {\n const parts: string[] = [];\n if (layer.inset) parts.push(\"inset\");\n parts.push(layer.offsetX, layer.offsetY, layer.blur, layer.spread, layer.color);\n return parts.join(\" \");\n};\n\nconst parseDimension = (value: string | number): number => {\n if (typeof value === \"number\") return value;\n const num = parseFloat(value);\n if (isNaN(num)) return 0;\n // Convert rem to px (assume 16px base)\n if (value.endsWith(\"rem\")) return Math.round(num * 16);\n return num;\n};\n\nconst parseDimensionOrKeep = (value: string | number): string | number => {\n if (typeof value === \"number\") return value;\n const num = parseFloat(value);\n if (isNaN(num)) return value;\n if (value.endsWith(\"px\")) return num;\n return value;\n};\n\n// --- refract round-trip (recipes via the com.theme-registry.refract extension) ---\n\n/**\n * Read the refract round-trip payload from a DTCG document's top-level `$extensions`, or `undefined`\n * when it carries none. `parseDTCGDocument` intentionally drops top-level `$extensions`, so this reads\n * `doc.$extensions` directly. Throws on a payload from a newer, unreadable schema version.\n */\nexport const readRefractExtension = (doc: DTCGDocument): RefractDTCGExtension | undefined => {\n const ext = doc.$extensions?.[REFRACT_DTCG_EXTENSION] as RefractDTCGExtension | undefined;\n if (!ext) return undefined;\n if (ext.version !== REFRACT_DTCG_EXTENSION_VERSION) {\n throw new RefractError(\n \"REFRACT_E_DTCG_VERSION\",\n `Unsupported refract DTCG extension version ${ext.version} (this build reads version ` +\n `${REFRACT_DTCG_EXTENSION_VERSION}). Upgrade @theme-registry/refract to import this document's recipes.`,\n );\n }\n return ext;\n};\n\n/**\n * Lossless `DTCG → refract` round-trip entry: {@link fromDTCG} for the property tokens, plus the\n * recipes / keyframes / containers the document stashed under `com.theme-registry.refract` reinjected\n * through createTheme's overlay. A plain DTCG document (no refract extension) round-trips to a\n * recipe-less theme — identical to `createTheme(fromDTCG(doc), { adapter })`.\n */\nexport const fromDTCGTheme = (\n doc: DTCGDocument,\n options: FromDTCGOptions & { adapter: ThemeAdapter },\n): Theme => {\n const raw = fromDTCG(doc, options);\n const ext = readRefractExtension(doc);\n return createTheme(raw, {\n adapter: options.adapter,\n propertiesOverlay: ext?.properties,\n ruleSetsOverlay: ext?.ruleSets,\n keyframesOverlay: ext?.keyframes,\n containersOverlay: ext?.containers,\n });\n};\n","import type { Theme } from \"../core\";\nimport type { Literal, ShadowDimension, ShadowLayer, TransitionPart } from \"../core\";\nimport type { ThemeModel, RuleSetGroup, Keyframe, ContainerModel, PropertyModel } from \"../core\";\nimport type { DTCGDocument, DTCGTokenType } from \"./types\";\nimport { REFRACT_DTCG_EXTENSION, REFRACT_DTCG_EXTENSION_VERSION } from \"./types\";\nimport { toHexColor } from \"../subsystems/colors/utils\";\n\n/** The refract round-trip payload stashed under {@link REFRACT_DTCG_EXTENSION}. Built IR, verbatim. */\nexport type RefractDTCGExtension = {\n version: number;\n /**\n * Per-subsystem property Model verbatim (§12 Phase 2) — the lossless channel for what the portable\n * DTCG token surface can't carry: appearance `modes` (a `PropertyOverride[]` list), `responsive`\n * overrides, derivation metadata (`{ ref, modifiers }`), and `external` passthroughs. Reinjected on\n * import via createTheme's `propertiesOverlay`. The standard resolved-literal tokens still emit\n * alongside for portability; this is refract-only (other tools ignore the extension).\n */\n properties?: Record<string, Record<string, PropertyModel>>;\n ruleSets?: Record<string, Record<string, RuleSetGroup>>;\n keyframes?: Record<string, Record<string, Keyframe>>;\n containers?: Record<string, ContainerModel>;\n};\n\n/**\n * Collect a theme's built property / rule-set / keyframe / container IR into the round-trip payload, or\n * `undefined` when the theme has none (so `includeRecipes` on an empty theme still emits no\n * `$extensions`, keeping standard output byte-identical). The Model is \"serializable as-is\", a plain walk.\n */\nconst buildRefractExtension = (model: ThemeModel): RefractDTCGExtension | undefined => {\n const properties: Record<string, Record<string, PropertyModel>> = {};\n const ruleSets: Record<string, Record<string, RuleSetGroup>> = {};\n const keyframes: Record<string, Record<string, Keyframe>> = {};\n for (const [sub, subModel] of Object.entries(model.subsystems)) {\n if (subModel.properties && Object.keys(subModel.properties).length) properties[sub] = subModel.properties;\n if (subModel.ruleSets && Object.keys(subModel.ruleSets).length) ruleSets[sub] = subModel.ruleSets;\n if (subModel.keyframes && Object.keys(subModel.keyframes).length) keyframes[sub] = subModel.keyframes;\n }\n const hasProperties = Object.keys(properties).length > 0;\n const hasRuleSets = Object.keys(ruleSets).length > 0;\n const hasKeyframes = Object.keys(keyframes).length > 0;\n const hasContainers = !!model.containers && Object.keys(model.containers).length > 0;\n if (!hasProperties && !hasRuleSets && !hasKeyframes && !hasContainers) return undefined;\n return {\n version: REFRACT_DTCG_EXTENSION_VERSION,\n ...(hasProperties ? { properties } : {}),\n ...(hasRuleSets ? { ruleSets } : {}),\n ...(hasKeyframes ? { keyframes } : {}),\n ...(hasContainers ? { containers: model.containers } : {}),\n };\n};\n\nexport type ToDTCGOptions = {\n /** Name for the DTCG document. */\n name?: string;\n\n /** Whether to include breakpoints as dimension tokens. Default: true. */\n includeBreakpoints?: boolean;\n\n /**\n * Stash the theme's built Model IR — **property tokens (incl. modes / responsive / derivation refs /\n * external), rule-sets, keyframes, containers** — under the reverse-DNS `com.theme-registry.refract`\n * `$extensions` key, so the document round-trips `refract → DTCG → refract` **losslessly** via\n * {@link fromDTCGTheme} (§12 Phase 2 widened this from recipes-only to the whole Model). **Not\n * portable** — other DTCG tools ignore the extension and see the resolved property tokens only.\n * Default `false` (standard output stays byte-identical).\n */\n includeRecipes?: boolean;\n};\n\n/**\n * Convert a built theme's tokens into a DTCG-compliant JSON document.\n *\n * **Model-first re-port:** this walks the flat, format-neutral `theme.tokens` map\n * (`\"<subsystem>.<property>[.<variant>]\" -> Ref`) — the single source of truth that\n * replaced the retired per-subsystem `theme.<sub>.tokens` shape. Each token path is\n * resolved to a concrete literal via `theme.resolveToken` (following aliases and\n * running `lighten` / `darken` derivations), then re-grouped into DTCG groups.\n *\n * DTCG carries **property tokens only** — recipes / composition are out of scope, and\n * layout structural-config knobs (property names containing `--`) are skipped.\n *\n * Returns a plain object — modify it freely before writing to a file.\n */\nexport const toDTCG = (theme: Theme, options?: ToDTCGOptions): DTCGDocument => {\n const doc: DTCGDocument = {};\n\n if (options?.name) {\n doc.$name = options.name;\n }\n\n // Breakpoints — read from the Model, emitted as dimension tokens.\n const breakpoints = theme.model.breakpoints;\n if (options?.includeBreakpoints !== false && breakpoints && Object.keys(breakpoints).length) {\n const bp: Record<string, unknown> = { $type: \"dimension\" as DTCGTokenType };\n for (const [name, value] of Object.entries(breakpoints)) {\n bp[name] = { $value: `${value}px` };\n }\n doc.breakpoint = bp;\n }\n\n // Group the flat token map by subsystem → property, resolving each path to a literal.\n const grouped = groupTokens(theme);\n\n // Resolve a `colors.*` (or any) token path to its literal for embedding in a composed shadow\n // string; falls back to the raw path if unresolvable (defensive).\n const resolveColor = (path: string): string => {\n try {\n return String(theme.resolveToken(path));\n } catch {\n return path;\n }\n };\n\n // Colors — { $type: color, <name>: { base, text?, <variant> } }\n const colors = grouped.get(\"colors\");\n if (colors) {\n const group: Record<string, unknown> = { $type: \"color\" as DTCGTokenType };\n for (const [name, prop] of colors) {\n const node: Record<string, unknown> = {};\n if (prop.base !== undefined) {\n node.base = { $value: toHexColor(String(prop.base)) };\n }\n for (const [member, value] of Object.entries(prop.members)) {\n node[member] = { $value: toHexColor(String(value)) };\n }\n group[name] = node;\n }\n doc.color = group;\n }\n\n // Typography — nested under `doc.typography`, one group per property.\n const typography = grouped.get(\"typography\");\n if (typography) {\n const typo: Record<string, unknown> = {};\n for (const [propName, prop] of typography) {\n const type = getTypographyTokenType(propName);\n const group: Record<string, unknown> = { $type: type };\n if (prop.base !== undefined) {\n group.base = { $value: formatTypoValue(prop.base, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatTypoValue(value, prop.memberUnits[variant]) };\n }\n typo[propName] = group;\n }\n doc.typography = typo;\n }\n\n // Effects — one top-level group per property, named/typed by getEffectsGroupInfo.\n const effects = grouped.get(\"effects\");\n if (effects) {\n for (const [propName, prop] of effects) {\n const { groupName, type } = getEffectsGroupInfo(propName);\n if (!doc[groupName]) {\n doc[groupName] = { $type: type };\n }\n const group = doc[groupName] as Record<string, unknown>;\n // §15: a structured shadow/transition token composes to a CSS string at the DTCG boundary\n // (its `colors.*` color ref resolved to a literal) — consistent with how a string-authored\n // shadow already exports. A fully-structured DTCG composite round-trip is a future enhancement.\n if (prop.base !== undefined) {\n group.base = { $value: formatEffectsValue(propName, prop.base, resolveColor, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatEffectsValue(propName, value, resolveColor, prop.memberUnits[variant]) };\n }\n }\n }\n\n // Borders (§14) — one top-level group per property (radius/width/offset → dimension px,\n // style → strokeStyle). Border geometry moved out of effects; color is never a borders token.\n const borders = grouped.get(\"borders\");\n if (borders) {\n for (const [propName, prop] of borders) {\n const { groupName, type } = getBordersGroupInfo(propName);\n if (!doc[groupName]) {\n doc[groupName] = { $type: type };\n }\n const group = doc[groupName] as Record<string, unknown>;\n if (prop.base !== undefined) {\n group.base = { $value: formatBordersValue(prop.base, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatBordersValue(value, prop.memberUnits[variant]) };\n }\n }\n }\n\n // Layout (spacing / gutters / aspectRatio) — dimension tokens. Structural-config\n // knobs (`columns--*` / `container--*`) are internal, not interchange tokens.\n const layout = grouped.get(\"layout\");\n if (layout) {\n for (const [propName, prop] of layout) {\n if (propName.includes(\"--\")) continue;\n const groupName = propName;\n if (!doc[groupName]) {\n doc[groupName] = { $type: \"dimension\" as DTCGTokenType };\n }\n const group = doc[groupName] as Record<string, unknown>;\n if (prop.base !== undefined) {\n group.base = { $value: formatDimensionValue(prop.base, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatDimensionValue(value, prop.memberUnits[variant]) };\n }\n }\n }\n\n // §DTCG round-trip — opt-in: stash the built rule-set/keyframe/container IR under the refract\n // extension key. Only touched when `includeRecipes` is set AND the theme actually has recipes, so\n // the standard property-token document stays byte-identical by default.\n if (options?.includeRecipes) {\n const ext = buildRefractExtension(theme.model);\n if (ext) doc.$extensions = { ...(doc.$extensions ?? {}), [REFRACT_DTCG_EXTENSION]: ext };\n }\n\n return doc;\n};\n\n// --- Flat-token grouping ---\n\ntype PropTokens = {\n /** the `<sub>.<prop>` base token, if present. */\n base?: Literal;\n /** the `<sub>.<prop>.<member>` variants / extras (e.g. colors' `text`). */\n members: Record<string, Literal>;\n /** §21 resolved length unit for `base` (absent = unit-less / non-length / raw string). */\n baseUnit?: string;\n /** §21 resolved length unit per member. */\n memberUnits: Record<string, string>;\n};\n\n/** A resolved dimension → DTCG text: append the §21 unit baked on the Model leaf; a unit-less value\n * (lineHeight, opacity, aspectRatio) or a raw string passes through untouched. */\nconst dimText = (value: Literal, unit?: string): string | number =>\n unit !== undefined ? `${value}${unit}` : value;\n\n/**\n * Group the flat `theme.tokens` map into `subsystem -> property -> { base, members }`,\n * resolving each path to a concrete literal via `theme.resolveToken`. Unresolvable\n * paths are skipped (defensive — a well-formed Model resolves everything).\n */\nconst groupTokens = (theme: Theme): Map<string, Map<string, PropTokens>> => {\n const out = new Map<string, Map<string, PropTokens>>();\n for (const path of Object.keys(theme.tokens)) {\n const dot = path.indexOf(\".\");\n if (dot < 0) continue;\n const subsystem = path.slice(0, dot);\n const rest = path.slice(dot + 1);\n const dot2 = rest.indexOf(\".\");\n const property = dot2 < 0 ? rest : rest.slice(0, dot2);\n const member = dot2 < 0 ? undefined : rest.slice(dot2 + 1);\n\n // §W6b / §12 Phase 2: an EXTERNAL token is a passthrough to a parent-owned var (`var(--…)`); it\n // has no value this document owns. Skip it from the portable token surface — emitting it as a\n // `var(--…)` colour would break re-import (colours reject `var()`). The lossless refract extension\n // carries it verbatim (its `PropertyModel.base` keeps `external`), so the round-trip restores it.\n const ref = theme.tokens[path];\n if (ref?.external !== undefined) continue;\n let value: Literal;\n if (ref?.struct !== undefined) {\n value = ref.struct as unknown as Literal;\n } else {\n try {\n value = theme.resolveToken(path);\n } catch {\n continue;\n }\n }\n const unit = ref?.unit; // §21 resolved length unit (absent for unit-less / raw / struct tokens)\n\n let subMap = out.get(subsystem);\n if (!subMap) {\n subMap = new Map<string, PropTokens>();\n out.set(subsystem, subMap);\n }\n let prop = subMap.get(property);\n if (!prop) {\n prop = { members: {}, memberUnits: {} };\n subMap.set(property, prop);\n }\n if (member === undefined) {\n prop.base = value;\n if (unit !== undefined) prop.baseUnit = unit;\n } else {\n prop.members[member] = value;\n if (unit !== undefined) prop.memberUnits[member] = unit;\n }\n }\n return out;\n};\n\n// --- Value formatting (per subsystem/property) ---\n\nconst getTypographyTokenType = (propName: string): DTCGTokenType => {\n switch (propName) {\n case \"fontFamily\": return \"fontFamily\";\n case \"fontWeight\": return \"fontWeight\";\n case \"fontSize\":\n case \"letterSpacing\": return \"dimension\";\n default: return \"number\";\n }\n};\n\n/** Typography value → DTCG. Length props (fontSize, letterSpacing) carry a resolved unit; the rest\n * (fontFamily string, fontWeight/lineHeight numbers) are unit-less → pass through. */\nconst formatTypoValue = (value: Literal, unit?: string): string | number => dimText(value, unit);\n\nconst getEffectsGroupInfo = (propName: string): { groupName: string; type: DTCGTokenType } => {\n switch (propName) {\n case \"shadow\": return { groupName: \"shadow\", type: \"shadow\" };\n case \"transitions\": return { groupName: \"transition\", type: \"transition\" };\n case \"blur\": return { groupName: propName, type: \"dimension\" };\n case \"opacity\":\n case \"zIndex\": return { groupName: propName, type: \"number\" };\n default: return { groupName: propName, type: \"dimension\" };\n }\n};\n\n/** A resolved shadow geometry field (§21 `{value,unit}`, or a bare number) → CSS text. */\nconst dtcgShadowDim = (dim: ShadowDimension): string =>\n typeof dim === \"number\" ? `${dim}px` : `${dim.value}${dim.unit}`;\n\n/** The layer's shared length unit — from the first resolved geometry field; `px` if none resolved. */\nconst dtcgLayerUnit = (layer: ShadowLayer): string => {\n for (const field of [layer.offsetX, layer.offsetY, layer.blur, layer.spread]) {\n if (field !== undefined && typeof field !== \"number\") return field.unit;\n }\n return \"px\";\n};\n\n/** Compose a structured shadow value (§15) → a CSS `box-shadow` string with color refs resolved\n * (translucency is carried by the referenced colour — an `alpha` colour variant, §13.3). Geometry\n * fields carry a resolved unit (§21); an absent (required) offset defaults to `0` in the layer's unit. */\nconst composeDtcgShadow = (layers: ShadowLayer[], resolveColor: (path: string) => string): string =>\n layers\n .map(layer => {\n const zero = `0${dtcgLayerUnit(layer)}`;\n const len = (dim: ShadowDimension | undefined): string => (dim === undefined ? zero : dtcgShadowDim(dim));\n const parts: string[] = [];\n if (layer.inset) parts.push(\"inset\");\n parts.push(len(layer.offsetX), len(layer.offsetY));\n if (layer.spread != null) parts.push(len(layer.blur), len(layer.spread));\n else if (layer.blur != null) parts.push(len(layer.blur));\n if (layer.color) parts.push(resolveColor(layer.color));\n return parts.join(\" \");\n })\n .join(\", \");\n\n/** Compose a structured transition value (§15) → a CSS `transition` string. */\nconst composeDtcgTransition = (parts: TransitionPart[]): string =>\n parts\n .map(part => {\n const segs: string[] = [part.property];\n if (part.duration != null || part.delay != null) segs.push(`${part.duration ?? 0}ms`);\n if (part.timingFunction) segs.push(part.timingFunction);\n if (part.delay != null) segs.push(`${part.delay}ms`);\n return segs.join(\" \");\n })\n .join(\", \");\n\nconst formatEffectsValue = (\n propName: string,\n value: Literal,\n resolveColor: (path: string) => string,\n unit?: string,\n): string | number => {\n // §15: shadow/transitions arrive as a structured array (cast to `Literal` in groupTokens).\n if (Array.isArray(value)) {\n return propName === \"transitions\"\n ? composeDtcgTransition(value as TransitionPart[])\n : composeDtcgShadow(value as ShadowLayer[], resolveColor);\n }\n // `blur` carries a resolved length unit (§21); `opacity`/`zIndex` are unit-less → pass through.\n return dimText(value, unit);\n};\n\nconst getBordersGroupInfo = (propName: string): { groupName: string; type: DTCGTokenType } => {\n switch (propName) {\n case \"radius\": return { groupName: \"radius\", type: \"dimension\" };\n case \"width\": return { groupName: \"borderWidth\", type: \"dimension\" };\n case \"offset\": return { groupName: \"outlineOffset\", type: \"dimension\" };\n case \"style\": return { groupName: \"borderStyle\", type: \"strokeStyle\" };\n default: return { groupName: propName, type: \"dimension\" };\n }\n};\n\n/** Borders geometry: radius/width/offset carry a resolved length unit (§21); `style` is a raw\n * strokeStyle string (no unit → passes through). */\nconst formatBordersValue = (value: Literal, unit?: string): string | number => dimText(value, unit);\n\n/** Layout dimension: spacing/gutters/sizes carry a resolved unit (§21); aspectRatio is unit-less. */\nconst formatDimensionValue = (value: Literal, unit?: string): string | number => dimText(value, unit);\n"],"names":["REFRACT_DTCG_EXTENSION","isToken","node","parseDTCGDocument","doc","tokens","tokensByPath","Map","walk","path","inheritedType","groupType","_a","$type","key","child","Object","entries","startsWith","childPath","token","resolved","type","_b","_c","value","$value","description","$description","extensions","$extensions","push","set","join","resolveReferences","REFERENCE_PATTERN","visited","Set","match","refPath","has","RefractError","referenced","get","add","Array","isArray","map","item","result","k","v","fromDTCG","options","groupMapping","colors","typography","effects","borders","layout","breakpoints","grouped","topGroup","bpGroup","breakpointGroup","length","parseDimension","delete","groupName","groupTokens","mapping","detectSubsystem","mapColorTokens","mapTypographyTokens","mapEffectsTokens","mapBordersTokens","mapLayoutTokens","keys","firstType","lower","toLowerCase","includes","UNRESOLVED_ALIAS","aliasToExternalPath","inner","dot","indexOf","group","slice","rest","subsystem","subgroups","topLevel","sub","name","external","base","String","subName","subTokens","variants","baseToken","find","t","last","TYPO_PROPERTY_MAP","fontfamily","fontsize","fontweight","lineheight","letterspacing","fontstyle","texttransform","textdecoration","textalign","variantName","fontFamily","addTypographyVariant","fontSize","parseDimensionOrKeep","undefined","fontWeight","lineHeight","letterSpacing","propertyKey","detectTypoProperty","property","prop","fullPath","shadowStr","formatShadowValue","addEffectsVariant","transition","bezier","timingFunction","transStr","duration","border","addBordersVariant","width","style","spacing","layer","formatSingleShadow","parts","inset","offsetX","offsetY","blur","spread","color","num","parseFloat","isNaN","endsWith","Math","round","readRefractExtension","ext","version","dimText","unit","theme","out","dot2","member","ref","struct","resolveToken","subMap","members","memberUnits","baseUnit","getTypographyTokenType","propName","formatTypoValue","getEffectsGroupInfo","formatEffectsValue","resolveColor","part","segs","delay","layers","zero","field","dtcgLayerUnit","len","dim","dtcgShadowDim","composeDtcgShadow","getBordersGroupInfo","formatBordersValue","formatDimensionValue","raw","createTheme","adapter","propertiesOverlay","properties","ruleSetsOverlay","ruleSets","keyframesOverlay","keyframes","containersOverlay","containers","$name","model","includeBreakpoints","bp","breakpoint","toHexColor","typo","variant","includeRecipes","subModel","subsystems","hasProperties","hasRuleSets","hasKeyframes","hasContainers","buildRefractExtension"],"mappings":"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"}
|
package/dist/dtcg.esm.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{R as e}from"./_errors-d75a5c74.esm.js";import{O as t}from"./_createTheme-255ff48e.esm.js";import{toHexColor as n}from"./color-math.esm.js";const s="com.theme-registry.refract",o=1,r=e=>"object"==typeof e&&null!==e&&"$value"in e,i=e=>{const t=[],n=new Map,s=(e,o,i)=>{var a,c,l;const u=null!==(a=e.$type)&&void 0!==a?a:i;for(const[i,a]of Object.entries(e)){if(i.startsWith("$"))continue;if("object"!=typeof a||null===a)continue;const e=[...o,i];if(r(a)){const s=a,o={path:e,type:null!==(l=null!==(c=s.$type)&&void 0!==c?c:u)&&void 0!==l?l:"color",value:s.$value,description:s.$description,extensions:s.$extensions};t.push(o),n.set(e.join("."),o)}else s(a,e,u)}};s(e,[]);for(const e of t)e.value=c(e.value,n);return t},a=/^\{([^}]+)\}$/,c=(t,n,s=new Set)=>{if("string"==typeof t){const o=t.match(a);if(o){const r=o[1];if(s.has(r))throw new e("REFRACT_E_CYCLE",`Circular token reference: ${r}`);const i=n.get(r);return i?(s.add(r),c(i.value,n,s)):t}return t}if(Array.isArray(t))return t.map(e=>c(e,n,new Set(s)));if("object"==typeof t&&null!==t){const e={};for(const[o,r]of Object.entries(t))e[o]=c(r,n,new Set(s));return e}return t},l=(e,t)=>{var n,s,o;const r=i(e),a=null!==(n=null==t?void 0:t.groupMapping)&&void 0!==n?n:{},c={},l={},f={},p={},y={};let b=null!==(s=null==t?void 0:t.breakpoints)&&void 0!==s?s:{};const m=new Map;for(const e of r){const t=e.path[0];m.has(t)||m.set(t,[]),m.get(t).push(e)}const g=null==t?void 0:t.breakpointGroup;if(g&&m.has(g)){b={};for(const e of m.get(g)){b[e.path[e.path.length-1]]=S(e.value)}m.delete(g)}for(const[e,t]of m){const n=null!==(o=a[e])&&void 0!==o?o:u(e,t);if("ignore"!==n)switch(n){case"colors":d(t,e,c);break;case"typography":h(t,e,l);break;case"effects":v(t,e,f);break;case"borders":j(t,e,p);break;case"layout":$(t,e,y)}}const k={};return Object.keys(b).length&&(k.breakpoints=b),Object.keys(c).length&&(k.colors=c),Object.keys(l).length&&(k.typography=l),Object.keys(f).length&&(k.effects=f),Object.keys(p).length&&(k.borders=p),Object.keys(y).length&&(k.layout=y),k},u=(e,t)=>{var n;const s=null===(n=t[0])||void 0===n?void 0:n.type;if("color"===s)return"colors";if("typography"===s)return"typography";if("shadow"===s)return"effects";if("border"===s)return"borders";if("strokeStyle"===s)return"borders";if("transition"===s)return"effects";const o=e.toLowerCase();if(o.includes("color")||o.includes("palette"))return"colors";if(o.includes("font")||o.includes("typo")||o.includes("text"))return"typography";if(o.includes("spacing")||o.includes("space")||o.includes("gutter"))return"layout";if(o.includes("radius")||o.includes("border")||o.includes("outline"))return"borders";if(o.includes("shadow")||o.includes("blur")||o.includes("opacity")||o.includes("z-index")||o.includes("zindex")||o.includes("transition")||o.includes("effect"))return"effects";if("dimension"===s){if(o.includes("spacing")||o.includes("gap"))return"layout";if(o.includes("radius")||o.includes("border"))return"borders";if(o.includes("font")||o.includes("size"))return"typography"}return"ignore"},f=/^\{([^}]+)\}$/,p=e=>{if("string"!=typeof e)return;const t=e.match(f);if(!t)return;const n=t[1],s=n.indexOf("."),o=s<0?n:n.slice(0,s),r=s<0?"":n.slice(s+1),i="color"===o?"colors":o;return r?`${i}.${r}`:i},d=(e,t,n)=>{var s;const o=new Map,r=[];for(const t of e)if(t.path.length<=2)r.push(t);else{const e=t.path[1];o.has(e)||o.set(e,[]),o.get(e).push(t)}for(const e of r){const t=e.path[e.path.length-1];if(!n[t]){const s=p(e.value);n[t]=s?{external:s}:{base:String(e.value)}}}for(const[e,t]of o)if(1===t.length){const s=t[0],o=s.path[s.path.length-1];o===e?n[e]={base:String(s.value)}:(n[e]||(n[e]={base:String(t[0].value)}),n[e].variants={[o]:String(s.value)})}else{const o=null!==(s=t.find(e=>{const t=e.path[e.path.length-1];return"base"===t||"default"===t||"500"===t}))&&void 0!==s?s:t[0],r={};for(const e of t){if(e===o)continue;r[e.path.slice(2).join("-")]=String(e.value)}n[e]={base:String(o.value),...Object.keys(r).length?{variants:r}:{}}}},y={fontfamily:"fontFamily",fontsize:"fontSize",fontweight:"fontWeight",lineheight:"lineHeight",letterspacing:"letterSpacing",fontstyle:"fontStyle",texttransform:"textTransform",textdecoration:"textDecoration",textalign:"textAlign"},h=(e,t,n)=>{for(const s of e)if("typography"===s.type){const e=s.value,t=s.path.slice(1).join("-")||s.path[s.path.length-1];e.fontFamily&&b(n,"fontFamily",Array.isArray(e.fontFamily)?e.fontFamily.join(", "):e.fontFamily,t),e.fontSize&&b(n,"fontSize",x(e.fontSize),t),void 0!==e.fontWeight&&b(n,"fontWeight",e.fontWeight,t),void 0!==e.lineHeight&&b(n,"lineHeight",e.lineHeight,t),e.letterSpacing&&b(n,"letterSpacing",e.letterSpacing,t)}else{const e=m(s,t);if(!e)continue;const o=s.path[s.path.length-1],r="fontFamily"===s.type&&Array.isArray(s.value)?s.value.join(", "):"dimension"===s.type?x(s.value):s.value;b(n,e,r,o)}},b=(e,t,n,s)=>{if(!e[t])return void(e[t]={base:n,variants:{}});const o=e[t];"base"===s||"default"===s||"md"===s?o.base=n:o.variants[s]=n},m=(e,t)=>{if("fontFamily"===e.type)return"fontFamily";if("fontWeight"===e.type)return"fontWeight";const n=e.path.join(".").toLowerCase();for(const[e,t]of Object.entries(y))if(n.includes(e))return t;const s=t.toLowerCase();for(const[e,t]of Object.entries(y))if(s.includes(e))return t;return null},v=(e,t,n)=>{for(const t of e){const e=t.path[t.path.length-1];switch(t.type){case"shadow":{const s=w(t.value);g(n,"shadow",s,e);break}case"transition":{const s=t.value,o=s.timingFunction?`cubic-bezier(${s.timingFunction.join(", ")})`:"ease",r=`all ${s.duration} ${o}`;g(n,"transitions",r,e);break}case"dimension":t.path.join(".").toLowerCase().includes("blur")&&g(n,"blur",x(t.value),e);break;case"number":{const s=t.path.join(".").toLowerCase();s.includes("opacity")?g(n,"opacity",t.value,e):(s.includes("z-index")||s.includes("zindex"))&&g(n,"zIndex",t.value,e);break}}}},g=(e,t,n,s)=>{if(!e[t])return void(e[t]={base:n,variants:{}});const o=e[t];"base"===s||"default"===s||"md"===s?o.base=n:o.variants[s]=n},j=(e,t,n)=>{for(const t of e){const e=t.path[t.path.length-1];switch(t.type){case"border":{const s=t.value;k(n,"width",x(s.width),e),s.style&&k(n,"style",s.style,e);break}case"strokeStyle":k(n,"style",String(t.value),e);break;case"dimension":{const s=t.path.join(".").toLowerCase();s.includes("radius")?k(n,"radius",x(t.value),e):s.includes("offset")?k(n,"offset",x(t.value),e):s.includes("width")&&k(n,"width",x(t.value),e);break}}}},k=(e,t,n,s)=>{if(!e[t])return void(e[t]={base:n,variants:{}});const o=e[t];"base"===s||"default"===s||"md"===s?o.base=n:o.variants[s]=n},$=(e,t,n)=>{for(const t of e){if("dimension"!==t.type)continue;const e=t.path[t.path.length-1],s=S(t.value);n.spacing||(n.spacing={base:s,variants:{}});const o=n.spacing;"base"===e||"default"===e||"4"===e?o.base=s:o.variants[e]=s}},w=e=>Array.isArray(e)?e.map(e=>O(e)).join(", "):O(e),O=e=>{const t=[];return e.inset&&t.push("inset"),t.push(e.offsetX,e.offsetY,e.blur,e.spread,e.color),t.join(" ")},S=e=>{if("number"==typeof e)return e;const t=parseFloat(e);return isNaN(t)?0:e.endsWith("rem")?Math.round(16*t):t},x=e=>{if("number"==typeof e)return e;const t=parseFloat(e);return isNaN(t)?e:e.endsWith("px")?t:e},F=t=>{var n;const o=null===(n=t.$extensions)||void 0===n?void 0:n[s];if(o){if(1!==o.version)throw new e("REFRACT_E_DTCG_VERSION",`Unsupported refract DTCG extension version ${o.version} (this build reads version 1). Upgrade @theme-registry/refract to import this document's recipes.`);return o}},N=(e,n)=>{const s=l(e,n),o=F(e);return t(s,{adapter:n.adapter,propertiesOverlay:null==o?void 0:o.properties,ruleSetsOverlay:null==o?void 0:o.ruleSets,keyframesOverlay:null==o?void 0:o.keyframes,containersOverlay:null==o?void 0:o.containers})},z=(e,t)=>{var o;const r={};(null==t?void 0:t.name)&&(r.$name=t.name);const i=e.model.breakpoints;if(!1!==(null==t?void 0:t.includeBreakpoints)&&i&&Object.keys(i).length){const e={$type:"dimension"};for(const[t,n]of Object.entries(i))e[t]={$value:`${n}px`};r.breakpoint=e}const a=C(e),c=t=>{try{return String(e.resolveToken(t))}catch{return t}},l=a.get("colors");if(l){const e={$type:"color"};for(const[t,s]of l){const o={};void 0!==s.base&&(o.base={$value:n(String(s.base))});for(const[e,t]of Object.entries(s.members))o[e]={$value:n(String(t))};e[t]=o}r.color=e}const u=a.get("typography");if(u){const e={};for(const[t,n]of u){const s={$type:U(t)};void 0!==n.base&&(s.base={$value:W(n.base,n.baseUnit)});for(const[e,t]of Object.entries(n.members))s[e]={$value:W(t,n.memberUnits[e])};e[t]=s}r.typography=e}const f=a.get("effects");if(f)for(const[e,t]of f){const{groupName:n,type:s}=T(e);r[n]||(r[n]={$type:s});const o=r[n];void 0!==t.base&&(o.base={$value:L(e,t.base,c,t.baseUnit)});for(const[n,s]of Object.entries(t.members))o[n]={$value:L(e,s,c,t.memberUnits[n])}}const p=a.get("borders");if(p)for(const[e,t]of p){const{groupName:n,type:s}=M(e);r[n]||(r[n]={$type:s});const o=r[n];void 0!==t.base&&(o.base={$value:R(t.base,t.baseUnit)});for(const[e,n]of Object.entries(t.members))o[e]={$value:R(n,t.memberUnits[e])}}const d=a.get("layout");if(d)for(const[e,t]of d){if(e.includes("--"))continue;const n=e;r[n]||(r[n]={$type:"dimension"});const s=r[n];void 0!==t.base&&(s.base={$value:_(t.base,t.baseUnit)});for(const[e,n]of Object.entries(t.members))s[e]={$value:_(n,t.memberUnits[e])}}if(null==t?void 0:t.includeRecipes){const t=(e=>{const t={},n={},s={};for(const[o,r]of Object.entries(e.subsystems))r.properties&&Object.keys(r.properties).length&&(t[o]=r.properties),r.ruleSets&&Object.keys(r.ruleSets).length&&(n[o]=r.ruleSets),r.keyframes&&Object.keys(r.keyframes).length&&(s[o]=r.keyframes);const o=Object.keys(t).length>0,r=Object.keys(n).length>0,i=Object.keys(s).length>0,a=!!e.containers&&Object.keys(e.containers).length>0;if(o||r||i||a)return{version:1,...o?{properties:t}:{},...r?{ruleSets:n}:{},...i?{keyframes:s}:{},...a?{containers:e.containers}:{}}})(e.model);t&&(r.$extensions={...null!==(o=r.$extensions)&&void 0!==o?o:{},[s]:t})}return r},A=(e,t)=>void 0!==t?`${e}${t}`:e,C=e=>{const t=new Map;for(const n of Object.keys(e.tokens)){const s=n.indexOf(".");if(s<0)continue;const o=n.slice(0,s),r=n.slice(s+1),i=r.indexOf("."),a=i<0?r:r.slice(0,i),c=i<0?void 0:r.slice(i+1),l=e.tokens[n];if(void 0!==(null==l?void 0:l.external))continue;let u;if(void 0!==(null==l?void 0:l.struct))u=l.struct;else try{u=e.resolveToken(n)}catch{continue}const f=null==l?void 0:l.unit;let p=t.get(o);p||(p=new Map,t.set(o,p));let d=p.get(a);d||(d={members:{},memberUnits:{}},p.set(a,d)),void 0===c?(d.base=u,void 0!==f&&(d.baseUnit=f)):(d.members[c]=u,void 0!==f&&(d.memberUnits[c]=f))}return t},U=e=>{switch(e){case"fontFamily":return"fontFamily";case"fontWeight":return"fontWeight";case"fontSize":case"letterSpacing":return"dimension";default:return"number"}},W=(e,t)=>A(e,t),T=e=>{switch(e){case"shadow":return{groupName:"shadow",type:"shadow"};case"transitions":return{groupName:"transition",type:"transition"};case"blur":default:return{groupName:e,type:"dimension"};case"opacity":case"zIndex":return{groupName:e,type:"number"}}},L=(e,t,n,s)=>Array.isArray(t)?"transitions"===e?t.map(e=>{var t;const n=[e.property];return null==e.duration&&null==e.delay||n.push(`${null!==(t=e.duration)&&void 0!==t?t:0}ms`),e.timingFunction&&n.push(e.timingFunction),null!=e.delay&&n.push(`${e.delay}ms`),n.join(" ")}).join(", "):((e,t)=>e.map(e=>{const n=`0${(e=>{for(const t of[e.offsetX,e.offsetY,e.blur,e.spread])if(void 0!==t&&"number"!=typeof t)return t.unit;return"px"})(e)}`,s=e=>void 0===e?n:(e=>"number"==typeof e?`${e}px`:`${e.value}${e.unit}`)(e),o=[];return e.inset&&o.push("inset"),o.push(s(e.offsetX),s(e.offsetY)),null!=e.spread?o.push(s(e.blur),s(e.spread)):null!=e.blur&&o.push(s(e.blur)),e.color&&o.push(t(e.color)),o.join(" ")}).join(", "))(t,n):A(t,s),M=e=>{switch(e){case"radius":return{groupName:"radius",type:"dimension"};case"width":return{groupName:"borderWidth",type:"dimension"};case"offset":return{groupName:"outlineOffset",type:"dimension"};case"style":return{groupName:"borderStyle",type:"strokeStyle"};default:return{groupName:e,type:"dimension"}}},R=(e,t)=>A(e,t),_=(e,t)=>A(e,t);export{s as REFRACT_DTCG_EXTENSION,o as REFRACT_DTCG_EXTENSION_VERSION,l as fromDTCG,N as fromDTCGTheme,i as parseDTCGDocument,F as readRefractExtension,z as toDTCG};
|
|
2
|
+
//# sourceMappingURL=dtcg.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dtcg.esm.js","sources":["../src/dtcg/types.ts","../src/dtcg/parse.ts","../src/dtcg/import.ts","../src/dtcg/export.ts"],"sourcesContent":["/**\n * W3C Design Tokens Community Group (DTCG) format types.\n * Based on Second Editors' Draft (2024).\n */\n\n// --- Primitive token value types ---\n\nexport type DTCGColorValue = string;\n\nexport type DTCGDimensionValue = string; // e.g. \"16px\", \"1rem\"\n\nexport type DTCGFontFamilyValue = string | string[];\n\nexport type DTCGFontWeightValue = number | string; // 400 or \"bold\"\n\nexport type DTCGDurationValue = string; // \"200ms\", \"0.3s\"\n\nexport type DTCGCubicBezierValue = [number, number, number, number];\n\nexport type DTCGNumberValue = number;\n\n// --- Composite token value types ---\n\nexport type DTCGTypographyValue = {\n fontFamily: string | string[];\n fontSize: string;\n fontWeight: number | string;\n lineHeight: number | string;\n letterSpacing?: string;\n};\n\nexport type DTCGShadowLayerValue = {\n offsetX: string;\n offsetY: string;\n blur: string;\n spread: string;\n color: string;\n inset?: boolean;\n};\n\nexport type DTCGShadowValue = DTCGShadowLayerValue | DTCGShadowLayerValue[];\n\nexport type DTCGBorderValue = {\n color: string;\n width: string;\n style: string;\n};\n\nexport type DTCGTransitionValue = {\n duration: string;\n delay?: string;\n timingFunction: DTCGCubicBezierValue;\n};\n\n// --- Token types enum ---\n\nexport type DTCGTokenType =\n | \"color\"\n | \"dimension\"\n | \"fontFamily\"\n | \"fontWeight\"\n | \"duration\"\n | \"cubicBezier\"\n | \"number\"\n | \"typography\"\n | \"shadow\"\n | \"border\"\n | \"transition\"\n | \"strokeStyle\"\n | \"gradient\";\n\n// --- Token node ---\n\nexport type DTCGToken = {\n $value: unknown;\n $type?: DTCGTokenType;\n $description?: string;\n $extensions?: Record<string, unknown>;\n};\n\nexport type DTCGGroup = {\n $type?: DTCGTokenType;\n $description?: string;\n $extensions?: Record<string, unknown>;\n [key: string]: DTCGToken | DTCGGroup | DTCGTokenType | string | Record<string, unknown> | undefined;\n};\n\nexport type DTCGDocument = DTCGGroup & {\n $name?: string;\n};\n\n// --- Resolved token (after reference resolution) ---\n\nexport type ResolvedDTCGToken = {\n path: string[];\n type: DTCGTokenType;\n value: unknown;\n description?: string;\n extensions?: Record<string, unknown>;\n};\n\n// --- refract round-trip extension ---\n\n/**\n * The reverse-DNS `$extensions` key under which `toDTCG(theme, { includeRecipes: true })` stashes the\n * built rule-set / keyframe / container IR so a document round-trips `refract → DTCG → refract` without\n * loss. Standard DTCG tools ignore unknown extensions, so the payload is **refract-specific and not\n * portable** — property tokens are the interoperable surface; recipes ride here.\n */\nexport const REFRACT_DTCG_EXTENSION = \"com.theme-registry.refract\";\n\n/** The payload schema version under {@link REFRACT_DTCG_EXTENSION}; bumped on a breaking shape change. */\nexport const REFRACT_DTCG_EXTENSION_VERSION = 1;\n","import type { DTCGDocument, DTCGTokenType, ResolvedDTCGToken } from \"./types\";\nimport { RefractError } from \"../core/errors\";\n\nconst SPEC_KEYS = new Set([\"$value\", \"$type\", \"$description\", \"$extensions\", \"$name\"]);\n\nconst isToken = (node: unknown): boolean =>\n typeof node === \"object\" && node !== null && \"$value\" in (node as Record<string, unknown>);\n\n/**\n * Walk a DTCG document and extract all tokens with resolved types and paths.\n * References (`{path.to.token}`) are resolved recursively.\n */\nexport const parseDTCGDocument = (doc: DTCGDocument): ResolvedDTCGToken[] => {\n const tokens: ResolvedDTCGToken[] = [];\n const tokensByPath = new Map<string, ResolvedDTCGToken>();\n\n // First pass: collect all tokens with their raw values\n const walk = (node: Record<string, unknown>, path: string[], inheritedType?: DTCGTokenType) => {\n const groupType = (node.$type as DTCGTokenType | undefined) ?? inheritedType;\n\n for (const [key, child] of Object.entries(node)) {\n if (key.startsWith(\"$\")) continue;\n if (typeof child !== \"object\" || child === null) continue;\n\n const childPath = [...path, key];\n\n if (isToken(child)) {\n const token = child as Record<string, unknown>;\n const resolved: ResolvedDTCGToken = {\n path: childPath,\n type: (token.$type as DTCGTokenType) ?? groupType ?? \"color\",\n value: token.$value,\n description: token.$description as string | undefined,\n extensions: token.$extensions as Record<string, unknown> | undefined,\n };\n tokens.push(resolved);\n tokensByPath.set(childPath.join(\".\"), resolved);\n } else {\n walk(child as Record<string, unknown>, childPath, groupType);\n }\n }\n };\n\n walk(doc, []);\n\n // Second pass: resolve references\n for (const token of tokens) {\n token.value = resolveReferences(token.value, tokensByPath);\n }\n\n return tokens;\n};\n\nconst REFERENCE_PATTERN = /^\\{([^}]+)\\}$/;\n\nconst resolveReferences = (\n value: unknown,\n tokensByPath: Map<string, ResolvedDTCGToken>,\n visited = new Set<string>(),\n): unknown => {\n if (typeof value === \"string\") {\n const match = value.match(REFERENCE_PATTERN);\n if (match) {\n const refPath = match[1];\n if (visited.has(refPath)) {\n throw new RefractError(\"REFRACT_E_CYCLE\", `Circular token reference: ${refPath}`);\n }\n const referenced = tokensByPath.get(refPath);\n if (!referenced) {\n return value; // unresolved reference — leave as-is\n }\n visited.add(refPath);\n return resolveReferences(referenced.value, tokensByPath, visited);\n }\n return value;\n }\n\n if (Array.isArray(value)) {\n return value.map(item => resolveReferences(item, tokensByPath, new Set(visited)));\n }\n\n if (typeof value === \"object\" && value !== null) {\n const result: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value)) {\n result[k] = resolveReferences(v, tokensByPath, new Set(visited));\n }\n return result;\n }\n\n return value;\n};\n","import type { DTCGDocument, DTCGShadowLayerValue, DTCGTypographyValue, DTCGBorderValue, DTCGTransitionValue, ResolvedDTCGToken } from \"./types\";\nimport { REFRACT_DTCG_EXTENSION, REFRACT_DTCG_EXTENSION_VERSION } from \"./types\";\nimport type { RefractDTCGExtension } from \"./export\";\nimport { parseDTCGDocument } from \"./parse\";\nimport { createTheme, RefractError } from \"../core\";\nimport type { Theme, ThemeAdapter } from \"../core\";\n\ntype RawThemeInput = Record<string, unknown>;\n\nexport type FromDTCGOptions = {\n /**\n * How to map DTCG groups to refract subsystems.\n * Default: auto-detect from $type and group name.\n */\n groupMapping?: Record<string, \"colors\" | \"typography\" | \"effects\" | \"borders\" | \"layout\" | \"ignore\">;\n\n /**\n * Breakpoints as { name: pixelValue } — DTCG has no breakpoint type,\n * so these must be provided separately or mapped from dimension tokens.\n */\n breakpoints?: Record<string, number>;\n\n /**\n * DTCG group path to use as breakpoints source (e.g. \"breakpoint\").\n * Dimension values are parsed to pixels.\n */\n breakpointGroup?: string;\n};\n\n/**\n * Convert a DTCG token document into a `createTheme` raw input.\n *\n * Returns a plain object — modify it freely before passing to `createTheme`.\n */\nexport const fromDTCG = (doc: DTCGDocument, options?: FromDTCGOptions): RawThemeInput => {\n const tokens = parseDTCGDocument(doc);\n const groupMapping = options?.groupMapping ?? {};\n\n const colors: Record<string, unknown> = {};\n const typography: Record<string, unknown> = {};\n const effects: Record<string, unknown> = {};\n const borders: Record<string, unknown> = {};\n const layout: Record<string, unknown> = {};\n let breakpoints: Record<string, number> = options?.breakpoints ?? {};\n\n // Group tokens by their top-level path segment\n const grouped = new Map<string, ResolvedDTCGToken[]>();\n for (const token of tokens) {\n const topGroup = token.path[0];\n if (!grouped.has(topGroup)) grouped.set(topGroup, []);\n grouped.get(topGroup)!.push(token);\n }\n\n // Extract breakpoints if a breakpoint group is specified\n const bpGroup = options?.breakpointGroup;\n if (bpGroup && grouped.has(bpGroup)) {\n breakpoints = {};\n for (const token of grouped.get(bpGroup)!) {\n const name = token.path[token.path.length - 1];\n breakpoints[name] = parseDimension(token.value as string);\n }\n grouped.delete(bpGroup);\n }\n\n for (const [groupName, groupTokens] of grouped) {\n const mapping = groupMapping[groupName] ?? detectSubsystem(groupName, groupTokens);\n if (mapping === \"ignore\") continue;\n\n switch (mapping) {\n case \"colors\":\n mapColorTokens(groupTokens, groupName, colors);\n break;\n case \"typography\":\n mapTypographyTokens(groupTokens, groupName, typography);\n break;\n case \"effects\":\n mapEffectsTokens(groupTokens, groupName, effects);\n break;\n case \"borders\":\n mapBordersTokens(groupTokens, groupName, borders);\n break;\n case \"layout\":\n mapLayoutTokens(groupTokens, groupName, layout);\n break;\n }\n }\n\n const result: RawThemeInput = {};\n if (Object.keys(breakpoints).length) result.breakpoints = breakpoints;\n if (Object.keys(colors).length) result.colors = colors;\n if (Object.keys(typography).length) result.typography = typography;\n if (Object.keys(effects).length) result.effects = effects;\n if (Object.keys(borders).length) result.borders = borders;\n if (Object.keys(layout).length) result.layout = layout;\n\n return result;\n};\n\n// --- Auto-detection ---\n\nconst detectSubsystem = (\n groupName: string,\n tokens: ResolvedDTCGToken[],\n): \"colors\" | \"typography\" | \"effects\" | \"borders\" | \"layout\" | \"ignore\" => {\n const firstType = tokens[0]?.type;\n\n // By type\n if (firstType === \"color\") return \"colors\";\n if (firstType === \"typography\") return \"typography\";\n if (firstType === \"shadow\") return \"effects\";\n if (firstType === \"border\") return \"borders\"; // §14 — border geometry lives in `borders` now\n if (firstType === \"strokeStyle\") return \"borders\";\n if (firstType === \"transition\") return \"effects\";\n\n // By name convention\n const lower = groupName.toLowerCase();\n if (lower.includes(\"color\") || lower.includes(\"palette\")) return \"colors\";\n if (lower.includes(\"font\") || lower.includes(\"typo\") || lower.includes(\"text\")) return \"typography\";\n if (lower.includes(\"spacing\") || lower.includes(\"space\") || lower.includes(\"gutter\")) return \"layout\";\n // Borders keywords take precedence over effects (radius/border/outline moved out of effects).\n if (lower.includes(\"radius\") || lower.includes(\"border\") || lower.includes(\"outline\")) return \"borders\";\n if (lower.includes(\"shadow\") || lower.includes(\"blur\") || lower.includes(\"opacity\") ||\n lower.includes(\"z-index\") || lower.includes(\"zindex\") || lower.includes(\"transition\") ||\n lower.includes(\"effect\")) return \"effects\";\n\n // Dimension tokens: check naming\n if (firstType === \"dimension\") {\n if (lower.includes(\"spacing\") || lower.includes(\"gap\")) return \"layout\";\n if (lower.includes(\"radius\") || lower.includes(\"border\")) return \"borders\";\n if (lower.includes(\"font\") || lower.includes(\"size\")) return \"typography\";\n }\n\n return \"ignore\";\n};\n\n// --- External aliases (dec.6 / §12 Phase 2) ---\n\n/** A DTCG value left as `\"{group.token}\"` after parse — an alias whose target is ABSENT from the\n * document (`parseDTCGDocument` leaves an unresolvable reference verbatim). */\nconst UNRESOLVED_ALIAS = /^\\{([^}]+)\\}$/;\n\n/**\n * Map a genuinely-external DTCG alias (target absent from the doc) to a refract `external` token path\n * — the refract analog of \"this references a token another (parent) theme owns.\" The DTCG `color`\n * group renames to the `colors` subsystem; other groups pass through best-effort. Returns `undefined`\n * for a non-alias / resolved value (which stays a normal literal). A resolvable same-doc alias never\n * reaches here — `parseDTCGDocument` already flattened it to its literal.\n */\nconst aliasToExternalPath = (value: unknown): string | undefined => {\n if (typeof value !== \"string\") return undefined;\n const match = value.match(UNRESOLVED_ALIAS);\n if (!match) return undefined;\n const inner = match[1];\n const dot = inner.indexOf(\".\");\n const group = dot < 0 ? inner : inner.slice(0, dot);\n const rest = dot < 0 ? \"\" : inner.slice(dot + 1);\n const subsystem = group === \"color\" ? \"colors\" : group;\n return rest ? `${subsystem}.${rest}` : subsystem;\n};\n\n// --- Color mapping ---\n\nconst mapColorTokens = (tokens: ResolvedDTCGToken[], groupName: string, colors: Record<string, unknown>) => {\n // Group by second path segment (e.g. color.brand.primary → \"brand\")\n const subgroups = new Map<string, ResolvedDTCGToken[]>();\n const topLevel: ResolvedDTCGToken[] = [];\n\n for (const token of tokens) {\n if (token.path.length <= 2) {\n topLevel.push(token);\n } else {\n const sub = token.path[1];\n if (!subgroups.has(sub)) subgroups.set(sub, []);\n subgroups.get(sub)!.push(token);\n }\n }\n\n // Top-level color tokens → flat colors with base. A genuinely-external alias (absent target) →\n // a refract `external` passthrough (dec.6) rather than a literal `{ base }` (which would reject `{…}`).\n for (const token of topLevel) {\n const name = token.path[token.path.length - 1];\n if (!colors[name]) {\n const external = aliasToExternalPath(token.value);\n colors[name] = external ? { external } : { base: String(token.value) };\n }\n }\n\n // Subgroups → colors with variants\n for (const [subName, subTokens] of subgroups) {\n if (subTokens.length === 1) {\n const token = subTokens[0];\n const name = token.path[token.path.length - 1];\n if (name === subName) {\n colors[subName] = { base: String(token.value) };\n } else {\n if (!colors[subName]) colors[subName] = { base: String(subTokens[0].value) };\n (colors[subName] as Record<string, unknown>).variants = {\n [name]: String(token.value),\n };\n }\n } else {\n // Multiple tokens in subgroup → first or \"base\"/\"default\"/\"500\" is base, rest are variants\n const baseToken = subTokens.find(t => {\n const last = t.path[t.path.length - 1];\n return last === \"base\" || last === \"default\" || last === \"500\";\n }) ?? subTokens[0];\n\n const variants: Record<string, string> = {};\n for (const t of subTokens) {\n if (t === baseToken) continue;\n const variantName = t.path.slice(2).join(\"-\");\n variants[variantName] = String(t.value);\n }\n\n colors[subName] = {\n base: String(baseToken.value),\n ...(Object.keys(variants).length ? { variants } : {}),\n };\n }\n }\n};\n\n// --- Typography mapping ---\n\nconst TYPO_PROPERTY_MAP: Record<string, string> = {\n fontfamily: \"fontFamily\",\n fontsize: \"fontSize\",\n fontweight: \"fontWeight\",\n lineheight: \"lineHeight\",\n letterspacing: \"letterSpacing\",\n fontstyle: \"fontStyle\",\n texttransform: \"textTransform\",\n textdecoration: \"textDecoration\",\n textalign: \"textAlign\",\n};\n\nconst mapTypographyTokens = (tokens: ResolvedDTCGToken[], groupName: string, typography: Record<string, unknown>) => {\n for (const token of tokens) {\n if (token.type === \"typography\") {\n // Composite typography token → decompose into individual properties\n const value = token.value as DTCGTypographyValue;\n const variantName = token.path.slice(1).join(\"-\") || token.path[token.path.length - 1];\n\n if (value.fontFamily) {\n addTypographyVariant(typography, \"fontFamily\",\n Array.isArray(value.fontFamily) ? value.fontFamily.join(\", \") : value.fontFamily, variantName);\n }\n if (value.fontSize) {\n addTypographyVariant(typography, \"fontSize\", parseDimensionOrKeep(value.fontSize), variantName);\n }\n if (value.fontWeight !== undefined) {\n addTypographyVariant(typography, \"fontWeight\", value.fontWeight, variantName);\n }\n if (value.lineHeight !== undefined) {\n addTypographyVariant(typography, \"lineHeight\", value.lineHeight, variantName);\n }\n if (value.letterSpacing) {\n addTypographyVariant(typography, \"letterSpacing\", value.letterSpacing, variantName);\n }\n } else {\n // Individual token (fontFamily, fontSize, fontWeight, dimension)\n const propertyKey = detectTypoProperty(token, groupName);\n if (!propertyKey) continue;\n const variantName = token.path[token.path.length - 1];\n const value = token.type === \"fontFamily\" && Array.isArray(token.value)\n ? (token.value as string[]).join(\", \")\n : token.type === \"dimension\"\n ? parseDimensionOrKeep(token.value as string)\n : token.value;\n addTypographyVariant(typography, propertyKey, value as string | number, variantName);\n }\n }\n};\n\nconst addTypographyVariant = (\n typography: Record<string, unknown>,\n property: string,\n value: string | number,\n variantName: string,\n) => {\n if (!typography[property]) {\n typography[property] = { base: value, variants: {} };\n return;\n }\n const prop = typography[property] as { base: unknown; variants: Record<string, unknown> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"md\") {\n prop.base = value;\n } else {\n prop.variants[variantName] = value;\n }\n};\n\nconst detectTypoProperty = (token: ResolvedDTCGToken, groupName: string): string | null => {\n // Check token type\n if (token.type === \"fontFamily\") return \"fontFamily\";\n if (token.type === \"fontWeight\") return \"fontWeight\";\n\n // Check group or parent path naming\n const fullPath = token.path.join(\".\").toLowerCase();\n for (const [key, prop] of Object.entries(TYPO_PROPERTY_MAP)) {\n if (fullPath.includes(key)) return prop;\n }\n\n // Check group name\n const lower = groupName.toLowerCase();\n for (const [key, prop] of Object.entries(TYPO_PROPERTY_MAP)) {\n if (lower.includes(key)) return prop;\n }\n\n return null;\n};\n\n// --- Effects mapping ---\n\nconst mapEffectsTokens = (tokens: ResolvedDTCGToken[], groupName: string, effects: Record<string, unknown>) => {\n for (const token of tokens) {\n const variantName = token.path[token.path.length - 1];\n\n switch (token.type) {\n case \"shadow\": {\n const shadowStr = formatShadowValue(token.value);\n addEffectsVariant(effects, \"shadow\", shadowStr, variantName);\n break;\n }\n case \"transition\": {\n const transition = token.value as DTCGTransitionValue;\n const bezier = transition.timingFunction\n ? `cubic-bezier(${transition.timingFunction.join(\", \")})`\n : \"ease\";\n const transStr = `all ${transition.duration} ${bezier}`;\n addEffectsVariant(effects, \"transitions\", transStr, variantName);\n break;\n }\n case \"dimension\": {\n const lower = token.path.join(\".\").toLowerCase();\n if (lower.includes(\"blur\")) {\n addEffectsVariant(effects, \"blur\", parseDimensionOrKeep(token.value as string), variantName);\n }\n break;\n }\n case \"number\": {\n const lower = token.path.join(\".\").toLowerCase();\n if (lower.includes(\"opacity\")) {\n addEffectsVariant(effects, \"opacity\", token.value as number, variantName);\n } else if (lower.includes(\"z-index\") || lower.includes(\"zindex\")) {\n addEffectsVariant(effects, \"zIndex\", token.value as number, variantName);\n }\n break;\n }\n }\n }\n};\n\nconst addEffectsVariant = (\n effects: Record<string, unknown>,\n property: string,\n value: string | number,\n variantName: string,\n) => {\n if (!effects[property]) {\n effects[property] = { base: value, variants: {} };\n return;\n }\n const prop = effects[property] as { base: unknown; variants: Record<string, unknown> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"md\") {\n prop.base = value;\n } else {\n prop.variants[variantName] = value;\n }\n};\n\n// --- Borders mapping (§14) ---\n\nconst mapBordersTokens = (tokens: ResolvedDTCGToken[], groupName: string, borders: Record<string, unknown>) => {\n for (const token of tokens) {\n const variantName = token.path[token.path.length - 1];\n\n switch (token.type) {\n case \"border\": {\n // The DTCG `border` composite carries width + style + color; only the geometry maps to\n // borders tokens (§14.4 — color is never a borders token, so it is dropped on import).\n const border = token.value as DTCGBorderValue;\n addBordersVariant(borders, \"width\", parseDimensionOrKeep(border.width), variantName);\n if (border.style) addBordersVariant(borders, \"style\", border.style, variantName);\n break;\n }\n case \"strokeStyle\": {\n addBordersVariant(borders, \"style\", String(token.value), variantName);\n break;\n }\n case \"dimension\": {\n const lower = token.path.join(\".\").toLowerCase();\n if (lower.includes(\"radius\")) {\n addBordersVariant(borders, \"radius\", parseDimensionOrKeep(token.value as string), variantName);\n } else if (lower.includes(\"offset\")) {\n addBordersVariant(borders, \"offset\", parseDimensionOrKeep(token.value as string), variantName);\n } else if (lower.includes(\"width\")) {\n addBordersVariant(borders, \"width\", parseDimensionOrKeep(token.value as string), variantName);\n }\n break;\n }\n }\n }\n};\n\nconst addBordersVariant = (\n borders: Record<string, unknown>,\n property: string,\n value: string | number,\n variantName: string,\n) => {\n if (!borders[property]) {\n borders[property] = { base: value, variants: {} };\n return;\n }\n const prop = borders[property] as { base: unknown; variants: Record<string, unknown> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"md\") {\n prop.base = value;\n } else {\n prop.variants[variantName] = value;\n }\n};\n\n// --- Layout mapping ---\n\nconst mapLayoutTokens = (tokens: ResolvedDTCGToken[], groupName: string, layout: Record<string, unknown>) => {\n for (const token of tokens) {\n if (token.type !== \"dimension\") continue;\n const variantName = token.path[token.path.length - 1];\n const value = parseDimension(token.value as string);\n\n if (!layout.spacing) {\n layout.spacing = { base: value, variants: {} };\n }\n\n const spacing = layout.spacing as { base: number; variants: Record<string, number> };\n if (variantName === \"base\" || variantName === \"default\" || variantName === \"4\") {\n spacing.base = value;\n } else {\n spacing.variants[variantName] = value;\n }\n }\n};\n\n// --- Helpers ---\n\nconst formatShadowValue = (value: unknown): string => {\n if (Array.isArray(value)) {\n return value.map(layer => formatSingleShadow(layer as DTCGShadowLayerValue)).join(\", \");\n }\n return formatSingleShadow(value as DTCGShadowLayerValue);\n};\n\nconst formatSingleShadow = (layer: DTCGShadowLayerValue): string => {\n const parts: string[] = [];\n if (layer.inset) parts.push(\"inset\");\n parts.push(layer.offsetX, layer.offsetY, layer.blur, layer.spread, layer.color);\n return parts.join(\" \");\n};\n\nconst parseDimension = (value: string | number): number => {\n if (typeof value === \"number\") return value;\n const num = parseFloat(value);\n if (isNaN(num)) return 0;\n // Convert rem to px (assume 16px base)\n if (value.endsWith(\"rem\")) return Math.round(num * 16);\n return num;\n};\n\nconst parseDimensionOrKeep = (value: string | number): string | number => {\n if (typeof value === \"number\") return value;\n const num = parseFloat(value);\n if (isNaN(num)) return value;\n if (value.endsWith(\"px\")) return num;\n return value;\n};\n\n// --- refract round-trip (recipes via the com.theme-registry.refract extension) ---\n\n/**\n * Read the refract round-trip payload from a DTCG document's top-level `$extensions`, or `undefined`\n * when it carries none. `parseDTCGDocument` intentionally drops top-level `$extensions`, so this reads\n * `doc.$extensions` directly. Throws on a payload from a newer, unreadable schema version.\n */\nexport const readRefractExtension = (doc: DTCGDocument): RefractDTCGExtension | undefined => {\n const ext = doc.$extensions?.[REFRACT_DTCG_EXTENSION] as RefractDTCGExtension | undefined;\n if (!ext) return undefined;\n if (ext.version !== REFRACT_DTCG_EXTENSION_VERSION) {\n throw new RefractError(\n \"REFRACT_E_DTCG_VERSION\",\n `Unsupported refract DTCG extension version ${ext.version} (this build reads version ` +\n `${REFRACT_DTCG_EXTENSION_VERSION}). Upgrade @theme-registry/refract to import this document's recipes.`,\n );\n }\n return ext;\n};\n\n/**\n * Lossless `DTCG → refract` round-trip entry: {@link fromDTCG} for the property tokens, plus the\n * recipes / keyframes / containers the document stashed under `com.theme-registry.refract` reinjected\n * through createTheme's overlay. A plain DTCG document (no refract extension) round-trips to a\n * recipe-less theme — identical to `createTheme(fromDTCG(doc), { adapter })`.\n */\nexport const fromDTCGTheme = (\n doc: DTCGDocument,\n options: FromDTCGOptions & { adapter: ThemeAdapter },\n): Theme => {\n const raw = fromDTCG(doc, options);\n const ext = readRefractExtension(doc);\n return createTheme(raw, {\n adapter: options.adapter,\n propertiesOverlay: ext?.properties,\n ruleSetsOverlay: ext?.ruleSets,\n keyframesOverlay: ext?.keyframes,\n containersOverlay: ext?.containers,\n });\n};\n","import type { Theme } from \"../core\";\nimport type { Literal, ShadowDimension, ShadowLayer, TransitionPart } from \"../core\";\nimport type { ThemeModel, RuleSetGroup, Keyframe, ContainerModel, PropertyModel } from \"../core\";\nimport type { DTCGDocument, DTCGTokenType } from \"./types\";\nimport { REFRACT_DTCG_EXTENSION, REFRACT_DTCG_EXTENSION_VERSION } from \"./types\";\nimport { toHexColor } from \"../subsystems/colors/utils\";\n\n/** The refract round-trip payload stashed under {@link REFRACT_DTCG_EXTENSION}. Built IR, verbatim. */\nexport type RefractDTCGExtension = {\n version: number;\n /**\n * Per-subsystem property Model verbatim (§12 Phase 2) — the lossless channel for what the portable\n * DTCG token surface can't carry: appearance `modes` (a `PropertyOverride[]` list), `responsive`\n * overrides, derivation metadata (`{ ref, modifiers }`), and `external` passthroughs. Reinjected on\n * import via createTheme's `propertiesOverlay`. The standard resolved-literal tokens still emit\n * alongside for portability; this is refract-only (other tools ignore the extension).\n */\n properties?: Record<string, Record<string, PropertyModel>>;\n ruleSets?: Record<string, Record<string, RuleSetGroup>>;\n keyframes?: Record<string, Record<string, Keyframe>>;\n containers?: Record<string, ContainerModel>;\n};\n\n/**\n * Collect a theme's built property / rule-set / keyframe / container IR into the round-trip payload, or\n * `undefined` when the theme has none (so `includeRecipes` on an empty theme still emits no\n * `$extensions`, keeping standard output byte-identical). The Model is \"serializable as-is\", a plain walk.\n */\nconst buildRefractExtension = (model: ThemeModel): RefractDTCGExtension | undefined => {\n const properties: Record<string, Record<string, PropertyModel>> = {};\n const ruleSets: Record<string, Record<string, RuleSetGroup>> = {};\n const keyframes: Record<string, Record<string, Keyframe>> = {};\n for (const [sub, subModel] of Object.entries(model.subsystems)) {\n if (subModel.properties && Object.keys(subModel.properties).length) properties[sub] = subModel.properties;\n if (subModel.ruleSets && Object.keys(subModel.ruleSets).length) ruleSets[sub] = subModel.ruleSets;\n if (subModel.keyframes && Object.keys(subModel.keyframes).length) keyframes[sub] = subModel.keyframes;\n }\n const hasProperties = Object.keys(properties).length > 0;\n const hasRuleSets = Object.keys(ruleSets).length > 0;\n const hasKeyframes = Object.keys(keyframes).length > 0;\n const hasContainers = !!model.containers && Object.keys(model.containers).length > 0;\n if (!hasProperties && !hasRuleSets && !hasKeyframes && !hasContainers) return undefined;\n return {\n version: REFRACT_DTCG_EXTENSION_VERSION,\n ...(hasProperties ? { properties } : {}),\n ...(hasRuleSets ? { ruleSets } : {}),\n ...(hasKeyframes ? { keyframes } : {}),\n ...(hasContainers ? { containers: model.containers } : {}),\n };\n};\n\nexport type ToDTCGOptions = {\n /** Name for the DTCG document. */\n name?: string;\n\n /** Whether to include breakpoints as dimension tokens. Default: true. */\n includeBreakpoints?: boolean;\n\n /**\n * Stash the theme's built Model IR — **property tokens (incl. modes / responsive / derivation refs /\n * external), rule-sets, keyframes, containers** — under the reverse-DNS `com.theme-registry.refract`\n * `$extensions` key, so the document round-trips `refract → DTCG → refract` **losslessly** via\n * {@link fromDTCGTheme} (§12 Phase 2 widened this from recipes-only to the whole Model). **Not\n * portable** — other DTCG tools ignore the extension and see the resolved property tokens only.\n * Default `false` (standard output stays byte-identical).\n */\n includeRecipes?: boolean;\n};\n\n/**\n * Convert a built theme's tokens into a DTCG-compliant JSON document.\n *\n * **Model-first re-port:** this walks the flat, format-neutral `theme.tokens` map\n * (`\"<subsystem>.<property>[.<variant>]\" -> Ref`) — the single source of truth that\n * replaced the retired per-subsystem `theme.<sub>.tokens` shape. Each token path is\n * resolved to a concrete literal via `theme.resolveToken` (following aliases and\n * running `lighten` / `darken` derivations), then re-grouped into DTCG groups.\n *\n * DTCG carries **property tokens only** — recipes / composition are out of scope, and\n * layout structural-config knobs (property names containing `--`) are skipped.\n *\n * Returns a plain object — modify it freely before writing to a file.\n */\nexport const toDTCG = (theme: Theme, options?: ToDTCGOptions): DTCGDocument => {\n const doc: DTCGDocument = {};\n\n if (options?.name) {\n doc.$name = options.name;\n }\n\n // Breakpoints — read from the Model, emitted as dimension tokens.\n const breakpoints = theme.model.breakpoints;\n if (options?.includeBreakpoints !== false && breakpoints && Object.keys(breakpoints).length) {\n const bp: Record<string, unknown> = { $type: \"dimension\" as DTCGTokenType };\n for (const [name, value] of Object.entries(breakpoints)) {\n bp[name] = { $value: `${value}px` };\n }\n doc.breakpoint = bp;\n }\n\n // Group the flat token map by subsystem → property, resolving each path to a literal.\n const grouped = groupTokens(theme);\n\n // Resolve a `colors.*` (or any) token path to its literal for embedding in a composed shadow\n // string; falls back to the raw path if unresolvable (defensive).\n const resolveColor = (path: string): string => {\n try {\n return String(theme.resolveToken(path));\n } catch {\n return path;\n }\n };\n\n // Colors — { $type: color, <name>: { base, text?, <variant> } }\n const colors = grouped.get(\"colors\");\n if (colors) {\n const group: Record<string, unknown> = { $type: \"color\" as DTCGTokenType };\n for (const [name, prop] of colors) {\n const node: Record<string, unknown> = {};\n if (prop.base !== undefined) {\n node.base = { $value: toHexColor(String(prop.base)) };\n }\n for (const [member, value] of Object.entries(prop.members)) {\n node[member] = { $value: toHexColor(String(value)) };\n }\n group[name] = node;\n }\n doc.color = group;\n }\n\n // Typography — nested under `doc.typography`, one group per property.\n const typography = grouped.get(\"typography\");\n if (typography) {\n const typo: Record<string, unknown> = {};\n for (const [propName, prop] of typography) {\n const type = getTypographyTokenType(propName);\n const group: Record<string, unknown> = { $type: type };\n if (prop.base !== undefined) {\n group.base = { $value: formatTypoValue(prop.base, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatTypoValue(value, prop.memberUnits[variant]) };\n }\n typo[propName] = group;\n }\n doc.typography = typo;\n }\n\n // Effects — one top-level group per property, named/typed by getEffectsGroupInfo.\n const effects = grouped.get(\"effects\");\n if (effects) {\n for (const [propName, prop] of effects) {\n const { groupName, type } = getEffectsGroupInfo(propName);\n if (!doc[groupName]) {\n doc[groupName] = { $type: type };\n }\n const group = doc[groupName] as Record<string, unknown>;\n // §15: a structured shadow/transition token composes to a CSS string at the DTCG boundary\n // (its `colors.*` color ref resolved to a literal) — consistent with how a string-authored\n // shadow already exports. A fully-structured DTCG composite round-trip is a future enhancement.\n if (prop.base !== undefined) {\n group.base = { $value: formatEffectsValue(propName, prop.base, resolveColor, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatEffectsValue(propName, value, resolveColor, prop.memberUnits[variant]) };\n }\n }\n }\n\n // Borders (§14) — one top-level group per property (radius/width/offset → dimension px,\n // style → strokeStyle). Border geometry moved out of effects; color is never a borders token.\n const borders = grouped.get(\"borders\");\n if (borders) {\n for (const [propName, prop] of borders) {\n const { groupName, type } = getBordersGroupInfo(propName);\n if (!doc[groupName]) {\n doc[groupName] = { $type: type };\n }\n const group = doc[groupName] as Record<string, unknown>;\n if (prop.base !== undefined) {\n group.base = { $value: formatBordersValue(prop.base, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatBordersValue(value, prop.memberUnits[variant]) };\n }\n }\n }\n\n // Layout (spacing / gutters / aspectRatio) — dimension tokens. Structural-config\n // knobs (`columns--*` / `container--*`) are internal, not interchange tokens.\n const layout = grouped.get(\"layout\");\n if (layout) {\n for (const [propName, prop] of layout) {\n if (propName.includes(\"--\")) continue;\n const groupName = propName;\n if (!doc[groupName]) {\n doc[groupName] = { $type: \"dimension\" as DTCGTokenType };\n }\n const group = doc[groupName] as Record<string, unknown>;\n if (prop.base !== undefined) {\n group.base = { $value: formatDimensionValue(prop.base, prop.baseUnit) };\n }\n for (const [variant, value] of Object.entries(prop.members)) {\n group[variant] = { $value: formatDimensionValue(value, prop.memberUnits[variant]) };\n }\n }\n }\n\n // §DTCG round-trip — opt-in: stash the built rule-set/keyframe/container IR under the refract\n // extension key. Only touched when `includeRecipes` is set AND the theme actually has recipes, so\n // the standard property-token document stays byte-identical by default.\n if (options?.includeRecipes) {\n const ext = buildRefractExtension(theme.model);\n if (ext) doc.$extensions = { ...(doc.$extensions ?? {}), [REFRACT_DTCG_EXTENSION]: ext };\n }\n\n return doc;\n};\n\n// --- Flat-token grouping ---\n\ntype PropTokens = {\n /** the `<sub>.<prop>` base token, if present. */\n base?: Literal;\n /** the `<sub>.<prop>.<member>` variants / extras (e.g. colors' `text`). */\n members: Record<string, Literal>;\n /** §21 resolved length unit for `base` (absent = unit-less / non-length / raw string). */\n baseUnit?: string;\n /** §21 resolved length unit per member. */\n memberUnits: Record<string, string>;\n};\n\n/** A resolved dimension → DTCG text: append the §21 unit baked on the Model leaf; a unit-less value\n * (lineHeight, opacity, aspectRatio) or a raw string passes through untouched. */\nconst dimText = (value: Literal, unit?: string): string | number =>\n unit !== undefined ? `${value}${unit}` : value;\n\n/**\n * Group the flat `theme.tokens` map into `subsystem -> property -> { base, members }`,\n * resolving each path to a concrete literal via `theme.resolveToken`. Unresolvable\n * paths are skipped (defensive — a well-formed Model resolves everything).\n */\nconst groupTokens = (theme: Theme): Map<string, Map<string, PropTokens>> => {\n const out = new Map<string, Map<string, PropTokens>>();\n for (const path of Object.keys(theme.tokens)) {\n const dot = path.indexOf(\".\");\n if (dot < 0) continue;\n const subsystem = path.slice(0, dot);\n const rest = path.slice(dot + 1);\n const dot2 = rest.indexOf(\".\");\n const property = dot2 < 0 ? rest : rest.slice(0, dot2);\n const member = dot2 < 0 ? undefined : rest.slice(dot2 + 1);\n\n // §W6b / §12 Phase 2: an EXTERNAL token is a passthrough to a parent-owned var (`var(--…)`); it\n // has no value this document owns. Skip it from the portable token surface — emitting it as a\n // `var(--…)` colour would break re-import (colours reject `var()`). The lossless refract extension\n // carries it verbatim (its `PropertyModel.base` keeps `external`), so the round-trip restores it.\n const ref = theme.tokens[path];\n if (ref?.external !== undefined) continue;\n let value: Literal;\n if (ref?.struct !== undefined) {\n value = ref.struct as unknown as Literal;\n } else {\n try {\n value = theme.resolveToken(path);\n } catch {\n continue;\n }\n }\n const unit = ref?.unit; // §21 resolved length unit (absent for unit-less / raw / struct tokens)\n\n let subMap = out.get(subsystem);\n if (!subMap) {\n subMap = new Map<string, PropTokens>();\n out.set(subsystem, subMap);\n }\n let prop = subMap.get(property);\n if (!prop) {\n prop = { members: {}, memberUnits: {} };\n subMap.set(property, prop);\n }\n if (member === undefined) {\n prop.base = value;\n if (unit !== undefined) prop.baseUnit = unit;\n } else {\n prop.members[member] = value;\n if (unit !== undefined) prop.memberUnits[member] = unit;\n }\n }\n return out;\n};\n\n// --- Value formatting (per subsystem/property) ---\n\nconst getTypographyTokenType = (propName: string): DTCGTokenType => {\n switch (propName) {\n case \"fontFamily\": return \"fontFamily\";\n case \"fontWeight\": return \"fontWeight\";\n case \"fontSize\":\n case \"letterSpacing\": return \"dimension\";\n default: return \"number\";\n }\n};\n\n/** Typography value → DTCG. Length props (fontSize, letterSpacing) carry a resolved unit; the rest\n * (fontFamily string, fontWeight/lineHeight numbers) are unit-less → pass through. */\nconst formatTypoValue = (value: Literal, unit?: string): string | number => dimText(value, unit);\n\nconst getEffectsGroupInfo = (propName: string): { groupName: string; type: DTCGTokenType } => {\n switch (propName) {\n case \"shadow\": return { groupName: \"shadow\", type: \"shadow\" };\n case \"transitions\": return { groupName: \"transition\", type: \"transition\" };\n case \"blur\": return { groupName: propName, type: \"dimension\" };\n case \"opacity\":\n case \"zIndex\": return { groupName: propName, type: \"number\" };\n default: return { groupName: propName, type: \"dimension\" };\n }\n};\n\n/** A resolved shadow geometry field (§21 `{value,unit}`, or a bare number) → CSS text. */\nconst dtcgShadowDim = (dim: ShadowDimension): string =>\n typeof dim === \"number\" ? `${dim}px` : `${dim.value}${dim.unit}`;\n\n/** The layer's shared length unit — from the first resolved geometry field; `px` if none resolved. */\nconst dtcgLayerUnit = (layer: ShadowLayer): string => {\n for (const field of [layer.offsetX, layer.offsetY, layer.blur, layer.spread]) {\n if (field !== undefined && typeof field !== \"number\") return field.unit;\n }\n return \"px\";\n};\n\n/** Compose a structured shadow value (§15) → a CSS `box-shadow` string with color refs resolved\n * (translucency is carried by the referenced colour — an `alpha` colour variant, §13.3). Geometry\n * fields carry a resolved unit (§21); an absent (required) offset defaults to `0` in the layer's unit. */\nconst composeDtcgShadow = (layers: ShadowLayer[], resolveColor: (path: string) => string): string =>\n layers\n .map(layer => {\n const zero = `0${dtcgLayerUnit(layer)}`;\n const len = (dim: ShadowDimension | undefined): string => (dim === undefined ? zero : dtcgShadowDim(dim));\n const parts: string[] = [];\n if (layer.inset) parts.push(\"inset\");\n parts.push(len(layer.offsetX), len(layer.offsetY));\n if (layer.spread != null) parts.push(len(layer.blur), len(layer.spread));\n else if (layer.blur != null) parts.push(len(layer.blur));\n if (layer.color) parts.push(resolveColor(layer.color));\n return parts.join(\" \");\n })\n .join(\", \");\n\n/** Compose a structured transition value (§15) → a CSS `transition` string. */\nconst composeDtcgTransition = (parts: TransitionPart[]): string =>\n parts\n .map(part => {\n const segs: string[] = [part.property];\n if (part.duration != null || part.delay != null) segs.push(`${part.duration ?? 0}ms`);\n if (part.timingFunction) segs.push(part.timingFunction);\n if (part.delay != null) segs.push(`${part.delay}ms`);\n return segs.join(\" \");\n })\n .join(\", \");\n\nconst formatEffectsValue = (\n propName: string,\n value: Literal,\n resolveColor: (path: string) => string,\n unit?: string,\n): string | number => {\n // §15: shadow/transitions arrive as a structured array (cast to `Literal` in groupTokens).\n if (Array.isArray(value)) {\n return propName === \"transitions\"\n ? composeDtcgTransition(value as TransitionPart[])\n : composeDtcgShadow(value as ShadowLayer[], resolveColor);\n }\n // `blur` carries a resolved length unit (§21); `opacity`/`zIndex` are unit-less → pass through.\n return dimText(value, unit);\n};\n\nconst getBordersGroupInfo = (propName: string): { groupName: string; type: DTCGTokenType } => {\n switch (propName) {\n case \"radius\": return { groupName: \"radius\", type: \"dimension\" };\n case \"width\": return { groupName: \"borderWidth\", type: \"dimension\" };\n case \"offset\": return { groupName: \"outlineOffset\", type: \"dimension\" };\n case \"style\": return { groupName: \"borderStyle\", type: \"strokeStyle\" };\n default: return { groupName: propName, type: \"dimension\" };\n }\n};\n\n/** Borders geometry: radius/width/offset carry a resolved length unit (§21); `style` is a raw\n * strokeStyle string (no unit → passes through). */\nconst formatBordersValue = (value: Literal, unit?: string): string | number => dimText(value, unit);\n\n/** Layout dimension: spacing/gutters/sizes carry a resolved unit (§21); aspectRatio is unit-less. */\nconst formatDimensionValue = (value: Literal, unit?: string): string | number => dimText(value, unit);\n"],"names":["REFRACT_DTCG_EXTENSION","REFRACT_DTCG_EXTENSION_VERSION","isToken","node","parseDTCGDocument","doc","tokens","tokensByPath","Map","walk","path","inheritedType","groupType","_a","$type","key","child","Object","entries","startsWith","childPath","token","resolved","type","_b","_c","value","$value","description","$description","extensions","$extensions","push","set","join","resolveReferences","REFERENCE_PATTERN","visited","Set","match","refPath","has","RefractError","referenced","get","add","Array","isArray","map","item","result","k","v","fromDTCG","options","groupMapping","colors","typography","effects","borders","layout","breakpoints","grouped","topGroup","bpGroup","breakpointGroup","length","parseDimension","delete","groupName","groupTokens","mapping","detectSubsystem","mapColorTokens","mapTypographyTokens","mapEffectsTokens","mapBordersTokens","mapLayoutTokens","keys","firstType","lower","toLowerCase","includes","UNRESOLVED_ALIAS","aliasToExternalPath","inner","dot","indexOf","group","slice","rest","subsystem","subgroups","topLevel","sub","name","external","base","String","subName","subTokens","variants","baseToken","find","t","last","TYPO_PROPERTY_MAP","fontfamily","fontsize","fontweight","lineheight","letterspacing","fontstyle","texttransform","textdecoration","textalign","variantName","fontFamily","addTypographyVariant","fontSize","parseDimensionOrKeep","undefined","fontWeight","lineHeight","letterSpacing","propertyKey","detectTypoProperty","property","prop","fullPath","shadowStr","formatShadowValue","addEffectsVariant","transition","bezier","timingFunction","transStr","duration","border","addBordersVariant","width","style","spacing","layer","formatSingleShadow","parts","inset","offsetX","offsetY","blur","spread","color","num","parseFloat","isNaN","endsWith","Math","round","readRefractExtension","ext","version","fromDTCGTheme","raw","createTheme","adapter","propertiesOverlay","properties","ruleSetsOverlay","ruleSets","keyframesOverlay","keyframes","containersOverlay","containers","toDTCG","theme","$name","model","includeBreakpoints","bp","breakpoint","resolveColor","resolveToken","toHexColor","member","members","typo","propName","getTypographyTokenType","formatTypoValue","baseUnit","variant","memberUnits","getEffectsGroupInfo","formatEffectsValue","getBordersGroupInfo","formatBordersValue","formatDimensionValue","includeRecipes","subModel","subsystems","hasProperties","hasRuleSets","hasKeyframes","hasContainers","buildRefractExtension","dimText","unit","out","dot2","ref","struct","subMap","part","segs","delay","layers","zero","field","dtcgLayerUnit","len","dim","dtcgShadowDim","composeDtcgShadow"],"mappings":"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"}
|