zyzz 0.0.2 → 0.0.5
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/README.md +34 -19
- package/dist/Config.d.ts +16 -167
- package/dist/Config.d.ts.map +1 -1
- package/dist/Config.js +7 -246
- package/dist/Config.js.map +1 -1
- package/dist/Style.d.ts +19 -13
- package/dist/Style.d.ts.map +1 -1
- package/dist/Style.js +73 -7
- package/dist/Style.js.map +1 -1
- package/dist/Vars.d.ts +114 -0
- package/dist/Vars.d.ts.map +1 -0
- package/dist/Vars.js +42 -0
- package/dist/Vars.js.map +1 -0
- package/dist/compiler/Graph.js +11 -8
- package/dist/compiler/Graph.js.map +1 -1
- package/dist/compiler/Native.d.ts +5 -5
- package/dist/compiler/Native.d.ts.map +1 -1
- package/dist/compiler/Native.js +21 -21
- package/dist/compiler/Native.js.map +1 -1
- package/dist/compiler/Source.d.ts +10 -6
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +66 -11
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/Transform.d.ts +1 -1
- package/dist/compiler/Transform.d.ts.map +1 -1
- package/dist/compiler/Transform.js +59 -21
- package/dist/compiler/Transform.js.map +1 -1
- package/dist/compiler/internal/Compositions.d.ts +5 -0
- package/dist/compiler/internal/Compositions.d.ts.map +1 -1
- package/dist/compiler/internal/Compositions.js +22 -3
- package/dist/compiler/internal/Compositions.js.map +1 -1
- package/dist/compiler/internal/Configurations.d.ts.map +1 -1
- package/dist/compiler/internal/Configurations.js +73 -12
- package/dist/compiler/internal/Configurations.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts +1 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +162 -13
- package/dist/compiler/internal/Contract.js.map +1 -1
- package/dist/compiler/internal/Contributions.js +1 -1
- package/dist/compiler/internal/Contributions.js.map +1 -1
- package/dist/compiler/internal/Dynamic.js +1 -1
- package/dist/compiler/internal/Dynamic.js.map +1 -1
- package/dist/compiler/internal/Expression.d.ts +3 -0
- package/dist/compiler/internal/Expression.d.ts.map +1 -1
- package/dist/compiler/internal/Expression.js +21 -0
- package/dist/compiler/internal/Expression.js.map +1 -1
- package/dist/compiler/internal/Identifiers.d.ts +1 -1
- package/dist/compiler/internal/Identifiers.d.ts.map +1 -1
- package/dist/compiler/internal/Identifiers.js +2 -2
- package/dist/compiler/internal/Identifiers.js.map +1 -1
- package/dist/compiler/internal/NativeBindings.d.ts +1 -1
- package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
- package/dist/compiler/internal/NativeBindings.js +3 -3
- package/dist/compiler/internal/NativeBindings.js.map +1 -1
- package/dist/compiler/internal/PackedStyles.d.ts +1 -1
- package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
- package/dist/compiler/internal/PackedStyles.js +15 -25
- package/dist/compiler/internal/PackedStyles.js.map +1 -1
- package/dist/compiler/internal/Recipes.js +1 -1
- package/dist/compiler/internal/Recipes.js.map +1 -1
- package/dist/compiler/internal/Selectors.js +1 -1
- package/dist/compiler/internal/Selectors.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts +12 -3
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +192 -52
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/compiler/internal/{Variables.d.ts → Vars.d.ts} +1 -1
- package/dist/compiler/internal/Vars.d.ts.map +1 -0
- package/dist/compiler/internal/{Variables.js → Vars.js} +3 -3
- package/dist/compiler/internal/Vars.js.map +1 -0
- package/dist/default.d.ts +451 -1649
- package/dist/default.d.ts.map +1 -1
- package/dist/default.js +389 -80
- package/dist/default.js.map +2 -2
- package/dist/default.js.zyzz.json +1 -1
- package/dist/esbuild/index.d.ts +3 -0
- package/dist/esbuild/index.d.ts.map +1 -0
- package/dist/esbuild/index.js +5 -0
- package/dist/esbuild/index.js.map +1 -0
- package/dist/index.d.ts +4 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/internal/Authoring.d.ts +1 -1
- package/dist/internal/Authoring.d.ts.map +1 -1
- package/dist/internal/Authoring.js +4 -4
- package/dist/internal/Authoring.js.map +1 -1
- package/dist/internal/Binding.d.ts +1 -1
- package/dist/internal/Binding.d.ts.map +1 -1
- package/dist/internal/Completion.d.ts +19 -0
- package/dist/internal/Completion.d.ts.map +1 -0
- package/dist/internal/Completion.js +2 -0
- package/dist/internal/Completion.js.map +1 -0
- package/dist/internal/Condition.d.ts +3 -1
- package/dist/internal/Condition.d.ts.map +1 -1
- package/dist/internal/Condition.js.map +1 -1
- package/dist/internal/Configuration.d.ts +248 -0
- package/dist/internal/Configuration.d.ts.map +1 -0
- package/dist/internal/Configuration.js +343 -0
- package/dist/internal/Configuration.js.map +1 -0
- package/dist/internal/Shorthands.d.ts +1 -1
- package/dist/internal/Shorthands.d.ts.map +1 -1
- package/dist/internal/Shorthands.js +1 -0
- package/dist/internal/Shorthands.js.map +1 -1
- package/dist/{Theme.d.ts → internal/Theme.d.ts} +24 -19
- package/dist/internal/Theme.d.ts.map +1 -0
- package/dist/{Theme.js → internal/Theme.js} +57 -14
- package/dist/internal/Theme.js.map +1 -0
- package/dist/internal/Token.d.ts +46 -16
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +89 -5
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/Typography.d.ts +31 -0
- package/dist/internal/Typography.d.ts.map +1 -0
- package/dist/internal/Typography.js +54 -0
- package/dist/internal/Typography.js.map +1 -0
- package/dist/internal/Value.d.ts +6 -1
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VariableSets.d.ts +20 -0
- package/dist/internal/VariableSets.d.ts.map +1 -0
- package/dist/internal/VariableSets.js +317 -0
- package/dist/internal/VariableSets.js.map +1 -0
- package/dist/next/loader.js +15 -5
- package/dist/next/loader.js.map +1 -1
- package/dist/node/Host.d.ts.map +1 -1
- package/dist/node/Host.js +1 -1
- package/dist/node/Host.js.map +1 -1
- package/dist/react-native/Host.d.ts +2 -2
- package/dist/react-native/Host.d.ts.map +1 -1
- package/dist/react-native/Host.js +4 -4
- package/dist/react-native/Host.js.map +1 -1
- package/dist/react-native/StyleSheet.d.ts +9 -8
- package/dist/react-native/StyleSheet.d.ts.map +1 -1
- package/dist/react-native/StyleSheet.js +29 -23
- package/dist/react-native/StyleSheet.js.map +1 -1
- package/dist/react-native/Variants.d.ts +3 -3
- package/dist/react-native/Variants.d.ts.map +1 -1
- package/dist/react-native/Variants.js +2 -2
- package/dist/react-native/react.d.ts +1 -1
- package/dist/react-native/react.d.ts.map +1 -1
- package/dist/react-native/react.js +5 -5
- package/dist/react-native/react.js.map +1 -1
- package/dist/rollup/index.d.ts +3 -0
- package/dist/rollup/index.d.ts.map +1 -0
- package/dist/rollup/index.js +5 -0
- package/dist/rollup/index.js.map +1 -0
- package/dist/runtime/Appearance.d.ts +7 -7
- package/dist/runtime/Appearance.d.ts.map +1 -1
- package/dist/runtime/Appearance.js +15 -15
- package/dist/runtime/Appearance.js.map +1 -1
- package/dist/runtime/Dynamic.d.ts.map +1 -1
- package/dist/runtime/Dynamic.js +4 -1
- package/dist/runtime/Dynamic.js.map +1 -1
- package/dist/runtime/NativeContext.d.ts +4 -4
- package/dist/runtime/NativeContext.d.ts.map +1 -1
- package/dist/runtime/NativeContext.js +5 -5
- package/dist/runtime/NativeContext.js.map +1 -1
- package/dist/runtime/NativeDynamic.d.ts +1 -1
- package/dist/runtime/NativeDynamic.d.ts.map +1 -1
- package/dist/runtime/NativeDynamic.js.map +1 -1
- package/dist/runtime/Props.d.ts +1 -1
- package/dist/runtime/Props.js +3 -3
- package/dist/runtime/Props.js.map +1 -1
- package/dist/runtime/Selection.d.ts +14 -10
- package/dist/runtime/Selection.d.ts.map +1 -1
- package/dist/runtime/Selection.js +19 -18
- package/dist/runtime/Selection.js.map +1 -1
- package/dist/styleFunction.d.ts +14 -14
- package/dist/styleFunction.d.ts.map +1 -1
- package/dist/styleFunction.js.map +1 -1
- package/dist/unplugin/index.d.ts +20 -0
- package/dist/unplugin/index.d.ts.map +1 -0
- package/dist/unplugin/index.js +498 -0
- package/dist/unplugin/index.js.map +1 -0
- package/dist/variants.d.ts +3 -3
- package/dist/variants.d.ts.map +1 -1
- package/dist/variants.js.map +1 -1
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +6 -3
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts +4 -3
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +4 -4
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/Themes.d.ts +3 -2
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +42 -6
- package/dist/web/internal/Themes.js.map +1 -1
- package/dist/webpack/index.d.ts +3 -0
- package/dist/webpack/index.d.ts.map +1 -0
- package/dist/webpack/index.js +5 -0
- package/dist/webpack/index.js.map +1 -0
- package/package.json +23 -2
- package/src/Config.ts +43 -684
- package/src/Style.ts +167 -40
- package/src/Vars.ts +299 -0
- package/src/compiler/Graph.ts +14 -9
- package/src/compiler/Native.ts +29 -32
- package/src/compiler/Source.ts +85 -18
- package/src/compiler/Transform.ts +78 -22
- package/src/compiler/internal/Compositions.ts +36 -3
- package/src/compiler/internal/Configurations.ts +83 -11
- package/src/compiler/internal/Contract.ts +223 -17
- package/src/compiler/internal/Contributions.ts +1 -1
- package/src/compiler/internal/Dynamic.ts +1 -1
- package/src/compiler/internal/Expression.ts +26 -0
- package/src/compiler/internal/Identifiers.ts +2 -1
- package/src/compiler/internal/NativeBindings.ts +3 -3
- package/src/compiler/internal/PackedStyles.ts +22 -26
- package/src/compiler/internal/Recipes.ts +1 -1
- package/src/compiler/internal/Selectors.ts +1 -1
- package/src/compiler/internal/Themes.ts +266 -57
- package/src/compiler/internal/{Variables.ts → Vars.ts} +2 -2
- package/src/default.ts +868 -156
- package/src/esbuild/index.ts +5 -0
- package/src/index.ts +4 -4
- package/src/internal/Authoring.ts +5 -7
- package/src/internal/Binding.ts +1 -1
- package/src/internal/Completion.ts +42 -0
- package/src/internal/Condition.ts +31 -1
- package/src/internal/Configuration.ts +970 -0
- package/src/internal/Shorthands.ts +2 -0
- package/src/{Theme.ts → internal/Theme.ts} +174 -48
- package/src/internal/Token.ts +258 -85
- package/src/internal/Typography.ts +106 -0
- package/src/internal/Value.ts +45 -26
- package/src/internal/VariableSets.ts +458 -0
- package/src/next/loader.ts +19 -5
- package/src/node/Host.ts +1 -2
- package/src/react-native/Host.ts +6 -6
- package/src/react-native/StyleSheet.ts +49 -42
- package/src/react-native/Variants.ts +3 -3
- package/src/react-native/react.ts +6 -6
- package/src/rollup/index.ts +5 -0
- package/src/runtime/Appearance.ts +20 -20
- package/src/runtime/Dynamic.ts +4 -1
- package/src/runtime/NativeContext.ts +8 -8
- package/src/runtime/NativeDynamic.ts +2 -4
- package/src/runtime/Props.ts +3 -3
- package/src/runtime/Selection.ts +44 -33
- package/src/styleFunction.ts +22 -19
- package/src/unplugin/index.ts +600 -0
- package/src/variants.ts +7 -5
- package/src/vite/index.ts +5 -4
- package/src/web/Css.ts +10 -7
- package/src/web/internal/Themes.ts +52 -9
- package/src/webpack/index.ts +5 -0
- package/dist/Theme.d.ts.map +0 -1
- package/dist/Theme.js.map +0 -1
- package/dist/compiler/internal/Variables.d.ts.map +0 -1
- package/dist/compiler/internal/Variables.js.map +0 -1
|
@@ -0,0 +1,458 @@
|
|
|
1
|
+
/** Normalizes shared variable data into compiler-owned token contracts. @module */
|
|
2
|
+
import * as Query from './Query.js'
|
|
3
|
+
import * as Typography from './Typography.js'
|
|
4
|
+
import * as Condition from './Condition.js'
|
|
5
|
+
import * as Identity from './Identity.js'
|
|
6
|
+
import * as Literal from './Literal.js'
|
|
7
|
+
import * as Token from './Token.js'
|
|
8
|
+
import * as Theme from './Theme.js'
|
|
9
|
+
import * as Vars from '../Vars.js'
|
|
10
|
+
|
|
11
|
+
/** Wraps a variable set for the shared style/compiler contract. */
|
|
12
|
+
export function theme(
|
|
13
|
+
variables: Vars.Definition,
|
|
14
|
+
mappings?: Vars.Mappings | false,
|
|
15
|
+
): Theme.Definition {
|
|
16
|
+
const original = Theme.define({})
|
|
17
|
+
const metadata = variables[Token.definition]
|
|
18
|
+
if (!metadata?.contract.variableSet)
|
|
19
|
+
throw new Vars.InvalidError([], 'Expected a variable set.')
|
|
20
|
+
const contract = Object.freeze({
|
|
21
|
+
...metadata.contract,
|
|
22
|
+
...(mappings !== undefined ? { mappings } : {}),
|
|
23
|
+
})
|
|
24
|
+
const tokens = from({
|
|
25
|
+
...metadata,
|
|
26
|
+
contract,
|
|
27
|
+
values: rebind(metadata, contract),
|
|
28
|
+
})
|
|
29
|
+
const definition = Object.create(null)
|
|
30
|
+
Object.defineProperties(definition, {
|
|
31
|
+
...Object.getOwnPropertyDescriptors(original),
|
|
32
|
+
className: {
|
|
33
|
+
get: () => {
|
|
34
|
+
const identity = metadata.contract[Token.identity]
|
|
35
|
+
return identity
|
|
36
|
+
? `z_theme-${identity}-${Identity.hash(JSON.stringify(metadata.values))}`
|
|
37
|
+
: original.className
|
|
38
|
+
},
|
|
39
|
+
enumerable: true,
|
|
40
|
+
},
|
|
41
|
+
tokens: { value: tokens, enumerable: true },
|
|
42
|
+
vars: { value: tokens, enumerable: true },
|
|
43
|
+
[Token.definition]: { value: tokens[Token.definition] },
|
|
44
|
+
})
|
|
45
|
+
return Object.freeze(definition) as Theme.Definition
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** Rebuilds a reference tree from normalized compiler metadata. */
|
|
49
|
+
export function from(metadata: Token.Metadata): Vars.Definition {
|
|
50
|
+
return buildTree(
|
|
51
|
+
metadata.values,
|
|
52
|
+
metadata.contract,
|
|
53
|
+
metadata.queries,
|
|
54
|
+
metadata.paths,
|
|
55
|
+
) as Vars.Definition
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Validates and freezes a complete set or compatible partial override. */
|
|
59
|
+
export function build(
|
|
60
|
+
input: unknown,
|
|
61
|
+
contract: Token.Contract,
|
|
62
|
+
base?: Token.Metadata['values'],
|
|
63
|
+
baseQueries?: Query.Metadata,
|
|
64
|
+
basePaths?: Token.Metadata['paths'],
|
|
65
|
+
): Vars.Definition {
|
|
66
|
+
const values: Record<string, Token.Value> = Object.assign(
|
|
67
|
+
Object.create(null),
|
|
68
|
+
base,
|
|
69
|
+
)
|
|
70
|
+
const paths = { ...basePaths }
|
|
71
|
+
const conditions: string[][] = []
|
|
72
|
+
const active = new Set<object>()
|
|
73
|
+
function visit(input: unknown, path: string[]) {
|
|
74
|
+
if (
|
|
75
|
+
typeof input === 'string' ||
|
|
76
|
+
typeof input === 'number' ||
|
|
77
|
+
Token.is(input) ||
|
|
78
|
+
(path.length > 0 &&
|
|
79
|
+
input &&
|
|
80
|
+
typeof input === 'object' &&
|
|
81
|
+
('default' in input ||
|
|
82
|
+
('light' in input && 'dark' in input) ||
|
|
83
|
+
(Object.keys(input).length <= 2 &&
|
|
84
|
+
('light' in input || 'dark' in input))))
|
|
85
|
+
) {
|
|
86
|
+
if (!path.length)
|
|
87
|
+
throw new Vars.InvalidError(path, 'Expected a variable record.')
|
|
88
|
+
const value = read(input, path, queryData)
|
|
89
|
+
const name = path.join('.')
|
|
90
|
+
if (base && !Object.hasOwn(base, name))
|
|
91
|
+
throw new Vars.InvalidError(
|
|
92
|
+
path,
|
|
93
|
+
'Extensions cannot add variable paths.',
|
|
94
|
+
)
|
|
95
|
+
if (base && domain(base[name]!) !== domain(value))
|
|
96
|
+
throw new Vars.InvalidError(
|
|
97
|
+
path,
|
|
98
|
+
'Variable overrides must preserve their domain.',
|
|
99
|
+
)
|
|
100
|
+
if (path.some((part) => Typography.condition(part)))
|
|
101
|
+
paths[name] = Object.freeze([...path])
|
|
102
|
+
values[name] = value
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
const entries = record(input, path)
|
|
106
|
+
if (active.has(input as object))
|
|
107
|
+
throw new Vars.InvalidError(path, 'Cyclic variables are not supported.')
|
|
108
|
+
active.add(input as object)
|
|
109
|
+
if (!entries.length && !base)
|
|
110
|
+
throw new Vars.InvalidError(path, 'Variable records cannot be empty.')
|
|
111
|
+
for (const [key, value] of entries) {
|
|
112
|
+
const query = path[0] === 'typography' && Typography.condition(key)
|
|
113
|
+
if (query) conditions.push([...path, key])
|
|
114
|
+
if (!query && (!key || /[.!]/.test(key) || key.startsWith('@')))
|
|
115
|
+
throw new Vars.InvalidError(
|
|
116
|
+
[...path, key],
|
|
117
|
+
'Expected a nonempty variable key without dots or conditions.',
|
|
118
|
+
)
|
|
119
|
+
visit(value, [...path, key])
|
|
120
|
+
}
|
|
121
|
+
active.delete(input as object)
|
|
122
|
+
}
|
|
123
|
+
const fields = Object.fromEntries(record(input, []))
|
|
124
|
+
const queries = { ...baseQueries }
|
|
125
|
+
for (const key of ['breakpoints', 'containers', 'containerNames'] as const) {
|
|
126
|
+
if (Object.hasOwn(fields, key)) {
|
|
127
|
+
const value = fields[key]
|
|
128
|
+
if (base) {
|
|
129
|
+
if (key === 'containerNames') {
|
|
130
|
+
if (
|
|
131
|
+
JSON.stringify(value) !==
|
|
132
|
+
JSON.stringify(baseQueries?.containerNames ?? [])
|
|
133
|
+
)
|
|
134
|
+
throw new Vars.InvalidError(
|
|
135
|
+
[key],
|
|
136
|
+
'Extensions cannot change container identities.',
|
|
137
|
+
)
|
|
138
|
+
} else {
|
|
139
|
+
for (const [name] of record(value, [key]))
|
|
140
|
+
if (!Object.hasOwn(baseQueries?.[key] ?? {}, name))
|
|
141
|
+
throw new Vars.InvalidError(
|
|
142
|
+
[key, name],
|
|
143
|
+
'Extensions cannot add query thresholds.',
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
Object.assign(queries, {
|
|
148
|
+
[key]:
|
|
149
|
+
key === 'containerNames'
|
|
150
|
+
? value
|
|
151
|
+
: { ...baseQueries?.[key], ...value },
|
|
152
|
+
})
|
|
153
|
+
delete fields[key]
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const queryData = Theme.define(queries as Theme.Tokens)[Token.definition]
|
|
157
|
+
.queries
|
|
158
|
+
if (Object.keys(fields).length) visit(fields, [])
|
|
159
|
+
for (const path of conditions) {
|
|
160
|
+
try {
|
|
161
|
+
Condition.normalize(
|
|
162
|
+
Query.resolve(
|
|
163
|
+
path.at(-1)!,
|
|
164
|
+
queryData ?? { breakpoints: {}, containers: {}, containerNames: [] },
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
} catch (error) {
|
|
168
|
+
throw new Vars.InvalidError(path, (error as Error).message)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return buildTree(
|
|
172
|
+
Object.freeze(values),
|
|
173
|
+
contract,
|
|
174
|
+
queryData,
|
|
175
|
+
Object.keys(paths).length ? Object.freeze(paths) : undefined,
|
|
176
|
+
) as Vars.Definition
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function buildTree(
|
|
180
|
+
values: Token.Metadata['values'],
|
|
181
|
+
contract: Token.Contract,
|
|
182
|
+
queries?: Query.Metadata,
|
|
183
|
+
paths?: Token.Metadata['paths'],
|
|
184
|
+
) {
|
|
185
|
+
values = rebind({ contract, values }, contract)
|
|
186
|
+
|
|
187
|
+
type Tree = { [key: string]: Tree | Token.Reference }
|
|
188
|
+
const tree: Tree = Object.create(null)
|
|
189
|
+
for (const [path, value] of Object.entries(values)) {
|
|
190
|
+
const parts = paths?.[path] ?? path.split('.')
|
|
191
|
+
let target = tree
|
|
192
|
+
for (const key of parts.slice(0, -1))
|
|
193
|
+
target = (target[key] ??= Object.create(null)) as Tree
|
|
194
|
+
target[parts.at(-1)!] = Token.create({
|
|
195
|
+
contract,
|
|
196
|
+
group: domain(value),
|
|
197
|
+
path,
|
|
198
|
+
value,
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
function freeze(tree: Tree) {
|
|
202
|
+
for (const value of Object.values(tree)) if (!Token.is(value)) freeze(value)
|
|
203
|
+
Object.freeze(tree)
|
|
204
|
+
}
|
|
205
|
+
Object.defineProperty(tree, Token.definition, {
|
|
206
|
+
value: Object.freeze({
|
|
207
|
+
contract,
|
|
208
|
+
values,
|
|
209
|
+
queries,
|
|
210
|
+
...(paths ? { paths } : {}),
|
|
211
|
+
}),
|
|
212
|
+
})
|
|
213
|
+
freeze(tree)
|
|
214
|
+
return tree
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function record(input: unknown, path: string[]) {
|
|
218
|
+
if (
|
|
219
|
+
!input ||
|
|
220
|
+
typeof input !== 'object' ||
|
|
221
|
+
![null, Object.prototype].includes(Object.getPrototypeOf(input))
|
|
222
|
+
)
|
|
223
|
+
throw new Vars.InvalidError(path, 'Expected a plain variable record.')
|
|
224
|
+
return Reflect.ownKeys(input).map((key) => {
|
|
225
|
+
const descriptor = Object.getOwnPropertyDescriptor(input, key)!
|
|
226
|
+
if (
|
|
227
|
+
typeof key !== 'string' ||
|
|
228
|
+
!descriptor.enumerable ||
|
|
229
|
+
!('value' in descriptor)
|
|
230
|
+
)
|
|
231
|
+
throw new Vars.InvalidError(
|
|
232
|
+
path,
|
|
233
|
+
'Vars require enumerable data properties.',
|
|
234
|
+
)
|
|
235
|
+
return [key, descriptor.value] as const
|
|
236
|
+
})
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function read(
|
|
240
|
+
input: unknown,
|
|
241
|
+
path: string[],
|
|
242
|
+
queries: Query.Metadata | undefined,
|
|
243
|
+
active = new Set<object>(),
|
|
244
|
+
): Token.Value {
|
|
245
|
+
if (Token.is(input)) return input
|
|
246
|
+
if (typeof input === 'number' && Number.isFinite(input)) return input
|
|
247
|
+
if (typeof input === 'string' && input.trim() && !/[;{}]/.test(input))
|
|
248
|
+
return input
|
|
249
|
+
if (active.has(input as object))
|
|
250
|
+
throw new Vars.InvalidError(path, 'Cyclic variables are not supported.')
|
|
251
|
+
const next = new Set(active).add(input as object)
|
|
252
|
+
const entries = record(input, path)
|
|
253
|
+
const fields = Object.fromEntries(entries)
|
|
254
|
+
if (Object.hasOwn(fields, 'default')) {
|
|
255
|
+
for (const [key] of entries)
|
|
256
|
+
if (key !== 'default' && (!/^@media\s+\S/.test(key) || /[;{}]/.test(key)))
|
|
257
|
+
throw new Vars.InvalidError(
|
|
258
|
+
[...path, key],
|
|
259
|
+
'Expected an @media condition.',
|
|
260
|
+
)
|
|
261
|
+
const result = Object.fromEntries(
|
|
262
|
+
entries.map(([key, value]) => {
|
|
263
|
+
let condition = key
|
|
264
|
+
try {
|
|
265
|
+
if (key !== 'default')
|
|
266
|
+
condition = Condition.normalize(
|
|
267
|
+
Query.resolve(
|
|
268
|
+
key,
|
|
269
|
+
queries ?? {
|
|
270
|
+
breakpoints: {},
|
|
271
|
+
containers: {},
|
|
272
|
+
containerNames: [],
|
|
273
|
+
},
|
|
274
|
+
),
|
|
275
|
+
)
|
|
276
|
+
} catch (error) {
|
|
277
|
+
throw new Vars.InvalidError([...path, key], (error as Error).message)
|
|
278
|
+
}
|
|
279
|
+
return [condition, read(value, [...path, key], queries, next)]
|
|
280
|
+
}),
|
|
281
|
+
) as Token.Conditions
|
|
282
|
+
const expected = domain(result.default)
|
|
283
|
+
if (Object.values(result).some((value) => domain(value) !== expected))
|
|
284
|
+
throw new Vars.InvalidError(
|
|
285
|
+
path,
|
|
286
|
+
'Conditional values must share one domain.',
|
|
287
|
+
)
|
|
288
|
+
return Object.freeze(result)
|
|
289
|
+
}
|
|
290
|
+
if (
|
|
291
|
+
entries.length === 2 &&
|
|
292
|
+
Object.hasOwn(fields, 'light') &&
|
|
293
|
+
Object.hasOwn(fields, 'dark')
|
|
294
|
+
) {
|
|
295
|
+
const light = read(fields.light, [...path, 'light'], queries, next)
|
|
296
|
+
const dark = read(fields.dark, [...path, 'dark'], queries, next)
|
|
297
|
+
if (domain(light) !== 'color' || domain(dark) !== 'color')
|
|
298
|
+
throw new Vars.InvalidError(path, 'Color schemes require colors.')
|
|
299
|
+
return Object.freeze({ light, dark })
|
|
300
|
+
}
|
|
301
|
+
throw new Vars.InvalidError(
|
|
302
|
+
path,
|
|
303
|
+
'Expected a scalar, a complete color pair, or media overrides with a default.',
|
|
304
|
+
)
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/** Infers the shared declaration domain after following defaults and references. */
|
|
308
|
+
export function domain(value: Token.Value): Token.Group {
|
|
309
|
+
if (Token.is(value)) return value.group
|
|
310
|
+
if (typeof value === 'object')
|
|
311
|
+
return 'default' in value ? domain(value.default) : 'color'
|
|
312
|
+
if (
|
|
313
|
+
typeof value === 'string' &&
|
|
314
|
+
(/^(?:#|(?:color|color-mix|contrast-color|light-dark|rgb|rgba|hsl|hsla|hwb|lab|lch|oklab|oklch)\()/i.test(
|
|
315
|
+
value,
|
|
316
|
+
) ||
|
|
317
|
+
(!/[0-9()#]/.test(value) && Literal.isLiteral('color', value)))
|
|
318
|
+
)
|
|
319
|
+
return 'color'
|
|
320
|
+
if (
|
|
321
|
+
value === 0 ||
|
|
322
|
+
value === '0' ||
|
|
323
|
+
(typeof value === 'string' &&
|
|
324
|
+
new RegExp(
|
|
325
|
+
`^[+-]?(?:[0-9]*\\.[0-9]+|[0-9]+)(?:${Literal.lengthUnits.join('|')})$`,
|
|
326
|
+
'i',
|
|
327
|
+
).test(value))
|
|
328
|
+
)
|
|
329
|
+
return 'spacing'
|
|
330
|
+
return typeof value === 'number' ? 'number' : 'string'
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
/** Copies and validates category mappings without retaining mutable caller input. */
|
|
334
|
+
export function mappings(input: unknown): Vars.Mappings | false | undefined {
|
|
335
|
+
if (input === undefined || input === false) return input
|
|
336
|
+
return Object.freeze(
|
|
337
|
+
Object.fromEntries(
|
|
338
|
+
record(input, ['mappings']).map(([category, value]) => {
|
|
339
|
+
if (
|
|
340
|
+
!category ||
|
|
341
|
+
!Array.isArray(value) ||
|
|
342
|
+
value.some(
|
|
343
|
+
(property) =>
|
|
344
|
+
typeof property !== 'string' ||
|
|
345
|
+
!Object.hasOwn(Literal.rules, property),
|
|
346
|
+
)
|
|
347
|
+
)
|
|
348
|
+
throw new Vars.InvalidError(
|
|
349
|
+
['mappings', category],
|
|
350
|
+
'Expected an array of CSS property names.',
|
|
351
|
+
)
|
|
352
|
+
if (new Set(value).size !== value.length)
|
|
353
|
+
throw new Vars.InvalidError(
|
|
354
|
+
['mappings', category],
|
|
355
|
+
'Property mappings cannot contain duplicates.',
|
|
356
|
+
)
|
|
357
|
+
return [category, Object.freeze([...value])]
|
|
358
|
+
}),
|
|
359
|
+
),
|
|
360
|
+
)
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/** Combines disjoint variable leaves without mutating either authored record. */
|
|
364
|
+
export function merge(
|
|
365
|
+
base: unknown,
|
|
366
|
+
derived: unknown,
|
|
367
|
+
path: string[] = [],
|
|
368
|
+
): Vars.Values {
|
|
369
|
+
const result: Record<string, unknown> = Object.assign(
|
|
370
|
+
Object.create(null),
|
|
371
|
+
Object.fromEntries(record(base, path)),
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
for (const [key, value] of record(derived, path)) {
|
|
375
|
+
const next = [...path, key]
|
|
376
|
+
if (Object.hasOwn(result, key)) {
|
|
377
|
+
for (const entry of [result[key], value])
|
|
378
|
+
if (
|
|
379
|
+
!entry ||
|
|
380
|
+
typeof entry !== 'object' ||
|
|
381
|
+
Array.isArray(entry) ||
|
|
382
|
+
Token.is(entry) ||
|
|
383
|
+
'default' in entry ||
|
|
384
|
+
('light' in entry && 'dark' in entry) ||
|
|
385
|
+
(Object.keys(entry).length <= 2 &&
|
|
386
|
+
('light' in entry || 'dark' in entry))
|
|
387
|
+
)
|
|
388
|
+
throw new Vars.InvalidError(
|
|
389
|
+
next,
|
|
390
|
+
'Derived variables cannot replace existing paths.',
|
|
391
|
+
)
|
|
392
|
+
|
|
393
|
+
result[key] = merge(result[key], value, next)
|
|
394
|
+
} else result[key] = value
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return result as Vars.Values
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/** Updates references within a set while retaining references to independent sets. */
|
|
401
|
+
export function rebind(
|
|
402
|
+
metadata: Token.Metadata,
|
|
403
|
+
contract: Token.Contract,
|
|
404
|
+
): Token.Metadata['values'] {
|
|
405
|
+
const active = new Set<string>()
|
|
406
|
+
const values: Record<string, Token.Value> = Object.create(null)
|
|
407
|
+
|
|
408
|
+
function resolve(value: Token.Value): Token.Value {
|
|
409
|
+
if (Token.is(value)) {
|
|
410
|
+
if (
|
|
411
|
+
value.contract !== metadata.contract &&
|
|
412
|
+
(metadata.contract[Token.identity] === undefined ||
|
|
413
|
+
value.contract[Token.identity] !== metadata.contract[Token.identity])
|
|
414
|
+
)
|
|
415
|
+
return value
|
|
416
|
+
|
|
417
|
+
return Token.create({
|
|
418
|
+
contract,
|
|
419
|
+
group: value.group,
|
|
420
|
+
path: value.path,
|
|
421
|
+
value: visit(value.path),
|
|
422
|
+
})
|
|
423
|
+
}
|
|
424
|
+
if (typeof value !== 'object') return value
|
|
425
|
+
|
|
426
|
+
return Object.freeze(
|
|
427
|
+
Object.fromEntries(
|
|
428
|
+
Object.entries(value).map(([key, entry]) => [key, resolve(entry)]),
|
|
429
|
+
),
|
|
430
|
+
) as Token.Value
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
function visit(path: string): Token.Value {
|
|
434
|
+
if (Object.hasOwn(values, path)) return values[path]!
|
|
435
|
+
if (active.has(path))
|
|
436
|
+
throw new Vars.InvalidError(
|
|
437
|
+
path.split('.'),
|
|
438
|
+
'Cyclic variables are not supported.',
|
|
439
|
+
)
|
|
440
|
+
if (!Object.hasOwn(metadata.values, path))
|
|
441
|
+
throw new Vars.InvalidError(
|
|
442
|
+
path.split('.'),
|
|
443
|
+
'Referenced variable path is missing.',
|
|
444
|
+
)
|
|
445
|
+
|
|
446
|
+
active.add(path)
|
|
447
|
+
values[path] = resolve(metadata.values[path]!)
|
|
448
|
+
active.delete(path)
|
|
449
|
+
return values[path]!
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
for (const path of Object.keys(metadata.values)) visit(path)
|
|
453
|
+
return Object.freeze(
|
|
454
|
+
Object.fromEntries(
|
|
455
|
+
Object.keys(metadata.values).map((path) => [path, values[path]!]),
|
|
456
|
+
),
|
|
457
|
+
)
|
|
458
|
+
}
|
package/src/next/loader.ts
CHANGED
|
@@ -90,10 +90,11 @@ async function compile(context: Context, source: string) {
|
|
|
90
90
|
|
|
91
91
|
const specifier = node.source.value
|
|
92
92
|
links[specifier] = null
|
|
93
|
+
// Next owns this virtual module, which has no physical stylesheet contract.
|
|
94
|
+
if (specifier === 'next/root-params') continue
|
|
93
95
|
if (
|
|
94
96
|
specifier === 'zyzz' ||
|
|
95
|
-
(specifier.startsWith('zyzz/') &&
|
|
96
|
-
specifier !== 'zyzz/default') ||
|
|
97
|
+
(specifier.startsWith('zyzz/') && specifier !== 'zyzz/default') ||
|
|
97
98
|
specifier.startsWith('node:')
|
|
98
99
|
)
|
|
99
100
|
continue
|
|
@@ -288,15 +289,28 @@ async function compile(context: Context, source: string) {
|
|
|
288
289
|
)
|
|
289
290
|
.split(Path.sep)
|
|
290
291
|
.join('/')
|
|
292
|
+
// Turbopack appends the output extension to loader-transformed resource paths.
|
|
293
|
+
const resource = await Fs.stat(context.resourcePath).then(
|
|
294
|
+
() => context.resourcePath,
|
|
295
|
+
async (error: NodeJS.ErrnoException) => {
|
|
296
|
+
if (error.code !== 'ENOENT') throw error
|
|
297
|
+
const original = context.resourcePath.slice(
|
|
298
|
+
0,
|
|
299
|
+
-Path.extname(context.resourcePath).length,
|
|
300
|
+
)
|
|
301
|
+
await Fs.access(original)
|
|
302
|
+
return original
|
|
303
|
+
},
|
|
304
|
+
)
|
|
291
305
|
const requests = [
|
|
292
306
|
...(graph.sharedCss
|
|
293
307
|
? [
|
|
294
|
-
`import ${JSON.stringify(sharedFile.startsWith('
|
|
308
|
+
`import ${JSON.stringify(sharedFile.startsWith('../') ? sharedFile : `./${sharedFile}`)};`,
|
|
295
309
|
]
|
|
296
310
|
: []),
|
|
297
311
|
...(output.css
|
|
298
312
|
? [
|
|
299
|
-
`import ${JSON.stringify(`./${Path.basename(
|
|
313
|
+
`import ${JSON.stringify(`./${Path.basename(resource)}?zyzz-style`)};`,
|
|
300
314
|
]
|
|
301
315
|
: []),
|
|
302
316
|
]
|
|
@@ -326,7 +340,7 @@ async function compile(context: Context, source: string) {
|
|
|
326
340
|
.split(Path.sep)
|
|
327
341
|
.join('/')
|
|
328
342
|
requests.push(
|
|
329
|
-
`import ${JSON.stringify(relative.startsWith('
|
|
343
|
+
`import ${JSON.stringify(relative.startsWith('../') ? relative : `./${relative}`)};`,
|
|
330
344
|
)
|
|
331
345
|
}
|
|
332
346
|
|
package/src/node/Host.ts
CHANGED
|
@@ -54,8 +54,7 @@ export async function create(options: create.Options): Promise<Runtime> {
|
|
|
54
54
|
fonts:
|
|
55
55
|
options.native.fonts && Object.freeze({ ...options.native.fonts }),
|
|
56
56
|
// Theme definitions are immutable. Only the caller-owned catalog needs copying.
|
|
57
|
-
|
|
58
|
-
options.native.themes && Object.freeze({ ...options.native.themes }),
|
|
57
|
+
vars: options.native.vars && Object.freeze({ ...options.native.vars }),
|
|
59
58
|
units:
|
|
60
59
|
options.native.units && Object.freeze({ ...options.native.units }),
|
|
61
60
|
})
|
package/src/react-native/Host.ts
CHANGED
|
@@ -28,7 +28,7 @@ export function create<
|
|
|
28
28
|
'highContrast',
|
|
29
29
|
'reducedMotion',
|
|
30
30
|
'rtl',
|
|
31
|
-
'
|
|
31
|
+
'set',
|
|
32
32
|
] as const
|
|
33
33
|
const bindings = new Set<(context: Snapshot) => () => void>()
|
|
34
34
|
const listeners = new Set<(context: Snapshot) => void>()
|
|
@@ -45,8 +45,8 @@ export function create<
|
|
|
45
45
|
(key) => !keys.includes(key as (typeof keys)[number]),
|
|
46
46
|
) ||
|
|
47
47
|
(values.colorScheme !== 'light' && values.colorScheme !== 'dark') ||
|
|
48
|
-
typeof values.
|
|
49
|
-
!values.
|
|
48
|
+
typeof values.set !== 'string' ||
|
|
49
|
+
!values.set.trim() ||
|
|
50
50
|
typeof values.density !== 'number' ||
|
|
51
51
|
!Number.isFinite(values.density) ||
|
|
52
52
|
values.density <= 0 ||
|
|
@@ -58,7 +58,7 @@ export function create<
|
|
|
58
58
|
typeof values.rtl !== 'boolean'
|
|
59
59
|
)
|
|
60
60
|
throw new InputError(
|
|
61
|
-
'Provide a
|
|
61
|
+
'Provide a set, resolved scheme, positive finite scales, and boolean accessibility inputs.',
|
|
62
62
|
)
|
|
63
63
|
const hairlineWidth =
|
|
64
64
|
Math.round(0.4 * values.density) / values.density || 1 / values.density
|
|
@@ -265,8 +265,8 @@ export type Inputs = {
|
|
|
265
265
|
readonly reducedMotion: boolean
|
|
266
266
|
/** Whether layout follows a right-to-left direction. */
|
|
267
267
|
readonly rtl: boolean
|
|
268
|
-
/** Compiled
|
|
269
|
-
readonly
|
|
268
|
+
/** Compiled set label selected by binding factories. */
|
|
269
|
+
readonly set: string
|
|
270
270
|
}
|
|
271
271
|
|
|
272
272
|
/** An operation attempted to change a disposed or currently updating host. */
|