zyzz 0.0.20 → 0.0.22
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/Zyzz.podspec +16 -0
- package/dist/Style.d.ts +10 -1
- package/dist/Style.d.ts.map +1 -1
- package/dist/Style.js +1 -5
- package/dist/Style.js.map +1 -1
- package/dist/babel/NativeJsx.d.ts.map +1 -1
- package/dist/babel/NativeJsx.js +204 -12
- package/dist/babel/NativeJsx.js.map +1 -1
- package/dist/babel/index.d.ts +6 -2
- package/dist/babel/index.d.ts.map +1 -1
- package/dist/babel/index.js +10 -1
- package/dist/babel/index.js.map +1 -1
- package/dist/compiler/Graph.d.ts +3 -0
- package/dist/compiler/Graph.d.ts.map +1 -1
- package/dist/compiler/Graph.js +108 -37
- package/dist/compiler/Graph.js.map +1 -1
- package/dist/compiler/Native.d.ts +6 -3
- package/dist/compiler/Native.d.ts.map +1 -1
- package/dist/compiler/Native.js +142 -24
- package/dist/compiler/Native.js.map +1 -1
- package/dist/compiler/Source.d.ts +6 -0
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +80 -11
- package/dist/compiler/Source.js.map +1 -1
- package/dist/compiler/Transform.d.ts +4 -1
- package/dist/compiler/Transform.d.ts.map +1 -1
- package/dist/compiler/Transform.js +32 -46
- package/dist/compiler/Transform.js.map +1 -1
- package/dist/compiler/internal/Catalogs.d.ts.map +1 -1
- package/dist/compiler/internal/Catalogs.js +6 -1
- package/dist/compiler/internal/Catalogs.js.map +1 -1
- package/dist/compiler/internal/Compositions.d.ts.map +1 -1
- package/dist/compiler/internal/Compositions.js +5 -0
- package/dist/compiler/internal/Compositions.js.map +1 -1
- package/dist/compiler/internal/Configurations.d.ts +2 -0
- package/dist/compiler/internal/Configurations.d.ts.map +1 -1
- package/dist/compiler/internal/Configurations.js +23 -4
- package/dist/compiler/internal/Configurations.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts +4 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +97 -151
- package/dist/compiler/internal/Contract.js.map +1 -1
- package/dist/compiler/internal/Contributions.d.ts.map +1 -1
- package/dist/compiler/internal/Contributions.js +8 -4
- package/dist/compiler/internal/Contributions.js.map +1 -1
- package/dist/compiler/internal/Descriptors.d.ts.map +1 -1
- package/dist/compiler/internal/Descriptors.js +11 -2
- package/dist/compiler/internal/Descriptors.js.map +1 -1
- package/dist/compiler/internal/Dynamic.d.ts +1 -1
- package/dist/compiler/internal/Dynamic.d.ts.map +1 -1
- package/dist/compiler/internal/Dynamic.js +5 -5
- package/dist/compiler/internal/Dynamic.js.map +1 -1
- package/dist/compiler/internal/Names.d.ts +5 -0
- package/dist/compiler/internal/Names.d.ts.map +1 -0
- package/dist/compiler/internal/Names.js +37 -0
- package/dist/compiler/internal/Names.js.map +1 -0
- package/dist/compiler/internal/NativeBindings.d.ts +24 -26
- package/dist/compiler/internal/NativeBindings.d.ts.map +1 -1
- package/dist/compiler/internal/NativeBindings.js +61 -8
- package/dist/compiler/internal/NativeBindings.js.map +1 -1
- package/dist/compiler/internal/NativeMedia.d.ts +14 -0
- package/dist/compiler/internal/NativeMedia.d.ts.map +1 -0
- package/dist/compiler/internal/NativeMedia.js +287 -0
- package/dist/compiler/internal/NativeMedia.js.map +1 -0
- package/dist/compiler/internal/NativeVars.d.ts +28 -0
- package/dist/compiler/internal/NativeVars.d.ts.map +1 -0
- package/dist/compiler/internal/NativeVars.js +157 -0
- package/dist/compiler/internal/NativeVars.js.map +1 -0
- package/dist/compiler/internal/PackedStyles.d.ts +2 -0
- package/dist/compiler/internal/PackedStyles.d.ts.map +1 -1
- package/dist/compiler/internal/PackedStyles.js +2 -0
- package/dist/compiler/internal/PackedStyles.js.map +1 -1
- package/dist/compiler/internal/Selectors.d.ts +1 -1
- package/dist/compiler/internal/Selectors.d.ts.map +1 -1
- package/dist/compiler/internal/Selectors.js +5 -2
- package/dist/compiler/internal/Selectors.js.map +1 -1
- package/dist/compiler/internal/Stylesheets.js +2 -2
- package/dist/compiler/internal/Stylesheets.js.map +1 -1
- package/dist/compiler/internal/Themes.d.ts +22 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +120 -4
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/compiler/internal/Vars.d.ts +3 -1
- package/dist/compiler/internal/Vars.d.ts.map +1 -1
- package/dist/compiler/internal/Vars.js +14 -3
- package/dist/compiler/internal/Vars.js.map +1 -1
- package/dist/default.d.ts +4 -4
- package/dist/default.d.ts.map +1 -1
- package/dist/default.js +9 -9
- package/dist/default.js.map +2 -2
- package/dist/default.js.zyzz.json +1 -1
- package/dist/internal/Authoring.d.ts.map +1 -1
- package/dist/internal/Authoring.js +8 -3
- package/dist/internal/Authoring.js.map +1 -1
- package/dist/internal/Binding.d.ts +4 -0
- package/dist/internal/Binding.d.ts.map +1 -1
- package/dist/internal/Binding.js +2 -0
- package/dist/internal/Binding.js.map +1 -1
- package/dist/internal/Completion.d.ts +1 -1
- package/dist/internal/Completion.d.ts.map +1 -1
- package/dist/internal/Configuration.d.ts +2 -2
- package/dist/internal/Configuration.d.ts.map +1 -1
- package/dist/internal/Configuration.js +4 -2
- package/dist/internal/Configuration.js.map +1 -1
- package/dist/internal/Identity.d.ts +3 -3
- package/dist/internal/Identity.d.ts.map +1 -1
- package/dist/internal/Identity.js +11 -9
- package/dist/internal/Identity.js.map +1 -1
- package/dist/internal/Targets.d.ts.map +1 -1
- package/dist/internal/Targets.js +2 -0
- package/dist/internal/Targets.js.map +1 -1
- package/dist/internal/Theme.js +2 -2
- package/dist/internal/Theme.js.map +1 -1
- package/dist/internal/Token.d.ts +3 -1
- package/dist/internal/Token.d.ts.map +1 -1
- package/dist/internal/Token.js +9 -2
- package/dist/internal/Token.js.map +1 -1
- package/dist/internal/Value.d.ts +7 -0
- package/dist/internal/Value.d.ts.map +1 -1
- package/dist/internal/Value.js.map +1 -1
- package/dist/internal/VariableSets.js +1 -1
- package/dist/internal/VariableSets.js.map +1 -1
- package/dist/metro/Graph.d.ts +22 -7
- package/dist/metro/Graph.d.ts.map +1 -1
- package/dist/metro/Graph.js +179 -42
- package/dist/metro/Graph.js.map +1 -1
- package/dist/metro/Watch.d.ts +28 -4
- package/dist/metro/Watch.d.ts.map +1 -1
- package/dist/metro/Watch.js +39 -7
- package/dist/metro/Watch.js.map +1 -1
- package/dist/metro/index.d.ts +15 -4
- package/dist/metro/index.d.ts.map +1 -1
- package/dist/metro/index.js +27 -0
- package/dist/metro/index.js.map +1 -1
- package/dist/metro/transformer.d.ts +5 -1
- package/dist/metro/transformer.d.ts.map +1 -1
- package/dist/metro/transformer.js +5 -3
- package/dist/metro/transformer.js.map +1 -1
- package/dist/node/Host.d.ts.map +1 -1
- package/dist/node/Host.js +2 -0
- package/dist/node/Host.js.map +1 -1
- package/dist/react-native/StyleSheet.d.ts +3 -2
- package/dist/react-native/StyleSheet.d.ts.map +1 -1
- package/dist/react-native/StyleSheet.js +17 -34
- package/dist/react-native/StyleSheet.js.map +1 -1
- package/dist/react-native/index.d.ts +1 -1
- package/dist/react-native/index.d.ts.map +1 -1
- package/dist/react-native/index.js +1 -1
- package/dist/react-native/index.js.map +1 -1
- package/dist/react-native/index.native.d.ts +5 -0
- package/dist/react-native/index.native.js +20 -0
- package/dist/react-native/index.native.js.map +7 -0
- package/dist/react-native/internal/Calculation.d.ts +7 -0
- package/dist/react-native/internal/Calculation.d.ts.map +1 -0
- package/dist/react-native/internal/Calculation.js +134 -0
- package/dist/react-native/internal/Calculation.js.map +1 -0
- package/dist/react-native/internal/Device.js +191 -0
- package/dist/react-native/internal/Device.js.map +7 -0
- package/dist/react-native/internal/NativeZyzz.js +7 -0
- package/dist/react-native/internal/NativeZyzz.js.map +7 -0
- package/dist/react-native/internal/Scalar.d.ts.map +1 -1
- package/dist/react-native/internal/Scalar.js +9 -2
- package/dist/react-native/internal/Scalar.js.map +1 -1
- package/dist/react-native/internal/Store.d.ts +32 -0
- package/dist/react-native/internal/Store.d.ts.map +1 -0
- package/dist/react-native/internal/Store.js +57 -0
- package/dist/react-native/internal/Store.js.map +1 -0
- package/dist/react-native/internal/Tokens.d.ts +21 -0
- package/dist/react-native/internal/Tokens.d.ts.map +1 -0
- package/dist/react-native/internal/Tokens.js +58 -0
- package/dist/react-native/internal/Tokens.js.map +1 -0
- package/dist/react-native/internal/Viewport.d.ts +6 -0
- package/dist/react-native/internal/Viewport.d.ts.map +1 -0
- package/dist/react-native/internal/Viewport.js +4 -0
- package/dist/react-native/internal/Viewport.js.map +1 -0
- package/dist/react-native/react.d.ts +74 -11
- package/dist/react-native/react.d.ts.map +1 -1
- package/dist/react-native/react.js +111 -12
- package/dist/react-native/react.js.map +1 -1
- package/dist/react-native/reanimated.d.ts +39 -0
- package/dist/react-native/reanimated.d.ts.map +1 -0
- package/dist/react-native/reanimated.js +76 -0
- package/dist/react-native/reanimated.js.map +1 -0
- package/dist/runtime/NativeContext.d.ts +10 -1
- package/dist/runtime/NativeContext.d.ts.map +1 -1
- package/dist/runtime/NativeContext.js +67 -14
- package/dist/runtime/NativeContext.js.map +1 -1
- package/dist/runtime/NativeDynamic.d.ts +3 -2
- package/dist/runtime/NativeDynamic.d.ts.map +1 -1
- package/dist/runtime/NativeDynamic.js +32 -7
- package/dist/runtime/NativeDynamic.js.map +1 -1
- package/dist/runtime/NativeStatic.d.ts +23 -0
- package/dist/runtime/NativeStatic.d.ts.map +1 -0
- package/dist/runtime/NativeStatic.js +106 -0
- package/dist/runtime/NativeStatic.js.map +1 -0
- package/dist/runtime/NativeVars.d.ts +53 -0
- package/dist/runtime/NativeVars.d.ts.map +1 -0
- package/dist/runtime/NativeVars.js +77 -0
- package/dist/runtime/NativeVars.js.map +1 -0
- package/dist/runtime/index.d.ts +4 -0
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +4 -0
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/internal/NativeMedia.d.ts +25 -0
- package/dist/runtime/internal/NativeMedia.d.ts.map +1 -0
- package/dist/runtime/internal/NativeMedia.js +36 -0
- package/dist/runtime/internal/NativeMedia.js.map +1 -0
- package/dist/variable.js +1 -1
- package/dist/variable.js.map +1 -1
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +43 -47
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts +7 -2
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +76 -57
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/ClassName.d.ts +13 -2
- package/dist/web/internal/ClassName.d.ts.map +1 -1
- package/dist/web/internal/ClassName.js +17 -30
- package/dist/web/internal/ClassName.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 +54 -28
- package/dist/web/internal/Themes.js.map +1 -1
- package/dist/web/page.d.ts +2 -0
- package/dist/web/page.d.ts.map +1 -1
- package/native/NativeZyzz.cpp +215 -0
- package/native/NativeZyzz.h +52 -0
- package/native/ZyzzSpecJSI.h +65 -0
- package/native/android/CMakeLists.txt +8 -0
- package/native/android/ZyzzSpec-generated.cpp +50 -0
- package/native/android/ZyzzSpec.h +31 -0
- package/native/ios/ZyzzModuleProvider.mm +13 -0
- package/package.json +39 -1
- package/react-native.config.ts +14 -0
- package/src/Style.ts +15 -9
- package/src/babel/NativeJsx.ts +305 -28
- package/src/babel/index.ts +21 -3
- package/src/compiler/Graph.ts +135 -46
- package/src/compiler/Native.ts +158 -26
- package/src/compiler/Source.ts +115 -10
- package/src/compiler/Transform.ts +42 -60
- package/src/compiler/internal/Catalogs.ts +9 -1
- package/src/compiler/internal/Compositions.ts +7 -0
- package/src/compiler/internal/Configurations.ts +27 -4
- package/src/compiler/internal/Contract.ts +130 -260
- package/src/compiler/internal/Contributions.ts +8 -6
- package/src/compiler/internal/Descriptors.ts +12 -8
- package/src/compiler/internal/Dynamic.ts +14 -9
- package/src/compiler/internal/Names.ts +48 -0
- package/src/compiler/internal/NativeBindings.ts +98 -15
- package/src/compiler/internal/NativeMedia.ts +342 -0
- package/src/compiler/internal/NativeVars.ts +228 -0
- package/src/compiler/internal/PackedStyles.ts +4 -0
- package/src/compiler/internal/Selectors.ts +6 -1
- package/src/compiler/internal/Stylesheets.ts +2 -2
- package/src/compiler/internal/Themes.ts +193 -3
- package/src/compiler/internal/Vars.ts +21 -2
- package/src/default.ts +9 -10
- package/src/internal/Authoring.ts +8 -2
- package/src/internal/Binding.ts +5 -0
- package/src/internal/Completion.ts +6 -3
- package/src/internal/Configuration.ts +7 -4
- package/src/internal/Identity.ts +14 -12
- package/src/internal/Targets.ts +2 -0
- package/src/internal/Theme.ts +2 -2
- package/src/internal/Token.ts +11 -1
- package/src/internal/Value.ts +20 -0
- package/src/internal/VariableSets.ts +1 -1
- package/src/metro/Graph.ts +235 -50
- package/src/metro/Watch.ts +95 -10
- package/src/metro/index.ts +62 -4
- package/src/metro/transformer.ts +21 -11
- package/src/node/Host.ts +3 -0
- package/src/react-native/StyleSheet.ts +28 -44
- package/src/react-native/index.native.ts +10 -0
- package/src/react-native/index.ts +1 -1
- package/src/react-native/internal/Calculation.ts +159 -0
- package/src/react-native/internal/Device.ts +231 -0
- package/src/react-native/internal/NativeZyzz.ts +20 -0
- package/src/react-native/internal/Scalar.ts +13 -2
- package/src/react-native/internal/Store.ts +78 -0
- package/src/react-native/internal/Tokens.ts +85 -0
- package/src/react-native/internal/Viewport.ts +8 -0
- package/src/react-native/react.ts +211 -19
- package/src/react-native/reanimated.ts +162 -0
- package/src/runtime/NativeContext.ts +88 -17
- package/src/runtime/NativeDynamic.ts +35 -10
- package/src/runtime/NativeStatic.ts +145 -0
- package/src/runtime/NativeVars.ts +189 -0
- package/src/runtime/index.ts +6 -0
- package/src/runtime/internal/NativeMedia.ts +63 -0
- package/src/variable.ts +1 -1
- package/src/vite/index.ts +52 -60
- package/src/web/Css.ts +123 -74
- package/src/web/internal/ClassName.ts +31 -36
- package/src/web/internal/Themes.ts +62 -39
- package/src/web/page.ts +2 -0
|
@@ -1,13 +1,32 @@
|
|
|
1
1
|
/** Lowers target-neutral callback declarations to ordered native binding data. @module */
|
|
2
|
-
import type * as Recipe from '../../internal/Recipe.js'
|
|
3
2
|
import * as Binding from '../../internal/Binding.js'
|
|
4
|
-
import * as Token from '../../internal/Token.js'
|
|
5
|
-
import type * as Style from '../../Style.js'
|
|
6
|
-
import * as StyleSheet from '../../react-native/StyleSheet.js'
|
|
7
|
-
import * as Scalar from '../../react-native/internal/Scalar.js'
|
|
8
|
-
import type * as Runtime from '../../runtime/NativeDynamic.js'
|
|
9
3
|
import type * as Native from '../Native.js'
|
|
4
|
+
import type * as Recipe from '../../internal/Recipe.js'
|
|
5
|
+
import type * as Runtime from '../../runtime/NativeDynamic.js'
|
|
6
|
+
import * as Scalar from '../../react-native/internal/Scalar.js'
|
|
10
7
|
import type * as Source from '../Source.js'
|
|
8
|
+
import type * as Static from '../../runtime/NativeStatic.js'
|
|
9
|
+
import type * as Style from '../../Style.js'
|
|
10
|
+
import * as StyleSheet from '../../react-native/StyleSheet.js'
|
|
11
|
+
import * as Token from '../../internal/Token.js'
|
|
12
|
+
import * as Tokens from '../../react-native/internal/Tokens.js'
|
|
13
|
+
|
|
14
|
+
type Step = Runtime.Program['rules'][number]['steps'][number]
|
|
15
|
+
type PreparedStep =
|
|
16
|
+
| Extract<Step, { readonly style: string }>
|
|
17
|
+
| {
|
|
18
|
+
readonly property: keyof typeof Scalar.properties
|
|
19
|
+
readonly parts: readonly (
|
|
20
|
+
| string
|
|
21
|
+
| number
|
|
22
|
+
| Token.Reference
|
|
23
|
+
| { readonly slot: string; readonly number?: true }
|
|
24
|
+
)[]
|
|
25
|
+
}
|
|
26
|
+
type PreparedRule = {
|
|
27
|
+
readonly matches: Runtime.Program['rules'][number]['matches']
|
|
28
|
+
readonly steps: readonly PreparedStep[]
|
|
29
|
+
}
|
|
11
30
|
|
|
12
31
|
/** Compiles static fragments and retains scalar assignments in authored order. */
|
|
13
32
|
export function compile(
|
|
@@ -16,8 +35,36 @@ export function compile(
|
|
|
16
35
|
options: Native.compile.Options,
|
|
17
36
|
prepared = prepare(recipe, call, options),
|
|
18
37
|
): Runtime.create.Options {
|
|
38
|
+
const selected = options.vars?.[options.set ?? 'default']
|
|
39
|
+
const metadata =
|
|
40
|
+
selected &&
|
|
41
|
+
(Object.getOwnPropertyDescriptor(selected, Token.definition)?.value as
|
|
42
|
+
| Token.Metadata
|
|
43
|
+
| undefined)
|
|
19
44
|
return {
|
|
20
45
|
...prepared,
|
|
46
|
+
program: {
|
|
47
|
+
slots: prepared.program.slots,
|
|
48
|
+
rules: prepared.program.rules.map((rule) => ({
|
|
49
|
+
...rule,
|
|
50
|
+
steps: rule.steps.map((step) =>
|
|
51
|
+
'style' in step
|
|
52
|
+
? step
|
|
53
|
+
: {
|
|
54
|
+
...step,
|
|
55
|
+
parts: step.parts.map((part) =>
|
|
56
|
+
Token.is(part)
|
|
57
|
+
? Tokens.resolve(part, {
|
|
58
|
+
...options,
|
|
59
|
+
metadata,
|
|
60
|
+
resolution: { schemeIndependent: true },
|
|
61
|
+
})
|
|
62
|
+
: part,
|
|
63
|
+
),
|
|
64
|
+
},
|
|
65
|
+
),
|
|
66
|
+
})),
|
|
67
|
+
},
|
|
21
68
|
styles: StyleSheet.select(prepared.styles, {
|
|
22
69
|
set: options.set ?? 'default',
|
|
23
70
|
colorScheme: options.colorScheme,
|
|
@@ -25,6 +72,39 @@ export function compile(
|
|
|
25
72
|
}
|
|
26
73
|
}
|
|
27
74
|
|
|
75
|
+
/** Removes dynamic instructions and resolves absolute line heights before publication. */
|
|
76
|
+
export function finite(options: Runtime.create.Options): Static.create.Options {
|
|
77
|
+
const styles = { ...options.styles }
|
|
78
|
+
return {
|
|
79
|
+
axes: options.axes,
|
|
80
|
+
defaults: options.defaults,
|
|
81
|
+
rules: options.program.rules.map((rule) => ({
|
|
82
|
+
matches: rule.matches,
|
|
83
|
+
steps: rule.steps.map((step) => {
|
|
84
|
+
if ('style' in step) return step.style
|
|
85
|
+
if (
|
|
86
|
+
step.property !== 'lineHeight' ||
|
|
87
|
+
!step.parts.length ||
|
|
88
|
+
step.parts.some((part) => typeof part === 'object')
|
|
89
|
+
)
|
|
90
|
+
throw new Error(
|
|
91
|
+
'Static native recipes cannot contain runtime bindings.',
|
|
92
|
+
)
|
|
93
|
+
const value = (
|
|
94
|
+
step.parts.length === 1 ? step.parts[0]! : step.parts.join('')
|
|
95
|
+
) as string | number
|
|
96
|
+
if (typeof value === 'number') return value
|
|
97
|
+
const name = String(Object.keys(styles).length)
|
|
98
|
+
styles[name] = {
|
|
99
|
+
lineHeight: Scalar.length(value, options, false, ['lineHeight']),
|
|
100
|
+
}
|
|
101
|
+
return name
|
|
102
|
+
}),
|
|
103
|
+
})),
|
|
104
|
+
styles,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
28
108
|
/** Prepares immutable programs and all set/scheme tables before selection. */
|
|
29
109
|
export function prepare(
|
|
30
110
|
recipe: Recipe.Definition,
|
|
@@ -41,15 +121,10 @@ export function prepare(
|
|
|
41
121
|
),
|
|
42
122
|
])
|
|
43
123
|
const fragments: Style.NamedStyle[] = []
|
|
44
|
-
const rules:
|
|
45
|
-
|
|
46
|
-
for (const choices of Object.values(recipe.axes)) count *= choices.length + 1
|
|
47
|
-
if (count > 256)
|
|
48
|
-
throw new Error(
|
|
49
|
-
'Native recipes support at most 256 selections, including null choices.',
|
|
50
|
-
)
|
|
124
|
+
const rules: PreparedRule[] = []
|
|
125
|
+
|
|
51
126
|
for (const rule of recipe.rules) {
|
|
52
|
-
const steps:
|
|
127
|
+
const steps: PreparedStep[] = []
|
|
53
128
|
function fragment(style: Style.NamedStyle) {
|
|
54
129
|
const name = String(fragments.length)
|
|
55
130
|
fragments.push({ ...style, name })
|
|
@@ -94,14 +169,22 @@ export function prepare(
|
|
|
94
169
|
)
|
|
95
170
|
const values = parts.map((part) => {
|
|
96
171
|
if (typeof part === 'string' || typeof part === 'number') return part
|
|
172
|
+
if (Token.is(part)) return part
|
|
97
173
|
if (!Binding.is(part) || !available.has(part.name))
|
|
98
174
|
throw new Error(
|
|
99
175
|
'Native bindings require declared runtime scalar fields.',
|
|
100
176
|
)
|
|
101
|
-
return {
|
|
177
|
+
return {
|
|
178
|
+
slot: part.name,
|
|
179
|
+
...(part.type === 'number' ? { number: true as const } : {}),
|
|
180
|
+
}
|
|
102
181
|
})
|
|
182
|
+
const calculation = values.some(
|
|
183
|
+
(value) => typeof value === 'string' && /(?:^|\s)calc\(/i.test(value),
|
|
184
|
+
)
|
|
103
185
|
if (
|
|
104
186
|
values.length > 1 &&
|
|
187
|
+
!calculation &&
|
|
105
188
|
!(
|
|
106
189
|
values.length === 2 &&
|
|
107
190
|
typeof values[0] === 'object' &&
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/** Lowers native media rules and conditional tokens to bounded static alternatives. @module */
|
|
2
|
+
import * as CssTree from 'css-tree'
|
|
3
|
+
import type * as Media from '../../runtime/internal/NativeMedia.js'
|
|
4
|
+
import * as Scalar from '../../react-native/internal/Scalar.js'
|
|
5
|
+
import type * as Style from '../../Style.js'
|
|
6
|
+
import type * as StyleSheet from '../../react-native/StyleSheet.js'
|
|
7
|
+
import * as Token from '../../internal/Token.js'
|
|
8
|
+
|
|
9
|
+
/** Retains authored precedence while selecting each possible media outcome. */
|
|
10
|
+
export function prepare<variables extends StyleSheet.compile.Options['vars']>(
|
|
11
|
+
styles: readonly Style.NamedStyle[] | undefined,
|
|
12
|
+
vars: variables,
|
|
13
|
+
options: Scalar.Options,
|
|
14
|
+
) {
|
|
15
|
+
const catalog: StyleSheet.compile.Options['vars'] = vars
|
|
16
|
+
const expressions = new Map<string, number>()
|
|
17
|
+
const names = new Map<string, number>()
|
|
18
|
+
const queries: Media.Query[] = []
|
|
19
|
+
const visited = new Set<object>()
|
|
20
|
+
|
|
21
|
+
function add(name: string) {
|
|
22
|
+
if (names.has(name)) return
|
|
23
|
+
|
|
24
|
+
const query = parse(name, options)
|
|
25
|
+
const expression = JSON.stringify(query)
|
|
26
|
+
let index = expressions.get(expression)
|
|
27
|
+
if (index === undefined) {
|
|
28
|
+
index = queries.length
|
|
29
|
+
if (index === 8)
|
|
30
|
+
throw new Error(
|
|
31
|
+
'Native media supports at most eight distinct conditions per definition.',
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
queries.push(query)
|
|
35
|
+
expressions.set(expression, index)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
names.set(name, index)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function values(value: unknown) {
|
|
42
|
+
if (!value || typeof value !== 'object' || visited.has(value)) return
|
|
43
|
+
|
|
44
|
+
visited.add(value)
|
|
45
|
+
if (Token.is(value)) {
|
|
46
|
+
values(value.value)
|
|
47
|
+
for (const theme of Object.values(catalog ?? {})) {
|
|
48
|
+
const metadata = theme[Token.definition]
|
|
49
|
+
if (
|
|
50
|
+
metadata.contract === value.contract ||
|
|
51
|
+
(metadata.contract[Token.identity] !== undefined &&
|
|
52
|
+
metadata.contract[Token.identity] ===
|
|
53
|
+
value.contract[Token.identity])
|
|
54
|
+
)
|
|
55
|
+
values(metadata.values[value.path])
|
|
56
|
+
}
|
|
57
|
+
} else if (Token.isExpression(value)) value.parts.forEach(values)
|
|
58
|
+
else if ('default' in value) {
|
|
59
|
+
for (const [name, entry] of Object.entries(value)) {
|
|
60
|
+
if (name !== 'default') {
|
|
61
|
+
// Unsupported variable leaves keep their deferred read diagnostic.
|
|
62
|
+
try {
|
|
63
|
+
add(name)
|
|
64
|
+
} catch (error) {
|
|
65
|
+
if (!(error instanceof UnsupportedError)) throw error
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
values(entry)
|
|
69
|
+
}
|
|
70
|
+
} else if ('light' in value && 'dark' in value) {
|
|
71
|
+
values(value.light)
|
|
72
|
+
values(value.dark)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function visit(style: Style.NamedStyle) {
|
|
77
|
+
for (const declaration of style.declarations) values(declaration.value)
|
|
78
|
+
for (const rule of style.rules ?? []) {
|
|
79
|
+
if (rule.condition?.startsWith('@media')) add(rule.condition)
|
|
80
|
+
visit(rule.style)
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
styles?.forEach(visit)
|
|
85
|
+
if (!styles)
|
|
86
|
+
for (const theme of Object.values(catalog ?? {})) {
|
|
87
|
+
const metadata = theme[Token.definition]
|
|
88
|
+
Object.values(metadata.values).forEach(values)
|
|
89
|
+
}
|
|
90
|
+
if (!queries.length) return
|
|
91
|
+
|
|
92
|
+
return {
|
|
93
|
+
queries,
|
|
94
|
+
select(selection: string) {
|
|
95
|
+
const active = new Set<object>()
|
|
96
|
+
function value<entry>(entry: entry): entry {
|
|
97
|
+
if (!entry || typeof entry !== 'object') return entry
|
|
98
|
+
if (active.has(entry))
|
|
99
|
+
throw new Error('Native token aliases must not form a cycle.')
|
|
100
|
+
|
|
101
|
+
active.add(entry)
|
|
102
|
+
try {
|
|
103
|
+
if (Token.is(entry))
|
|
104
|
+
return Token.create({
|
|
105
|
+
...entry,
|
|
106
|
+
value: value(entry.value),
|
|
107
|
+
}) as entry
|
|
108
|
+
if (Token.isExpression(entry))
|
|
109
|
+
return { ...entry, parts: entry.parts.map(value) } as entry
|
|
110
|
+
if ('default' in entry) {
|
|
111
|
+
const branches = Object.entries(entry)
|
|
112
|
+
if (
|
|
113
|
+
branches.some(([name]) => name !== 'default' && !names.has(name))
|
|
114
|
+
)
|
|
115
|
+
return Object.fromEntries(
|
|
116
|
+
branches
|
|
117
|
+
.filter(([name]) => name === 'default' || !names.has(name))
|
|
118
|
+
.map(([name, branch]) => [name, value(branch)]),
|
|
119
|
+
) as entry
|
|
120
|
+
|
|
121
|
+
let selected = entry.default
|
|
122
|
+
for (const [name, branch] of branches)
|
|
123
|
+
if (name !== 'default' && selection[names.get(name)!] === '1')
|
|
124
|
+
selected = branch
|
|
125
|
+
|
|
126
|
+
return value(selected) as entry
|
|
127
|
+
}
|
|
128
|
+
if ('light' in entry && 'dark' in entry)
|
|
129
|
+
return {
|
|
130
|
+
...entry,
|
|
131
|
+
dark: value(entry.dark),
|
|
132
|
+
light: value(entry.light),
|
|
133
|
+
}
|
|
134
|
+
return entry
|
|
135
|
+
} finally {
|
|
136
|
+
active.delete(entry)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function style(entry: Style.NamedStyle): Style.NamedStyle {
|
|
141
|
+
return {
|
|
142
|
+
...entry,
|
|
143
|
+
declarations: entry.declarations.map((declaration) => ({
|
|
144
|
+
...declaration,
|
|
145
|
+
value: value(declaration.value),
|
|
146
|
+
})),
|
|
147
|
+
...(entry.rules
|
|
148
|
+
? {
|
|
149
|
+
rules: entry.rules.flatMap((rule) => {
|
|
150
|
+
const index =
|
|
151
|
+
rule.condition === undefined
|
|
152
|
+
? undefined
|
|
153
|
+
: names.get(rule.condition)
|
|
154
|
+
if (index !== undefined && selection[index] !== '1') return []
|
|
155
|
+
|
|
156
|
+
return [
|
|
157
|
+
{
|
|
158
|
+
...(index === undefined ? rule : {}),
|
|
159
|
+
style: style(rule.style),
|
|
160
|
+
},
|
|
161
|
+
]
|
|
162
|
+
}),
|
|
163
|
+
}
|
|
164
|
+
: {}),
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
style,
|
|
170
|
+
vars:
|
|
171
|
+
catalog &&
|
|
172
|
+
(Object.fromEntries(
|
|
173
|
+
Object.entries(catalog).map(([name, theme]) => {
|
|
174
|
+
const metadata = theme[Token.definition]
|
|
175
|
+
return [
|
|
176
|
+
name,
|
|
177
|
+
Object.defineProperty({}, Token.definition, {
|
|
178
|
+
value: {
|
|
179
|
+
...metadata,
|
|
180
|
+
values: Object.fromEntries(
|
|
181
|
+
Object.entries(metadata.values).map(([path, entry]) => [
|
|
182
|
+
path,
|
|
183
|
+
value(entry),
|
|
184
|
+
]),
|
|
185
|
+
),
|
|
186
|
+
},
|
|
187
|
+
}) as typeof theme,
|
|
188
|
+
]
|
|
189
|
+
}),
|
|
190
|
+
) as variables),
|
|
191
|
+
}
|
|
192
|
+
},
|
|
193
|
+
selections: Array.from({ length: 2 ** queries.length }, (_entry, index) =>
|
|
194
|
+
index.toString(2).padStart(queries.length, '0'),
|
|
195
|
+
),
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
class UnsupportedError extends Error {
|
|
200
|
+
override name = 'NativeMedia.UnsupportedError'
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function parse(input: string, options: Scalar.Options): Media.Query {
|
|
204
|
+
if (!input.startsWith('@media'))
|
|
205
|
+
throw new UnsupportedError(
|
|
206
|
+
'Native conditional variables require media queries.',
|
|
207
|
+
)
|
|
208
|
+
const parsed = CssTree.parse(input.slice(6), { context: 'mediaQueryList' })
|
|
209
|
+
let count = 0
|
|
210
|
+
function read(node: CssTree.CssNode): Media.Query {
|
|
211
|
+
if (++count > 128)
|
|
212
|
+
throw new Error('Native media queries exceed 128 syntax nodes.')
|
|
213
|
+
if (node.type === 'MediaQueryList') {
|
|
214
|
+
const queries = node.children.toArray().map(read)
|
|
215
|
+
return queries.length === 1 ? queries[0]! : { kind: 'or', queries }
|
|
216
|
+
}
|
|
217
|
+
if (node.type === 'MediaQuery') {
|
|
218
|
+
if (
|
|
219
|
+
(node.mediaType &&
|
|
220
|
+
!['all', 'screen'].includes(node.mediaType.toLowerCase())) ||
|
|
221
|
+
node.modifier?.toLowerCase() === 'not'
|
|
222
|
+
)
|
|
223
|
+
throw new UnsupportedError(
|
|
224
|
+
'Native media types support all or screen without negation.',
|
|
225
|
+
)
|
|
226
|
+
return node.condition
|
|
227
|
+
? read(node.condition)
|
|
228
|
+
: { kind: 'compare', left: 0, operator: '=', right: 0 }
|
|
229
|
+
}
|
|
230
|
+
if (node.type === 'Condition') {
|
|
231
|
+
const parts = node.children.toArray()
|
|
232
|
+
if (parts.length === 1) return read(parts[0]!)
|
|
233
|
+
if (
|
|
234
|
+
parts.length === 2 &&
|
|
235
|
+
parts[0]?.type === 'Identifier' &&
|
|
236
|
+
parts[0].name.toLowerCase() === 'not'
|
|
237
|
+
)
|
|
238
|
+
return { kind: 'not', query: read(parts[1]!) }
|
|
239
|
+
const operator =
|
|
240
|
+
parts[1]?.type === 'Identifier'
|
|
241
|
+
? parts[1].name.toLowerCase()
|
|
242
|
+
: undefined
|
|
243
|
+
if (
|
|
244
|
+
(operator !== 'and' && operator !== 'or') ||
|
|
245
|
+
parts.length % 2 !== 1 ||
|
|
246
|
+
parts.some(
|
|
247
|
+
(part, index) =>
|
|
248
|
+
index % 2 === 1 &&
|
|
249
|
+
(part.type !== 'Identifier' ||
|
|
250
|
+
part.name.toLowerCase() !== operator),
|
|
251
|
+
)
|
|
252
|
+
)
|
|
253
|
+
throw new UnsupportedError('Unsupported native media condition.')
|
|
254
|
+
return {
|
|
255
|
+
kind: operator,
|
|
256
|
+
queries: parts.filter((_part, index) => index % 2 === 0).map(read),
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function operand(entry: CssTree.CssNode): number | 'height' | 'width' {
|
|
260
|
+
if (
|
|
261
|
+
entry.type === 'Identifier' &&
|
|
262
|
+
(entry.name.toLowerCase() === 'height' ||
|
|
263
|
+
entry.name.toLowerCase() === 'width')
|
|
264
|
+
)
|
|
265
|
+
return entry.name.toLowerCase() as 'height' | 'width'
|
|
266
|
+
if (entry.type === 'Dimension') {
|
|
267
|
+
try {
|
|
268
|
+
return Scalar.length(
|
|
269
|
+
`${entry.value}${entry.unit.toLowerCase()}`,
|
|
270
|
+
options,
|
|
271
|
+
false,
|
|
272
|
+
[],
|
|
273
|
+
)
|
|
274
|
+
} catch (error) {
|
|
275
|
+
throw new UnsupportedError((error as Error).message)
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (entry.type === 'Number' && Number(entry.value) === 0) return 0
|
|
279
|
+
throw new UnsupportedError(
|
|
280
|
+
'Native media ranges require width/height and px/rem thresholds.',
|
|
281
|
+
)
|
|
282
|
+
}
|
|
283
|
+
function comparison(
|
|
284
|
+
left: CssTree.CssNode,
|
|
285
|
+
operator: string | null,
|
|
286
|
+
right: CssTree.CssNode,
|
|
287
|
+
): Media.Query {
|
|
288
|
+
if (!operator || !['<', '<=', '=', '>', '>='].includes(operator))
|
|
289
|
+
throw new UnsupportedError('Unsupported native media comparison.')
|
|
290
|
+
return {
|
|
291
|
+
kind: 'compare',
|
|
292
|
+
left: operand(left),
|
|
293
|
+
operator: operator as '<' | '<=' | '=' | '>' | '>=',
|
|
294
|
+
right: operand(right),
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
if (node.type === 'FeatureRange') {
|
|
298
|
+
const first = comparison(node.left, node.leftComparison, node.middle)
|
|
299
|
+
return node.right
|
|
300
|
+
? {
|
|
301
|
+
kind: 'and',
|
|
302
|
+
queries: [
|
|
303
|
+
first,
|
|
304
|
+
comparison(node.middle, node.rightComparison, node.right),
|
|
305
|
+
],
|
|
306
|
+
}
|
|
307
|
+
: first
|
|
308
|
+
}
|
|
309
|
+
if (node.type === 'Feature') {
|
|
310
|
+
const name = node.name.toLowerCase()
|
|
311
|
+
if (
|
|
312
|
+
name === 'orientation' &&
|
|
313
|
+
node.value?.type === 'Identifier' &&
|
|
314
|
+
['landscape', 'portrait'].includes(node.value.name.toLowerCase())
|
|
315
|
+
)
|
|
316
|
+
return {
|
|
317
|
+
kind: 'compare',
|
|
318
|
+
left: 'width',
|
|
319
|
+
operator: node.value.name.toLowerCase() === 'landscape' ? '>' : '<=',
|
|
320
|
+
right: 'height',
|
|
321
|
+
}
|
|
322
|
+
const match = /^(?:(min|max)-)?(height|width)$/.exec(name)
|
|
323
|
+
if (match)
|
|
324
|
+
return {
|
|
325
|
+
kind: 'compare',
|
|
326
|
+
left: match[2] as 'height' | 'width',
|
|
327
|
+
operator:
|
|
328
|
+
match[1] === 'min'
|
|
329
|
+
? '>='
|
|
330
|
+
: match[1] === 'max'
|
|
331
|
+
? '<='
|
|
332
|
+
: node.value
|
|
333
|
+
? '='
|
|
334
|
+
: '>',
|
|
335
|
+
right: node.value ? operand(node.value) : 0,
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
throw new UnsupportedError('Unsupported native media feature.')
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return read(parsed)
|
|
342
|
+
}
|