@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,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout's `interpretRecipe` hook â resolves recipe declarations to token-path Refs.
|
|
3
|
+
*
|
|
4
|
+
* A layout recipe prop names a **spacing variant** (`paddingY: "xl"`, `gap: "relaxed"`),
|
|
5
|
+
* which this interpreter emits as a `layout.spacing.<variant>` token-path {@link Ref}
|
|
6
|
+
* (`layout.spacing` for the base). `background` passes through as a literal. One recipe prop
|
|
7
|
+
* can fan out to several CSS declarations (`paddingY` â `padding-top` + `padding-bottom`).
|
|
8
|
+
* Emits refs **directly** â no `var(--â¦)` strings; the CSS adapter maps each path to a
|
|
9
|
+
* `var(--â¦)` at render time. Ported + reshaped from the old `subsystems/layout/recipes.ts`.
|
|
10
|
+
*/
|
|
11
|
+
import type { InterpretedRecipeVariant } from "../../core/model";
|
|
12
|
+
import type { NormalizedRecipeVariant } from "../../core/normalize";
|
|
13
|
+
import type { RecipeInterpretContext } from "../../core/subsystem";
|
|
14
|
+
import type { LayoutRecipeProps } from "./types";
|
|
15
|
+
/** Interpret one layout recipe variant into base + responsive/state override declarations. */
|
|
16
|
+
export declare const interpretLayoutRecipeVariant: (variantName: string, variant: NormalizedRecipeVariant<LayoutRecipeProps, string>, ctx: RecipeInterpretContext) => InterpretedRecipeVariant<string>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout structural generators → **Model rule-sets** (the clean-room payoff).
|
|
3
|
+
*
|
|
4
|
+
* `columns` / `grids` / `stacks` / `container` used to emit `CssNode[]` that a lossless
|
|
5
|
+
* node↔rule-set codec (`routeLayoutStructuralThroughModel`) round-tripped into the Model.
|
|
6
|
+
* Here the generators emit {@link RuleSetGroup}s **natively** — declarations carry token-path
|
|
7
|
+
* {@link Ref}s (`layout.spacing.relaxed`), never `var(--…)` — so the codec never exists. The CSS
|
|
8
|
+
* adapter lowers these rule-sets to `CssRuleNode[]` (columns/grids/stacks via `lowerRecipeGroup`,
|
|
9
|
+
* container via the two-pass `lowerContainerGroup`, matching the old unshift-bases/push-medias order).
|
|
10
|
+
*
|
|
11
|
+
* The columns/container config knobs (`--…-columns--size`, `--…-container--inset`, …) ride along as
|
|
12
|
+
* **layout property tokens** (`configProperties`, merged as `extraProperties` in the Model); the
|
|
13
|
+
* structural rule declarations reference those config tokens by path (`layout.container--inset`),
|
|
14
|
+
* exactly the two-level indirection the old generators produced. Math ported verbatim from the old
|
|
15
|
+
* `subsystems/layout/tokens.ts`; only the output shape (rule-sets, not CSS) differs.
|
|
16
|
+
*
|
|
17
|
+
* The math forms variant keys from raw breakpoint keys + span numbers (`col-sm-3`); the adapter
|
|
18
|
+
* prepends the class prefix + sanitizes. No CSS syntax is produced here — core stays format-neutral.
|
|
19
|
+
*/
|
|
20
|
+
import type { PropertyModel, RuleSetGroup } from "../../core/model";
|
|
21
|
+
import { type MediaConfig } from "../../core/media";
|
|
22
|
+
import type { ColumnsValue, GridsDefinition, StacksDefinition } from "./types";
|
|
23
|
+
/** The structural output: rule-set groups (for the Model + CSS) + config `:root` tokens. */
|
|
24
|
+
export type LayoutStructuralOutput = {
|
|
25
|
+
ruleSetGroups: Record<string, RuleSetGroup>;
|
|
26
|
+
configProperties: Record<string, PropertyModel>;
|
|
27
|
+
};
|
|
28
|
+
export declare const buildColumns: (input: ColumnsValue | undefined, breakpoints: Record<string, number>) => LayoutStructuralOutput | undefined;
|
|
29
|
+
export declare const buildGrids: (grids: GridsDefinition | undefined) => LayoutStructuralOutput | undefined;
|
|
30
|
+
export declare const buildStacks: (stacks: StacksDefinition | undefined) => LayoutStructuralOutput | undefined;
|
|
31
|
+
export declare const buildContainer: (containerInput: unknown, breakpoints: Record<string, number>, sizeNames?: ReadonlySet<string>, mediaConfig?: MediaConfig) => LayoutStructuralOutput;
|
|
32
|
+
/**
|
|
33
|
+
* Run all four structural generators over the raw layout slice, merging their rule-set groups
|
|
34
|
+
* (structural order: columns → grids → stacks → container) and config tokens. Container always
|
|
35
|
+
* runs; the rest run only when their raw key is present.
|
|
36
|
+
*/
|
|
37
|
+
export declare const buildLayoutStructural: (rawSlice: Record<string, unknown>, breakpoints: Record<string, number>, mediaConfig?: MediaConfig) => LayoutStructuralOutput;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layout subsystem types (clean-room).
|
|
3
|
+
*
|
|
4
|
+
* Regular property keys (`spacing` / `gutters` / `aspectRatio`) normalize like any other
|
|
5
|
+
* subsystem; the structural keys (`columns` / `grids` / `stacks` / `container`) drive the
|
|
6
|
+
* structural generators (see `structural.ts`); `recipes` are ordinary token-path recipes.
|
|
7
|
+
*/
|
|
8
|
+
import type { PropertyValue, RecipeBlock } from "../../core/normalize";
|
|
9
|
+
export type ResponsiveQuery = "min" | "max" | "exact";
|
|
10
|
+
/** The whitelisted "regular" layout property keys (the ones that become `PropertyModel`s). */
|
|
11
|
+
export declare const LAYOUT_PROPERTY_KEYS: readonly string[];
|
|
12
|
+
/**
|
|
13
|
+
* Scale-synthesis authoring keys (§10.6) for a length scale (`spacing`/`gutters`/`sizes`). Declare
|
|
14
|
+
* one curve — `ratio` (geometric `base × ratio^n`, `steps` an ordered name array) or `step` (linear
|
|
15
|
+
* `step × n`, `steps` a name→multiplier map) — to synthesize the variant ramp instead of hand-listing
|
|
16
|
+
* it. Opt-in: absent both, the property behaves exactly as before. The same keys inside a `responsive`
|
|
17
|
+
* entry regenerate the whole named scale at that breakpoint (D6). Authored `variants` still win.
|
|
18
|
+
*/
|
|
19
|
+
export type LayoutScaleExtras = {
|
|
20
|
+
ratio?: number;
|
|
21
|
+
step?: number;
|
|
22
|
+
steps?: readonly string[] | Record<string, number>;
|
|
23
|
+
};
|
|
24
|
+
export type ColumnsConfig = {
|
|
25
|
+
size: number;
|
|
26
|
+
gutter?: string;
|
|
27
|
+
inset?: string;
|
|
28
|
+
};
|
|
29
|
+
export type ColumnsValue = number | ColumnsConfig;
|
|
30
|
+
export type GridDefinition = {
|
|
31
|
+
templateColumns?: string;
|
|
32
|
+
templateRows?: string;
|
|
33
|
+
autoRows?: string;
|
|
34
|
+
autoColumns?: string;
|
|
35
|
+
justifyItems?: string;
|
|
36
|
+
alignItems?: string;
|
|
37
|
+
justifyContent?: string;
|
|
38
|
+
alignContent?: string;
|
|
39
|
+
gap?: string;
|
|
40
|
+
responsive?: Array<{
|
|
41
|
+
breakpoint: string;
|
|
42
|
+
query?: ResponsiveQuery;
|
|
43
|
+
templateColumns?: string;
|
|
44
|
+
templateRows?: string;
|
|
45
|
+
autoRows?: string;
|
|
46
|
+
autoColumns?: string;
|
|
47
|
+
justifyItems?: string;
|
|
48
|
+
alignItems?: string;
|
|
49
|
+
justifyContent?: string;
|
|
50
|
+
alignContent?: string;
|
|
51
|
+
gap?: string;
|
|
52
|
+
}>;
|
|
53
|
+
};
|
|
54
|
+
export type GridsDefinition = Record<string, GridDefinition>;
|
|
55
|
+
export type StackDefinition = {
|
|
56
|
+
direction?: "row" | "column";
|
|
57
|
+
align?: string;
|
|
58
|
+
justify?: string;
|
|
59
|
+
wrap?: string;
|
|
60
|
+
inline?: boolean;
|
|
61
|
+
gap?: string;
|
|
62
|
+
responsive?: Array<{
|
|
63
|
+
breakpoint: string;
|
|
64
|
+
query?: ResponsiveQuery;
|
|
65
|
+
direction?: "row" | "column";
|
|
66
|
+
align?: string;
|
|
67
|
+
justify?: string;
|
|
68
|
+
wrap?: string;
|
|
69
|
+
inline?: boolean;
|
|
70
|
+
}>;
|
|
71
|
+
};
|
|
72
|
+
export type StacksDefinition = Record<string, StackDefinition>;
|
|
73
|
+
export type ContainerConfig = {
|
|
74
|
+
/** The resolved mode: `"fixed"` / `"fluid"` / a custom width string. */
|
|
75
|
+
mode: string;
|
|
76
|
+
inset?: string;
|
|
77
|
+
gutter?: string;
|
|
78
|
+
direction?: string;
|
|
79
|
+
align?: string;
|
|
80
|
+
justify?: string;
|
|
81
|
+
maxWidth?: string | number;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* One authored container variant (§8a) — a mode string (`"fixed"` / `"fluid"` / a width) or a
|
|
85
|
+
* config object. Distinct from {@link ContainerConfig}, which is the resolved `{ mode }` shape the
|
|
86
|
+
* structural generator produces.
|
|
87
|
+
*/
|
|
88
|
+
export type ContainerVariantRaw = string | {
|
|
89
|
+
base?: string;
|
|
90
|
+
inset?: string;
|
|
91
|
+
gutter?: string;
|
|
92
|
+
direction?: string;
|
|
93
|
+
align?: string;
|
|
94
|
+
justify?: string;
|
|
95
|
+
maxWidth?: string | number;
|
|
96
|
+
};
|
|
97
|
+
/** The authored `layout.container` value (§8a) — a mode string or a config with variants/responsive. */
|
|
98
|
+
export type ContainerRaw = string | {
|
|
99
|
+
base?: string;
|
|
100
|
+
inset?: string;
|
|
101
|
+
gutter?: string;
|
|
102
|
+
direction?: string;
|
|
103
|
+
align?: string;
|
|
104
|
+
justify?: string;
|
|
105
|
+
maxWidth?: string | number;
|
|
106
|
+
variants?: Record<string, ContainerVariantRaw>;
|
|
107
|
+
responsive?: Array<{
|
|
108
|
+
breakpoint: string;
|
|
109
|
+
query?: ResponsiveQuery;
|
|
110
|
+
target?: string;
|
|
111
|
+
direction?: string;
|
|
112
|
+
align?: string;
|
|
113
|
+
justify?: string;
|
|
114
|
+
inset?: string;
|
|
115
|
+
gutter?: string;
|
|
116
|
+
}>;
|
|
117
|
+
};
|
|
118
|
+
export type LayoutRecipeProps = {
|
|
119
|
+
paddingY?: string;
|
|
120
|
+
paddingX?: string;
|
|
121
|
+
marginY?: string;
|
|
122
|
+
marginX?: string;
|
|
123
|
+
gap?: string;
|
|
124
|
+
background?: string;
|
|
125
|
+
/**
|
|
126
|
+
* Sizing verbs (§22) — each names a `layout.sizes` variant and routes to its CSS longhand
|
|
127
|
+
* (`maxWidth` → `max-width`, no fan-out). A verb exists because it consumes a themed scale (`sizes`);
|
|
128
|
+
* dimensional CSS with no scale (`display`, `position`, …) stays in a component `css` delta.
|
|
129
|
+
*/
|
|
130
|
+
width?: string;
|
|
131
|
+
minWidth?: string;
|
|
132
|
+
maxWidth?: string;
|
|
133
|
+
height?: string;
|
|
134
|
+
minHeight?: string;
|
|
135
|
+
maxHeight?: string;
|
|
136
|
+
[property: string]: string | undefined;
|
|
137
|
+
};
|
|
138
|
+
/**
|
|
139
|
+
* The authored `raw.layout` slice (§8a). The only **closed** subsystem — its keys are fixed:
|
|
140
|
+
* the regular property tokens (`spacing`/`gutters`/`aspectRatio`), the four structural generators
|
|
141
|
+
* (`columns`/`grids`/`stacks`/`container`), and the `recipes` block. Authoring type only.
|
|
142
|
+
*/
|
|
143
|
+
export interface LayoutRaw {
|
|
144
|
+
spacing?: PropertyValue<string | number, LayoutScaleExtras>;
|
|
145
|
+
gutters?: PropertyValue<string | number, LayoutScaleExtras>;
|
|
146
|
+
aspectRatio?: PropertyValue<string | number>;
|
|
147
|
+
/** The sizing scale (§22) — one length scale for width/height/min/max, chosen at the recipe verb. */
|
|
148
|
+
sizes?: PropertyValue<string | number, LayoutScaleExtras>;
|
|
149
|
+
columns?: ColumnsValue;
|
|
150
|
+
grids?: GridsDefinition;
|
|
151
|
+
stacks?: StacksDefinition;
|
|
152
|
+
container?: ContainerRaw;
|
|
153
|
+
recipes?: RecipeBlock<LayoutRecipeProps>;
|
|
154
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The typography subsystem — a "regular" subsystem (no synthesized-ref derivations,
|
|
3
|
+
* unlike colors' tonal steps). Iterates `raw.typography` (skipping the reserved `recipes`
|
|
4
|
+
* key), runs the shared property normalize + the fontSize modular-scale synthesis per
|
|
5
|
+
* property, and interprets recipes into token-path refs. It grows a hook, never the spine.
|
|
6
|
+
*/
|
|
7
|
+
import type { Subsystem } from "../../core/subsystem";
|
|
8
|
+
export declare const typographySubsystem: Subsystem;
|
|
9
|
+
export type { TypographyRaw, TypographyPropertyValue } from "./types";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typography's `normalizeProperty` hook — modular font-size scale synthesis.
|
|
3
|
+
*
|
|
4
|
+
* When `fontSize` is authored with a `ratio`, this generates the scale steps
|
|
5
|
+
* (`xs`…`4xl`) as variants — each `base * ratio^step` (or a custom `algorithm`),
|
|
6
|
+
* rounded to `precision`. Author-declared steps are preserved and seed the chain.
|
|
7
|
+
* Non-`fontSize` properties and ratio-less `fontSize` pass through untouched.
|
|
8
|
+
*/
|
|
9
|
+
import type { NormalizedPropertyValue } from "../../core/normalize";
|
|
10
|
+
/**
|
|
11
|
+
* The typography `normalizeProperty` hook. Synthesizes the modular scale for
|
|
12
|
+
* `fontSize`; a pass-through for every other typography property.
|
|
13
|
+
*
|
|
14
|
+
* @param propertyKey The property being normalized (only `"fontSize"` is transformed).
|
|
15
|
+
* @param normalized The property after the shared property normalize pass.
|
|
16
|
+
*/
|
|
17
|
+
export declare const finalizeTypographyNormalization: (propertyKey: string, normalized: NormalizedPropertyValue<unknown>) => NormalizedPropertyValue<unknown>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typography's `interpretRecipe` hook â resolves recipe declarations to token-path Refs.
|
|
3
|
+
*
|
|
4
|
+
* A typography recipe prop value names a **variant** of the matching property (`fontSize:
|
|
5
|
+
* "3xl"`, `fontWeight: "bold"`), or the base value (`fontSize: "base"`). This interpreter
|
|
6
|
+
* emits a format-neutral {@link Ref} carrying the canonical token path â `typography.fontSize.3xl`
|
|
7
|
+
* for a variant, `typography.fontSize` for the base. It emits refs **directly** (no `var(--â¦)`
|
|
8
|
+
* strings); the CSS adapter maps each path to a `var(--â¦)` at render time, so `theme.model`
|
|
9
|
+
* carries no CSS syntax. Ported + reshaped from the old `subsystems/typography/recipes.ts`
|
|
10
|
+
* (which produced `var(--â¦)` strings via a prefix resolver).
|
|
11
|
+
*/
|
|
12
|
+
import type { InterpretedRecipeVariant } from "../../core/model";
|
|
13
|
+
import type { NormalizedRecipeVariant } from "../../core/normalize";
|
|
14
|
+
import type { RecipeInterpretContext } from "../../core/subsystem";
|
|
15
|
+
import type { TypographyRecipeProps } from "./types";
|
|
16
|
+
/**
|
|
17
|
+
* Interpret one typography recipe variant into base + responsive/state override declarations,
|
|
18
|
+
* each a token-path {@link Ref}. A responsive `variant:` swap inherits the sibling's base
|
|
19
|
+
* declarations (via `ctx.resolveRecipeVariant`).
|
|
20
|
+
*/
|
|
21
|
+
export declare const interpretTypographyRecipeVariant: (variantName: string, variant: NormalizedRecipeVariant<TypographyRecipeProps, string>, ctx: RecipeInterpretContext) => InterpretedRecipeVariant<string>;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PropertyValue, RecipeBlock } from "../../core/normalize";
|
|
2
|
+
/**
|
|
3
|
+
* Typography's fontSize-scale config. Only the normalize-relevant subset is ported
|
|
4
|
+
* for Step 0b (the recipe / token / source types grow in Step 2).
|
|
5
|
+
*/
|
|
6
|
+
export type TypographyScaleKey = "xs" | "sm" | "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl";
|
|
7
|
+
export type TypographyRatioKey = "minor-second" | "major-second" | "minor-third" | "major-third" | "perfect-fourth" | "augmented-fourth" | "perfect-fifth" | "golden";
|
|
8
|
+
export type FontSizeExtras = {
|
|
9
|
+
ratio?: TypographyRatioKey;
|
|
10
|
+
precision?: number;
|
|
11
|
+
unit?: "px" | "rem";
|
|
12
|
+
baseFontSize?: number;
|
|
13
|
+
algorithm?: (base: number, key: string, step: number, prev: number | null) => number;
|
|
14
|
+
};
|
|
15
|
+
export type FontSizeValue = PropertyValue<number, FontSizeExtras>;
|
|
16
|
+
/**
|
|
17
|
+
* A typography recipe declaration block. Each value names a **variant** of the
|
|
18
|
+
* matching typography property (`fontSize: "3xl"`, `fontWeight: "bold"`, `fontSize: "base"`
|
|
19
|
+
* for the base value) — the interpreter maps it to a token-path {@link import("../../core/model").Ref}.
|
|
20
|
+
* Only the keys in the property map are lowered; unknown keys are ignored.
|
|
21
|
+
*/
|
|
22
|
+
export type TypographyRecipeProps = {
|
|
23
|
+
fontFamily?: string;
|
|
24
|
+
fontSize?: string;
|
|
25
|
+
fontWeight?: string;
|
|
26
|
+
lineHeight?: string;
|
|
27
|
+
letterSpacing?: string;
|
|
28
|
+
fontStyle?: string;
|
|
29
|
+
textTransform?: string;
|
|
30
|
+
textDecoration?: string;
|
|
31
|
+
textAlign?: string;
|
|
32
|
+
[property: string]: string | undefined;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* A typography property value (§8a). Typography properties are heterogeneous —
|
|
36
|
+
* `fontFamily` is a string, `fontSize`/`fontWeight`/`lineHeight` numbers, `letterSpacing`
|
|
37
|
+
* a string — so the value unions `string | number`; the fontSize modular-scale extras
|
|
38
|
+
* (`ratio`/`precision`/…) ride along on every key (all optional, harmless elsewhere).
|
|
39
|
+
*/
|
|
40
|
+
export type TypographyPropertyValue = PropertyValue<string | number, FontSizeExtras>;
|
|
41
|
+
/**
|
|
42
|
+
* The authored `raw.typography` slice (§8a). An **open** map: keys are typography property
|
|
43
|
+
* names (`fontFamily`, `fontSize`, …), each a {@link TypographyPropertyValue}; the reserved
|
|
44
|
+
* `recipes` key is a {@link RecipeBlock} of typography recipes. Authoring type only.
|
|
45
|
+
*/
|
|
46
|
+
export interface TypographyRaw {
|
|
47
|
+
recipes?: RecipeBlock<TypographyRecipeProps>;
|
|
48
|
+
[property: string]: TypographyPropertyValue | RecipeBlock<TypographyRecipeProps> | undefined;
|
|
49
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@theme-registry/refract",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The framework-agnostic, format-neutral theme compiler core — build a ThemeModel from a RawTheme, then lower it with any adapter package (CSS, SCSS, JSON, styled-components).",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Petyo Stoyanov",
|
|
7
|
+
"email": "petyosv@gmail.com"
|
|
8
|
+
},
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/theme-registry/refract.git",
|
|
12
|
+
"directory": "packages/refract"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/theme-registry/refract/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://github.com/theme-registry/refract#readme",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"main": "./dist/index.cjs.js",
|
|
20
|
+
"module": "./dist/index.esm.js",
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"bin": {
|
|
23
|
+
"refract": "./dist/cli.js"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"/dist",
|
|
27
|
+
"/skills",
|
|
28
|
+
"/src/subsystems/colors/utils.ts"
|
|
29
|
+
],
|
|
30
|
+
"sideEffects": false,
|
|
31
|
+
"exports": {
|
|
32
|
+
".": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"import": "./dist/index.esm.js",
|
|
35
|
+
"require": "./dist/index.cjs.js"
|
|
36
|
+
},
|
|
37
|
+
"./dtcg": {
|
|
38
|
+
"types": "./dist/dtcg/index.d.ts",
|
|
39
|
+
"import": "./dist/dtcg.esm.js",
|
|
40
|
+
"require": "./dist/dtcg.cjs.js"
|
|
41
|
+
},
|
|
42
|
+
"./build": {
|
|
43
|
+
"types": "./dist/build/index.d.ts",
|
|
44
|
+
"import": "./dist/build.esm.js",
|
|
45
|
+
"require": "./dist/build.cjs.js"
|
|
46
|
+
},
|
|
47
|
+
"./adapter-kit": {
|
|
48
|
+
"types": "./dist/adapter-kit.d.ts",
|
|
49
|
+
"import": "./dist/adapter-kit.esm.js",
|
|
50
|
+
"require": "./dist/adapter-kit.cjs.js"
|
|
51
|
+
},
|
|
52
|
+
"./color-math": {
|
|
53
|
+
"types": "./dist/subsystems/colors/utils.d.ts",
|
|
54
|
+
"import": "./dist/color-math.esm.js",
|
|
55
|
+
"require": "./dist/color-math.cjs.js"
|
|
56
|
+
},
|
|
57
|
+
"./package.json": "./package.json"
|
|
58
|
+
},
|
|
59
|
+
"peerDependencies": {
|
|
60
|
+
"typescript": ">=5.0.0"
|
|
61
|
+
},
|
|
62
|
+
"peerDependenciesMeta": {
|
|
63
|
+
"typescript": {
|
|
64
|
+
"optional": true
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
69
|
+
"@rollup/plugin-typescript": "^11.1.6",
|
|
70
|
+
"@types/node": "^24",
|
|
71
|
+
"rimraf": "^5.0.5",
|
|
72
|
+
"rollup": "^3.29.4",
|
|
73
|
+
"rollup-plugin-peer-deps-external": "^2.2.4",
|
|
74
|
+
"typescript": "^5.4.2",
|
|
75
|
+
"vitest": "^4.1.10"
|
|
76
|
+
},
|
|
77
|
+
"scripts": {
|
|
78
|
+
"build": "rollup -c",
|
|
79
|
+
"typecheck": "tsc -p tsconfig.typecheck.json",
|
|
80
|
+
"clean": "rimraf dist",
|
|
81
|
+
"test": "vitest run"
|
|
82
|
+
}
|
|
83
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adapter-scaffold
|
|
3
|
+
description: Write your own refract output adapter when no shipped adapter targets your format — a standalone package or a local module in your own project, against the public defineAdapter contract. Use when you need a format refract doesn't ship (React-Native, Flutter, a bespoke JSON shape, …). Triggers: "no adapter for X", "write my own adapter", "custom output format", "defineAdapter", "React Native adapter".
|
|
4
|
+
tier: optional
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Write your own adapter
|
|
8
|
+
|
|
9
|
+
refract's adapter contract is public and stable, so if the shipped adapters (CSS, SCSS,
|
|
10
|
+
styled-components, JSON — see **adapter-usage**) don't target your format, you can write one **in
|
|
11
|
+
your own project** — a small standalone npm package or just a local module. You depend only on the
|
|
12
|
+
published `@theme-registry/refract`; you do **not** fork or clone the refract repo. Full contract
|
|
13
|
+
reference: `docs/extending.md`.
|
|
14
|
+
|
|
15
|
+
## The contract
|
|
16
|
+
|
|
17
|
+
`createTheme` calls your adapter's `bind(model, ctx)` once, then curries the returned `BoundSpec`
|
|
18
|
+
onto the theme. You author an `AdapterSpec<TUnit>` and wrap it with `defineAdapter`.
|
|
19
|
+
|
|
20
|
+
- **`TUnit`** — your output unit: `string` for text formats, an object type for JSON / RN / style
|
|
21
|
+
objects. `recipeName` is always `string`; only `renderRecipe` / `renderVariables` / `join` are
|
|
22
|
+
`TUnit`.
|
|
23
|
+
- **Required primitives** (the only format-specific work):
|
|
24
|
+
- `recipeName(subsystem, group, variant): string` — the rule-set's identity (a class, a key).
|
|
25
|
+
- `renderRecipe(subsystem, group, variant): TUnit` — one rule-set (base + state/responsive rules).
|
|
26
|
+
- `renderVariables(subsystem): TUnit` — one subsystem's tokens.
|
|
27
|
+
- `join(parts: TUnit[]): TUnit` — combine units.
|
|
28
|
+
- **`allowedStates?`** — the states your format can render (`["hover","focus",…]`); omit to accept
|
|
29
|
+
any. Core validates recipe `state:` refs against it before `bind`.
|
|
30
|
+
- **Optional:** `renderToken`, aggregator overrides (`renderAllRecipes`/`…Variables`/`renderAll`),
|
|
31
|
+
`extend(theme)` (attach runtime glue), `emit(plan?)` (build-time files — switch on `plan.type`
|
|
32
|
+
and throw a clear error for modes you don't support).
|
|
33
|
+
|
|
34
|
+
`defineAdapter(spec)` supplies the default aggregators as pure Model walks — override only if the
|
|
35
|
+
full document isn't a flat concatenation.
|
|
36
|
+
|
|
37
|
+
## The module
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import type { ThemeModel, AdapterSpec, RenderContext, ThemeAdapter } from "@theme-registry/refract";
|
|
41
|
+
import { defineAdapter } from "@theme-registry/refract";
|
|
42
|
+
// naming helpers if you need them: from "@theme-registry/refract/adapter-kit"
|
|
43
|
+
// OKLCH color math if you need it: from "@theme-registry/refract/color-math"
|
|
44
|
+
|
|
45
|
+
export type MyUnit = string; // ← or your object type
|
|
46
|
+
export type MyAdapterOptions = { /* prefix?, … */ };
|
|
47
|
+
|
|
48
|
+
export const createMyAdapter = (options: MyAdapterOptions = {}): ThemeAdapter<MyUnit> =>
|
|
49
|
+
defineAdapter({
|
|
50
|
+
name: "my-format",
|
|
51
|
+
version: 1,
|
|
52
|
+
// allowedStates: ["hover", "focus", "disabled"],
|
|
53
|
+
bind(model: ThemeModel, ctx: RenderContext) {
|
|
54
|
+
const { media, containers, resolve } = ctx; // resolve(ref) → value; containers = §10.5
|
|
55
|
+
void options; void media; void containers;
|
|
56
|
+
// Precompute per-subsystem lowering here (walk model.subsystems.<sub>.properties / .ruleSets).
|
|
57
|
+
return {
|
|
58
|
+
recipeName(subsystem, group, variant) { /* … */ return `${subsystem}-${group}-${variant}`; },
|
|
59
|
+
renderRecipe(subsystem, group, variant) { /* … */ return "" as MyUnit; },
|
|
60
|
+
renderVariables(subsystem) { /* … */ return "" as MyUnit; },
|
|
61
|
+
join(parts) { return parts.join("\n\n") as MyUnit; },
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Use it like any adapter: `createTheme(raw, { adapter: createMyAdapter() })`.
|
|
68
|
+
|
|
69
|
+
## Packaging choices
|
|
70
|
+
|
|
71
|
+
- **Local module** — simplest: a file in your app, imported straight into your `theme.config` or a
|
|
72
|
+
`createTheme` call. No publishing.
|
|
73
|
+
- **Standalone package** — if you want to reuse or share it: a normal npm package with
|
|
74
|
+
`@theme-registry/refract` as a **peer dependency** (the consumer's single installed core is
|
|
75
|
+
shared), marked `external` in your bundler so you never ship a copy of core.
|
|
76
|
+
|
|
77
|
+
## Notes
|
|
78
|
+
|
|
79
|
+
- Never import from a relative core path — always the published specifiers
|
|
80
|
+
(`@theme-registry/refract`, `/adapter-kit`, `/color-math`).
|
|
81
|
+
- Adapters are **not** subsystems; you don't register anything on core.
|
|
82
|
+
- Read `docs/extending.md` for the full `ThemeModel` walk and the `emit()` file contract.
|
|
83
|
+
|
|
84
|
+
*(Contributing an adapter back into the refract monorepo itself is a different, internal workflow —
|
|
85
|
+
that's the repo's own `adapter-scaffold` contributor skill, not this one.)*
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: adapter-usage
|
|
3
|
+
description: Choose a refract output adapter and use its call surface — CSS, SCSS, styled-components, or JSON, each a separate installable package. Use when deciding which format to emit, wiring createTheme with an adapter, or installing the adapter package. Triggers: "which adapter", "createTheme adapter", "CSS vs styled-components", "install refract-css", "adapter options / prefix / colorFormat / scheme".
|
|
4
|
+
tier: core
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Adapter usage
|
|
8
|
+
|
|
9
|
+
Core (`@theme-registry/refract`) ships **zero adapters** — that's what keeps it format-neutral.
|
|
10
|
+
Each adapter is a **separate package** you install alongside core. Pick by target format, then
|
|
11
|
+
pass a constructed adapter to `createTheme`.
|
|
12
|
+
|
|
13
|
+
## Which adapter
|
|
14
|
+
|
|
15
|
+
| Package | Factory | Emits | Choose it when |
|
|
16
|
+
|---|---|---|---|
|
|
17
|
+
| `@theme-registry/refract-css` | `createCssAdapter` | `:root` custom properties + recipe classes, `@media`/`@container`/`@keyframes` | Default. Framework-agnostic; runtime theming by swapping `:root`; MFE isolation via `prefix`. |
|
|
18
|
+
| `@theme-registry/refract-styled-components` | `createStyledComponentsAdapter` | TS/JS modules (literal `theme` object + tree-shakeable `css` recipes + `GlobalStyle`) | React apps on styled-components ^6. No `var()`; dark lives in each recipe so it tree-shakes. |
|
|
19
|
+
| `@theme-registry/refract-scss` | `createScssAdapter` | Sass `$variables` + `@use` partials + mixins/classes | A Sass build wanting compile-time `$variables`. |
|
|
20
|
+
| `@theme-registry/refract-json` | `createJsonAdapter` | The full model as address-keyed JSON (refs kept beside resolved values) | Data-interchange, tooling, or feeding a non-CSS consumer. |
|
|
21
|
+
|
|
22
|
+
If the format you need has no adapter, you can write one — see the opt-in **adapter-scaffold**
|
|
23
|
+
guide (build a standalone adapter against the public `defineAdapter` contract).
|
|
24
|
+
|
|
25
|
+
## Install the package you picked
|
|
26
|
+
|
|
27
|
+
Add core **and** the chosen adapter (detect the package manager from the lockfile):
|
|
28
|
+
|
|
29
|
+
```
|
|
30
|
+
npm i @theme-registry/refract @theme-registry/refract-css
|
|
31
|
+
# styled-components target also needs the peer:
|
|
32
|
+
npm i @theme-registry/refract-styled-components styled-components
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Call surface
|
|
36
|
+
|
|
37
|
+
`createTheme(raw, { adapter })` — `adapter` is **required**. Returns a `Theme` with the
|
|
38
|
+
format-neutral surface (`model`, `tokens`, `resolveToken(path)`, `override(partial)`), plus
|
|
39
|
+
whatever the adapter attaches via `extend()`:
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { createTheme } from "@theme-registry/refract";
|
|
43
|
+
import { createCssAdapter } from "@theme-registry/refract-css";
|
|
44
|
+
|
|
45
|
+
const theme = createTheme(raw, { adapter: createCssAdapter({ prefix: "acme" }) });
|
|
46
|
+
theme.css; // full stylesheet
|
|
47
|
+
theme.classes; // recipe → class name map
|
|
48
|
+
theme.getClass("components", "buttons", "primary");
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
- **CSS** adds `theme.css` / `variablesCss` / `recipesCss` / `classes` / `getClass()` /
|
|
52
|
+
`renderRecipe()` / `media`.
|
|
53
|
+
- **styled-components** adds `theme.theme` (for `<ThemeProvider>`) / `recipes` / `GlobalStyle` /
|
|
54
|
+
`media` / `scheme`.
|
|
55
|
+
- **JSON** adds `theme.json` / `jsonString`; **SCSS** adds `theme.scss` / `variablesScss` /
|
|
56
|
+
`rulesScss` / `classes`.
|
|
57
|
+
|
|
58
|
+
See **consuming-the-output** for wiring these into an app.
|
|
59
|
+
|
|
60
|
+
## Adapter options (constructor)
|
|
61
|
+
|
|
62
|
+
Options are passed when constructing the adapter, never as CLI flags. The common ones:
|
|
63
|
+
|
|
64
|
+
- **CSS** — `prefix` (default `"dt"`, also the class prefix + MFE isolation), `classPrefix`,
|
|
65
|
+
`inline` (bake values, drop `var()`), `colorFormat: "rgb" | "hex" | "oklch"`, `naming` (§7B
|
|
66
|
+
override hook), `layer: string | boolean` (wrap output in `@layer` for deterministic precedence
|
|
67
|
+
under app CSS), `reducedMotion: true` (append a `prefers-reduced-motion` reduce block). The last
|
|
68
|
+
two are single-file-emit only and off by default (byte-identical).
|
|
69
|
+
- **styled-components** — `language: "ts" | "js"`, `emit: "single" | "split"`,
|
|
70
|
+
`scheme: "media" | "attribute" | "both"` (dark realization), `helpers: ["color-math"]`,
|
|
71
|
+
`naming`.
|
|
72
|
+
- **SCSS** — `prefix`, `inline`, `indent`, `layer` (same as CSS). **JSON** — minimal; see
|
|
73
|
+
`docs/css-adapter.md` and `docs/authoring.md` for the full tables.
|
|
74
|
+
|
|
75
|
+
Cross-format concerns — emit modes, dark-mode strategy, the CLI — live in **build-config**.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: build-config
|
|
3
|
+
description: Wire the refract build — theme.config.ts (defineConfig, targets), the emit modes (single/split/subsystem/components), the refract CLI (init/build/import/tokens), and per-target dark-mode strategy. Use when emitting a theme to disk rather than building it at runtime. Triggers: "theme.config", "defineConfig", "refract build", "emit split/subsystem/components", "output multiple formats", "dark mode strategy", "refract init".
|
|
4
|
+
tier: core
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Build config
|
|
8
|
+
|
|
9
|
+
Two ways to realize a theme: **at runtime** via `createTheme(raw, { adapter })` (see
|
|
10
|
+
**adapter-usage**), or **to disk** via a `theme.config` + the `refract` CLI. This guide is the
|
|
11
|
+
disk path.
|
|
12
|
+
|
|
13
|
+
## `theme.config.(ts|mjs|js)`
|
|
14
|
+
|
|
15
|
+
The config is **your code** — it imports the adapter(s) and the raw theme, and that import *is*
|
|
16
|
+
the extensibility seam (like Rollup/Vite). Adapter options are passed at construction, not as CLI
|
|
17
|
+
flags. Multiple targets emit multiple formats from one theme. Keep the raw theme in a sibling
|
|
18
|
+
`theme.raw.ts` (the `.ts` config graph-compiles, so `import { raw } from "./theme.raw"` resolves).
|
|
19
|
+
|
|
20
|
+
```ts
|
|
21
|
+
import { defineConfig } from "@theme-registry/refract/build";
|
|
22
|
+
import { createCssAdapter } from "@theme-registry/refract-css";
|
|
23
|
+
import { createStyledComponentsAdapter } from "@theme-registry/refract-styled-components";
|
|
24
|
+
import { raw } from "./theme.raw";
|
|
25
|
+
|
|
26
|
+
export default defineConfig({
|
|
27
|
+
raw,
|
|
28
|
+
targets: [
|
|
29
|
+
{ name: "css", adapter: createCssAdapter(), outDir: "dist/theme" },
|
|
30
|
+
{ name: "sc", adapter: createStyledComponentsAdapter({ language: "ts" }), outDir: "dist/sc" },
|
|
31
|
+
],
|
|
32
|
+
// media / units / baseFontSize resolve once so every target emits identical units.
|
|
33
|
+
});
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`ThemeConfig` = `{ raw, targets, media?, units?, baseFontSize? }`. Each `EmitTarget` =
|
|
37
|
+
`{ adapter, outDir, name?, emit?, helpers? }`. Resolution order: `theme.config.ts` → `.mjs` →
|
|
38
|
+
`.js` (a `.ts` config lazy-loads the optional `typescript` peer).
|
|
39
|
+
|
|
40
|
+
## Emit modes (`emit` on a target)
|
|
41
|
+
|
|
42
|
+
Core owns the vocabulary; **each adapter decides which modes it honors** and throws a clear error
|
|
43
|
+
otherwise.
|
|
44
|
+
|
|
45
|
+
| Mode | Output | Notes |
|
|
46
|
+
|---|---|---|
|
|
47
|
+
| `single` (default) | one file | `{ file }` renames it |
|
|
48
|
+
| `split` | rules file + variables file | load-order contract, **no `@import`** |
|
|
49
|
+
| `subsystem` | a styles+variables pair per subsystem | `filename(subsystem, kind)` |
|
|
50
|
+
| `components` | one self-contained rule-set per component variant | `inline` defaults **true** (bakes values); `inline: false` emits `var()` + a tree-shaken variables file |
|
|
51
|
+
|
|
52
|
+
Only `single` / `split` may omit `type`. Support matrix: **CSS** and **JSON** = all four; **SCSS**
|
|
53
|
+
= single/split/components (subsystem throws); **styled-components** = single/split only (ES modules
|
|
54
|
+
tree-shake, so the CSS-only modes are redundant).
|
|
55
|
+
|
|
56
|
+
## The `refract` CLI
|
|
57
|
+
|
|
58
|
+
- `refract init [--js|--mjs] [--force]` — scaffold a runnable `theme.config`.
|
|
59
|
+
- `refract build [--config <path>] [--target <name|index>] [--out <dir>]` — emit each target.
|
|
60
|
+
- `refract import <tokens.json> […]` — seed a theme from a DTCG document (see **dtcg-import**).
|
|
61
|
+
- `refract tokens [--config <path>] [--out <file>]` — DTCG export (see **dtcg-import**).
|
|
62
|
+
- `refract help`.
|
|
63
|
+
|
|
64
|
+
Run via `npx refract <cmd>`. `outDir` resolves relative to the config file's directory.
|
|
65
|
+
|
|
66
|
+
## Dark-mode strategy (differs by target)
|
|
67
|
+
|
|
68
|
+
- **CSS / SCSS / JSON** — dark rides the *referenced token's own `modes`* (see **theme-foundations**);
|
|
69
|
+
a token with a `dark` value emits `@media (prefers-color-scheme: dark)` overrides. No separate
|
|
70
|
+
global switch; `colorFormat` is the main CSS colour knob.
|
|
71
|
+
- **styled-components** — an explicit `scheme` option: `"media"` (OS), `"attribute"`
|
|
72
|
+
(`[data-theme="dark"]` manual toggle), or `"both"`.
|
|
73
|
+
|
|
74
|
+
## Vendored helpers
|
|
75
|
+
|
|
76
|
+
`helpers: ["color-math"]` on a target materializes a shared helper module (live `lighten`/`darken`/
|
|
77
|
+
`alpha`) next to the output — opt-in, only when named.
|