zyzz 0.0.21 → 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 +3 -1
- package/dist/Style.d.ts.map +1 -1
- 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.map +1 -1
- package/dist/compiler/Graph.js +64 -0
- 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 +2 -0
- package/dist/compiler/Source.d.ts.map +1 -1
- package/dist/compiler/Source.js +17 -5
- package/dist/compiler/Source.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 +21 -3
- package/dist/compiler/internal/Configurations.js.map +1 -1
- package/dist/compiler/internal/Contract.d.ts.map +1 -1
- package/dist/compiler/internal/Contract.js +75 -38
- 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 +7 -1
- 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/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/Themes.d.ts +22 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +118 -3
- package/dist/compiler/internal/Themes.js.map +1 -1
- package/dist/compiler/internal/Vars.d.ts +1 -1
- package/dist/compiler/internal/Vars.d.ts.map +1 -1
- package/dist/compiler/internal/Vars.js +7 -2
- package/dist/compiler/internal/Vars.js.map +1 -1
- package/dist/default.js.zyzz.json +1 -1
- package/dist/internal/Completion.d.ts +1 -1
- package/dist/internal/Completion.d.ts.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/Token.d.ts +0 -2
- package/dist/internal/Token.d.ts.map +1 -1
- 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/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/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/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +7 -35
- package/dist/vite/index.js.map +1 -1
- package/dist/web/Css.d.ts.map +1 -1
- package/dist/web/Css.js +31 -19
- package/dist/web/Css.js.map +1 -1
- package/dist/web/internal/Themes.d.ts +0 -2
- package/dist/web/internal/Themes.d.ts.map +1 -1
- package/dist/web/internal/Themes.js +30 -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 +11 -8
- package/src/babel/NativeJsx.ts +305 -28
- package/src/babel/index.ts +21 -3
- package/src/compiler/Graph.ts +75 -0
- package/src/compiler/Native.ts +158 -26
- package/src/compiler/Source.ts +32 -5
- package/src/compiler/internal/Configurations.ts +25 -3
- package/src/compiler/internal/Contract.ts +98 -50
- package/src/compiler/internal/Contributions.ts +7 -1
- package/src/compiler/internal/Descriptors.ts +12 -8
- 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/Themes.ts +187 -2
- package/src/compiler/internal/Vars.ts +12 -1
- package/src/internal/Completion.ts +6 -3
- package/src/internal/Targets.ts +2 -0
- package/src/internal/Token.ts +0 -2
- package/src/internal/Value.ts +20 -0
- 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/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/vite/index.ts +9 -42
- package/src/web/Css.ts +42 -27
- package/src/web/internal/Themes.ts +34 -57
- package/src/web/page.ts +2 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/** Resolves portable references for native tables and callback expressions. @module */
|
|
2
|
+
import * as Calculation from './Calculation.js'
|
|
3
|
+
import type * as Scalar from './Scalar.js'
|
|
4
|
+
import type * as Style from '../../Style.js'
|
|
5
|
+
import * as Token from '../../internal/Token.js'
|
|
6
|
+
|
|
7
|
+
/** Identifies values whose behavior requires a web target. */
|
|
8
|
+
export class UnsupportedError extends Error {
|
|
9
|
+
override name = 'Tokens.UnsupportedError'
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Selects live token aliases and schemes without evaluating authored code. */
|
|
13
|
+
export function resolve(
|
|
14
|
+
input: Style.Declaration['value'],
|
|
15
|
+
options: resolve.Options,
|
|
16
|
+
): string | number {
|
|
17
|
+
const active = new Set<Token.Reference>()
|
|
18
|
+
function scalar(
|
|
19
|
+
value: Token.Value | Style.Declaration['value'],
|
|
20
|
+
): string | number {
|
|
21
|
+
if (typeof value === 'number' || typeof value === 'string') return value
|
|
22
|
+
if (
|
|
23
|
+
Token.is(value) &&
|
|
24
|
+
!Object.getOwnPropertyDescriptor(value, Token.web)?.value
|
|
25
|
+
) {
|
|
26
|
+
if (active.has(value))
|
|
27
|
+
throw new Error('Native token aliases must not form a cycle.')
|
|
28
|
+
const metadata = options.metadata
|
|
29
|
+
const shared =
|
|
30
|
+
metadata &&
|
|
31
|
+
(metadata.contract === value.contract ||
|
|
32
|
+
(metadata.contract[Token.identity] !== undefined &&
|
|
33
|
+
metadata.contract[Token.identity] ===
|
|
34
|
+
value.contract[Token.identity]))
|
|
35
|
+
const next = shared
|
|
36
|
+
? Object.hasOwn(metadata.values, value.path)
|
|
37
|
+
? metadata.values[value.path]
|
|
38
|
+
: undefined
|
|
39
|
+
: value.value
|
|
40
|
+
if (next === undefined) throw new Error('Theme is missing a live token.')
|
|
41
|
+
active.add(value)
|
|
42
|
+
const result = scalar(next)
|
|
43
|
+
active.delete(value)
|
|
44
|
+
return result
|
|
45
|
+
}
|
|
46
|
+
if (Token.isExpression(value)) {
|
|
47
|
+
const text = value.parts.map(scalar).join('')
|
|
48
|
+
if (
|
|
49
|
+
!('group' in value) ||
|
|
50
|
+
value.group !== 'spacing' ||
|
|
51
|
+
!/^\s*calc\(/i.test(text)
|
|
52
|
+
)
|
|
53
|
+
return text
|
|
54
|
+
return `${Calculation.length(text, options) / (options.units?.px ?? 1)}px`
|
|
55
|
+
}
|
|
56
|
+
if (
|
|
57
|
+
value &&
|
|
58
|
+
typeof value === 'object' &&
|
|
59
|
+
'light' in value &&
|
|
60
|
+
'dark' in value
|
|
61
|
+
) {
|
|
62
|
+
if (value.light !== value.dark)
|
|
63
|
+
options.resolution.schemeIndependent = false
|
|
64
|
+
return scalar(value[options.colorScheme])
|
|
65
|
+
}
|
|
66
|
+
if (value && typeof value === 'object' && 'default' in value)
|
|
67
|
+
throw new UnsupportedError(
|
|
68
|
+
'Media-conditioned variables require a web target.',
|
|
69
|
+
)
|
|
70
|
+
throw new UnsupportedError(
|
|
71
|
+
'Web variables, expressions, and dynamic bindings are not native scalar tokens.',
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
return scalar(input)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Native token selection and explicit unit conversion. */
|
|
78
|
+
export declare namespace resolve {
|
|
79
|
+
/** Profile metadata and scheme independence shared by table preparation. */
|
|
80
|
+
type Options = Scalar.Options & {
|
|
81
|
+
readonly colorScheme: 'dark' | 'light'
|
|
82
|
+
readonly metadata: Token.Metadata | undefined
|
|
83
|
+
readonly resolution: { schemeIndependent: boolean }
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** Connects the native device adapter to framework subscriptions. @module */
|
|
2
|
+
import type * as Media from '../../runtime/internal/NativeMedia.js'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
/** Window measurements owned by the native Provider lifecycle. */
|
|
6
|
+
export const context = React.createContext<Media.Viewport | undefined>(
|
|
7
|
+
undefined,
|
|
8
|
+
)
|
|
@@ -1,47 +1,239 @@
|
|
|
1
|
-
/** React
|
|
2
|
-
import * as
|
|
1
|
+
/** React subscriptions for compiled native styles and variable values. @module */
|
|
2
|
+
import * as Config from '../Config.js'
|
|
3
3
|
import * as NativeContext from '../runtime/NativeContext.js'
|
|
4
|
+
import * as NativeVars from '../runtime/NativeVars.js'
|
|
5
|
+
import * as React from 'react'
|
|
6
|
+
import type * as Vars from '../Vars.js'
|
|
7
|
+
import * as Store from './internal/Store.js'
|
|
8
|
+
import * as Viewport from './internal/Viewport.js'
|
|
9
|
+
|
|
10
|
+
const unbound = {
|
|
11
|
+
getSnapshot: () => undefined,
|
|
12
|
+
subscribe: () => () => {},
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Creates native authoring helpers and a Provider typed to the configured variables. */
|
|
16
|
+
export function defineConfig<const options extends Config.create.Options = {}>(
|
|
17
|
+
options: options & Parameters<typeof Config.create<options>>[0] = {} as never,
|
|
18
|
+
): defineConfig.ReturnType<options> {
|
|
19
|
+
const config = Config.create<options>(options)
|
|
20
|
+
const defaultVars = (options as Config.VariableOptions).defaultVars
|
|
21
|
+
const names =
|
|
22
|
+
defaultVars === undefined
|
|
23
|
+
? undefined
|
|
24
|
+
: new Set(Object.keys((options as Config.VariableOptions).vars))
|
|
4
25
|
|
|
5
|
-
|
|
26
|
+
function BoundProvider(props: defineConfig.ProviderProps<options>) {
|
|
27
|
+
if (props.vars !== undefined && !names?.has(props.vars))
|
|
28
|
+
throw new Error(`Unknown native vars: ${props.vars}.`)
|
|
6
29
|
|
|
7
|
-
|
|
30
|
+
return React.createElement(Provider, {
|
|
31
|
+
...props,
|
|
32
|
+
vars: props.vars ?? defaultVars,
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return Object.freeze({
|
|
37
|
+
...config,
|
|
38
|
+
Provider: BoundProvider,
|
|
39
|
+
}) as defineConfig.ReturnType<options>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Native configuration helpers and inferred Provider props. */
|
|
43
|
+
export declare namespace defineConfig {
|
|
44
|
+
/** Resolved scheme and variable names from the owning configuration. */
|
|
45
|
+
type ProviderProps<options extends Config.create.Options> = Omit<
|
|
46
|
+
Provider.Props,
|
|
47
|
+
'vars'
|
|
48
|
+
> & {
|
|
49
|
+
/** Selected variables. Omission uses the owning configuration's default. */
|
|
50
|
+
readonly vars?:
|
|
51
|
+
| (options extends { defaultVars: string; vars: infer catalog }
|
|
52
|
+
? Extract<keyof catalog, string>
|
|
53
|
+
: never)
|
|
54
|
+
| undefined
|
|
55
|
+
}
|
|
56
|
+
/** Existing authoring helpers plus a configuration-scoped Provider. */
|
|
57
|
+
type ReturnType<options extends Config.create.Options = {}> =
|
|
58
|
+
Config.create.ReturnType<options> & {
|
|
59
|
+
/** Provides this configuration's typed selection to native consumers. */
|
|
60
|
+
readonly Provider: React.FunctionComponent<ProviderProps<options>>
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** Supplies selected variables, appearance, and adapter measurements to this subtree. */
|
|
8
65
|
export function Provider(props: Provider.Props) {
|
|
66
|
+
if (Object.hasOwn(props, 'set'))
|
|
67
|
+
throw new Error('Provider uses vars instead of set.')
|
|
9
68
|
if (
|
|
10
69
|
(props.colorScheme !== 'light' && props.colorScheme !== 'dark') ||
|
|
11
|
-
(props.
|
|
12
|
-
(typeof props.
|
|
70
|
+
(props.vars !== undefined &&
|
|
71
|
+
(typeof props.vars !== 'string' || !props.vars.trim()))
|
|
13
72
|
)
|
|
14
73
|
throw new Error(
|
|
15
|
-
'Native appearance requires a resolved light/dark scheme and a nonempty
|
|
74
|
+
'Native appearance requires a resolved light/dark scheme and a nonempty vars name.',
|
|
16
75
|
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
76
|
+
|
|
77
|
+
const viewport = React.useContext(Viewport.context)
|
|
78
|
+
const [store] = React.useState(() =>
|
|
79
|
+
Store.create({ colorScheme: props.colorScheme, set: props.vars, viewport }),
|
|
20
80
|
)
|
|
21
|
-
|
|
81
|
+
const [, publish] = React.useReducer((version: number) => version + 1, 0)
|
|
82
|
+
const committed = React.useRef(props.children)
|
|
83
|
+
const snapshot = store.getSnapshot()
|
|
84
|
+
const pending =
|
|
85
|
+
snapshot.colorScheme !== props.colorScheme ||
|
|
86
|
+
snapshot.set !== props.vars ||
|
|
87
|
+
snapshot.viewport?.width !== viewport?.width ||
|
|
88
|
+
snapshot.viewport?.height !== viewport?.height
|
|
89
|
+
const children = pending ? committed.current : props.children
|
|
90
|
+
React.useLayoutEffect(() => {
|
|
91
|
+
committed.current = children
|
|
92
|
+
if (!pending) return
|
|
93
|
+
// Keep the committed subtree until its selection is published. This avoids
|
|
94
|
+
// rendering new application props with the previous store snapshot, without
|
|
95
|
+
// mutating an external store during a potentially abandoned React render.
|
|
96
|
+
store.update({ colorScheme: props.colorScheme, set: props.vars, viewport })
|
|
97
|
+
publish()
|
|
98
|
+
}, [children, pending, props.colorScheme, props.vars, store, viewport])
|
|
99
|
+
|
|
100
|
+
return React.createElement(Store.context.Provider, { value: store }, children)
|
|
22
101
|
}
|
|
23
102
|
|
|
24
|
-
/** Application boundary
|
|
103
|
+
/** Application boundary for native variable selection. */
|
|
25
104
|
export declare namespace Provider {
|
|
26
|
-
/**
|
|
27
|
-
type Props =
|
|
28
|
-
/** Components that consume compiled native
|
|
105
|
+
/** Resolved appearance and a configuration-relative variable name. */
|
|
106
|
+
type Props = {
|
|
107
|
+
/** Components that consume compiled native styling or values. */
|
|
29
108
|
readonly children?: React.ReactNode | undefined
|
|
109
|
+
/** Resolved device scheme or an application override. */
|
|
110
|
+
readonly colorScheme: 'dark' | 'light'
|
|
111
|
+
/** Selected variables. Omission uses each configuration's default. */
|
|
112
|
+
readonly vars?: string | undefined
|
|
30
113
|
}
|
|
31
114
|
}
|
|
32
115
|
|
|
33
|
-
/** Compiler-inserted
|
|
116
|
+
/** Compiler-inserted subscription for resolving native style applications. */
|
|
34
117
|
export function useStyles() {
|
|
35
|
-
|
|
118
|
+
const store = React.useContext(Store.context) ?? unbound
|
|
119
|
+
const value = React.useSyncExternalStore(
|
|
120
|
+
store.subscribe,
|
|
121
|
+
store.getSnapshot,
|
|
122
|
+
store.getSnapshot,
|
|
123
|
+
)
|
|
124
|
+
return React.useMemo(() => styles(value), [value])
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** Compiler fallback for native view bindings when no native adapter is installed. */
|
|
128
|
+
export function useNativeStyles() {
|
|
129
|
+
const selected = useStyles()
|
|
130
|
+
return { ...selected, view: selected.props }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Reads readonly native variables using the nearest Provider's selection.
|
|
135
|
+
* @throws For missing providers, uncompiled definitions, or unsupported field reads.
|
|
136
|
+
*/
|
|
137
|
+
export function useVars<const variables extends Vars.Definition>(
|
|
138
|
+
variables: variables,
|
|
139
|
+
select?: undefined,
|
|
140
|
+
): NativeVars.Values<Vars.Extract<variables>>
|
|
141
|
+
/**
|
|
142
|
+
* Subscribes to a selection, comparing results with Object.is.
|
|
143
|
+
* @throws For invalid variable selection or unsupported field reads.
|
|
144
|
+
*/
|
|
145
|
+
export function useVars<const variables extends Vars.Definition, selected>(
|
|
146
|
+
variables: variables,
|
|
147
|
+
select: (values: NativeVars.Values<Vars.Extract<variables>>) => selected,
|
|
148
|
+
): selected
|
|
149
|
+
export function useVars(
|
|
150
|
+
variables: Vars.Definition,
|
|
151
|
+
select: (values: never) => unknown = (values) => values,
|
|
152
|
+
) {
|
|
153
|
+
const store = React.useContext(Store.context)
|
|
154
|
+
if (!store) throw new Error('useVars requires a Zyzz Provider.')
|
|
155
|
+
|
|
156
|
+
const read = React.useMemo(() => {
|
|
157
|
+
let previous: NativeContext.Context | undefined
|
|
158
|
+
let selected: unknown
|
|
159
|
+
return () => {
|
|
160
|
+
const snapshot = store.getSnapshot()
|
|
161
|
+
if (snapshot !== previous) {
|
|
162
|
+
const next = select(NativeVars.read(variables, snapshot) as never)
|
|
163
|
+
if (!previous || !Object.is(selected, next)) selected = next
|
|
164
|
+
previous = snapshot
|
|
165
|
+
}
|
|
166
|
+
return selected
|
|
167
|
+
}
|
|
168
|
+
}, [select, store, variables])
|
|
169
|
+
|
|
170
|
+
return React.useSyncExternalStore(store.subscribe, read, read)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Resolves compiled style props for components using React updates.
|
|
175
|
+
* @param Component - Function, class, or ref-forwarding component receiving native styles.
|
|
176
|
+
* @param options - Additional style-bearing prop names.
|
|
177
|
+
* @returns A component preserving the original props and ref.
|
|
178
|
+
* @throws For invalid style prop names or unresolved native selections.
|
|
179
|
+
*/
|
|
180
|
+
export function withStyles<const component extends React.ElementType>(
|
|
181
|
+
Component: component,
|
|
182
|
+
options: withStyles.Options<component> = {},
|
|
183
|
+
) {
|
|
184
|
+
const additional = options.styleProps ?? []
|
|
185
|
+
if (
|
|
186
|
+
!Array.isArray(additional) ||
|
|
187
|
+
additional.some(
|
|
188
|
+
(name) =>
|
|
189
|
+
typeof name !== 'string' || !name || name === 'key' || name === 'ref',
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
throw new Error(
|
|
193
|
+
'withStyles requires style prop names excluding key and ref.',
|
|
194
|
+
)
|
|
195
|
+
|
|
196
|
+
const names = [...new Set(['style', 'contentContainerStyle', ...additional])]
|
|
197
|
+
const Wrapped = React.forwardRef<
|
|
198
|
+
React.ComponentRef<component>,
|
|
199
|
+
React.ComponentPropsWithoutRef<component>
|
|
200
|
+
>((props, ref) => {
|
|
201
|
+
const selected = useStyles()
|
|
202
|
+
const resolved: Record<string, unknown> = { ...props, ref }
|
|
203
|
+
for (const name of names)
|
|
204
|
+
if (Object.hasOwn(props, name))
|
|
205
|
+
resolved[name] = selected.style(
|
|
206
|
+
(props as Record<string, unknown>)[name],
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return React.createElement(Component, resolved)
|
|
210
|
+
})
|
|
211
|
+
Wrapped.displayName = `withStyles(${typeof Component === 'string' ? Component : Component.displayName || Component.name || 'Component'})`
|
|
212
|
+
|
|
213
|
+
return Wrapped
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/** Style-bearing component properties resolved by the wrapper. */
|
|
217
|
+
export declare namespace withStyles {
|
|
218
|
+
/** Additional names are resolved alongside style and contentContainerStyle. */
|
|
219
|
+
type Options<component extends React.ElementType> = {
|
|
220
|
+
/** Additional style props declared by the wrapped component. */
|
|
221
|
+
readonly styleProps?:
|
|
222
|
+
| readonly Exclude<
|
|
223
|
+
Extract<keyof React.ComponentProps<component>, string>,
|
|
224
|
+
'key' | 'ref'
|
|
225
|
+
>[]
|
|
226
|
+
| undefined
|
|
227
|
+
}
|
|
36
228
|
}
|
|
37
229
|
|
|
38
230
|
function styles(value: NativeContext.Context | undefined) {
|
|
39
231
|
return {
|
|
40
|
-
style: (style: unknown, input?: unknown) =>
|
|
41
|
-
NativeContext.resolve(style, value, input),
|
|
42
232
|
props: (props: Record<string, unknown> | null | undefined) =>
|
|
43
233
|
props && Object.hasOwn(props, 'style')
|
|
44
234
|
? { ...props, style: NativeContext.resolve(props.style, value) }
|
|
45
235
|
: props,
|
|
236
|
+
style: (style: unknown, input?: unknown) =>
|
|
237
|
+
NativeContext.resolve(style, value, input),
|
|
46
238
|
}
|
|
47
239
|
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/** Publishes scoped native selections to Reanimated shared values. @module */
|
|
2
|
+
import * as NativeContext from '../runtime/NativeContext.js'
|
|
3
|
+
import * as NativeVars from '../runtime/NativeVars.js'
|
|
4
|
+
import * as React from 'react'
|
|
5
|
+
import * as ReactNative from 'react-native'
|
|
6
|
+
import * as Reanimated from 'react-native-reanimated'
|
|
7
|
+
import * as Store from './internal/Store.js'
|
|
8
|
+
import type * as StyleSheet from './StyleSheet.js'
|
|
9
|
+
import type * as Vars from '../Vars.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Reads a numeric or color property from a selected, composed native style.
|
|
13
|
+
* @param appliedStyle - Applied native style, including arrays and caller overrides.
|
|
14
|
+
* @param property - Numeric or color property to publish.
|
|
15
|
+
* @returns A shared value updated on style input and Provider selection changes.
|
|
16
|
+
* @throws For unresolved bindings, missing properties, or unsupported property values.
|
|
17
|
+
*/
|
|
18
|
+
export function useAnimatedStyleValue<
|
|
19
|
+
const property extends useAnimatedStyleValue.Property,
|
|
20
|
+
>(
|
|
21
|
+
appliedStyle: StyleSheet.StyleProp<object>,
|
|
22
|
+
property: property,
|
|
23
|
+
): Reanimated.SharedValue<useAnimatedStyleValue.Value<property>> {
|
|
24
|
+
const store = React.useContext(Store.context)
|
|
25
|
+
const read = React.useCallback(() => {
|
|
26
|
+
const resolved = NativeContext.resolve(appliedStyle, store?.getSnapshot())
|
|
27
|
+
const style = ReactNative.StyleSheet.flatten(
|
|
28
|
+
resolved as ReactNative.StyleProp<ReactNative.ViewStyle>,
|
|
29
|
+
)
|
|
30
|
+
const value = style?.[property as keyof ReactNative.ViewStyle]
|
|
31
|
+
const color = property === 'color' || property.endsWith('Color')
|
|
32
|
+
if (
|
|
33
|
+
color
|
|
34
|
+
? typeof value !== 'string' || ReactNative.processColor(value) == null
|
|
35
|
+
: typeof value !== 'number' || !Number.isFinite(value)
|
|
36
|
+
)
|
|
37
|
+
throw new Error(
|
|
38
|
+
`useAnimatedStyleValue requires a numeric or color value for ${property}.`,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
return value as useAnimatedStyleValue.Value<property>
|
|
42
|
+
}, [appliedStyle, property, store])
|
|
43
|
+
|
|
44
|
+
return useSelection(read, store)
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Properties supported by scalar style animation bindings. */
|
|
48
|
+
export declare namespace useAnimatedStyleValue {
|
|
49
|
+
/** Numeric native properties and native color properties. */
|
|
50
|
+
type Property = {
|
|
51
|
+
[key in keyof StyleSheet.NativeStyle]-?: key extends
|
|
52
|
+
| 'color'
|
|
53
|
+
| `${string}Color`
|
|
54
|
+
? key
|
|
55
|
+
: Extract<StyleSheet.NativeStyle[key], number> extends never
|
|
56
|
+
? never
|
|
57
|
+
: key
|
|
58
|
+
}[keyof StyleSheet.NativeStyle] &
|
|
59
|
+
string
|
|
60
|
+
/** Color strings or finite numeric selections, excluding layout strings. */
|
|
61
|
+
type Value<property extends Property> = property extends
|
|
62
|
+
| 'color'
|
|
63
|
+
| `${string}Color`
|
|
64
|
+
? string
|
|
65
|
+
: number
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Publishes compiled native variables without subscribing the component to React updates.
|
|
70
|
+
* @param variables - Statically linked variables from the owning configuration.
|
|
71
|
+
* @param select - Optional JS selector, with results compared using Object.is.
|
|
72
|
+
* @returns A shared value containing the selected serializable native values.
|
|
73
|
+
* @throws For a missing Provider, unsupported variable reads, or nonserializable selections.
|
|
74
|
+
*/
|
|
75
|
+
export function useAnimatedVars<const variables extends Vars.Definition>(
|
|
76
|
+
variables: variables,
|
|
77
|
+
select?: undefined,
|
|
78
|
+
): Reanimated.SharedValue<NativeVars.Values<Vars.Extract<variables>>>
|
|
79
|
+
/** Publishes a selected variable value to the UI thread. */
|
|
80
|
+
export function useAnimatedVars<
|
|
81
|
+
const variables extends Vars.Definition,
|
|
82
|
+
selected extends useAnimatedVars.Value,
|
|
83
|
+
>(
|
|
84
|
+
variables: variables,
|
|
85
|
+
select: (values: NativeVars.Values<Vars.Extract<variables>>) => selected,
|
|
86
|
+
): Reanimated.SharedValue<selected>
|
|
87
|
+
export function useAnimatedVars(
|
|
88
|
+
variables: Vars.Definition,
|
|
89
|
+
select: (values: never) => unknown = (values) => values,
|
|
90
|
+
) {
|
|
91
|
+
const store = React.useContext(Store.context)
|
|
92
|
+
if (!store) throw new Error('useAnimatedVars requires a Zyzz Provider.')
|
|
93
|
+
|
|
94
|
+
const read = React.useCallback(
|
|
95
|
+
() => select(NativeVars.read(variables, store.getSnapshot()) as never),
|
|
96
|
+
[select, store, variables],
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
return useSelection(read, store)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Serializable selections shared with animation worklets. */
|
|
103
|
+
export declare namespace useAnimatedVars {
|
|
104
|
+
/** Plain native values, arrays, and objects without functions or class instances. */
|
|
105
|
+
type Value =
|
|
106
|
+
| boolean
|
|
107
|
+
| null
|
|
108
|
+
| number
|
|
109
|
+
| readonly Value[]
|
|
110
|
+
| string
|
|
111
|
+
| undefined
|
|
112
|
+
| { readonly [key: string]: Value }
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function useSelection<value>(
|
|
116
|
+
read: () => value,
|
|
117
|
+
store: ReturnType<typeof Store.create> | undefined,
|
|
118
|
+
): Reanimated.SharedValue<value> {
|
|
119
|
+
const initial = read()
|
|
120
|
+
serializable(initial)
|
|
121
|
+
const previous = React.useRef(initial)
|
|
122
|
+
const shared = Reanimated.useSharedValue(initial)
|
|
123
|
+
|
|
124
|
+
React.useLayoutEffect(() => {
|
|
125
|
+
const update = () => {
|
|
126
|
+
const next = read()
|
|
127
|
+
if (Object.is(previous.current, next)) return
|
|
128
|
+
serializable(next)
|
|
129
|
+
shared.set(next)
|
|
130
|
+
previous.current = next
|
|
131
|
+
}
|
|
132
|
+
update()
|
|
133
|
+
return store?.subscribe(update)
|
|
134
|
+
}, [read, shared, store])
|
|
135
|
+
|
|
136
|
+
return shared
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
function serializable(value: unknown, ancestors = new Set<object>()): void {
|
|
140
|
+
if (value == null || typeof value === 'string' || typeof value === 'boolean')
|
|
141
|
+
return
|
|
142
|
+
if (typeof value === 'number' && Number.isFinite(value)) return
|
|
143
|
+
if (
|
|
144
|
+
typeof value !== 'object' ||
|
|
145
|
+
(Array.isArray(value)
|
|
146
|
+
? Object.getPrototypeOf(value) !== Array.prototype
|
|
147
|
+
: Object.getPrototypeOf(value) !== Object.prototype &&
|
|
148
|
+
Object.getPrototypeOf(value) !== null)
|
|
149
|
+
)
|
|
150
|
+
throw new Error(
|
|
151
|
+
'Animated selections require finite, serializable native values.',
|
|
152
|
+
)
|
|
153
|
+
|
|
154
|
+
if (ancestors.has(value))
|
|
155
|
+
throw new Error('Animated selections cannot contain cycles.')
|
|
156
|
+
if (Object.getOwnPropertySymbols(value).length)
|
|
157
|
+
throw new Error('Animated selections cannot contain symbol properties.')
|
|
158
|
+
|
|
159
|
+
ancestors.add(value)
|
|
160
|
+
for (const entry of Object.values(value)) serializable(entry, ancestors)
|
|
161
|
+
ancestors.delete(value)
|
|
162
|
+
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
/** Defers precompiled native selection until a
|
|
1
|
+
/** Defers precompiled native selection until a consumer supplies its scoped selection. @module */
|
|
2
2
|
import type * as Native from './Native.js'
|
|
3
|
+
import * as Media from './internal/NativeMedia.js'
|
|
3
4
|
|
|
4
5
|
const binding = Symbol('zyzz.native.context')
|
|
6
|
+
const dependency = Symbol('zyzz.native.dependency')
|
|
5
7
|
|
|
6
8
|
/** Render-local set and resolved appearance. */
|
|
7
9
|
export type Context = {
|
|
@@ -9,6 +11,8 @@ export type Context = {
|
|
|
9
11
|
readonly colorScheme: 'dark' | 'light'
|
|
10
12
|
/** Named compiled set; omission uses each configuration default. */
|
|
11
13
|
readonly set?: string | undefined
|
|
14
|
+
/** Logical window dimensions supplied by the native adapter. */
|
|
15
|
+
readonly viewport?: Media.Viewport | undefined
|
|
12
16
|
}
|
|
13
17
|
|
|
14
18
|
type Callable = (input: never) => Native.Props<object>
|
|
@@ -25,6 +29,9 @@ export function create<const tables extends Tables>(
|
|
|
25
29
|
Object.keys(tables).length === 1 && defaultVars === 'default'
|
|
26
30
|
? tables.default
|
|
27
31
|
: undefined
|
|
32
|
+
const selections = new Set(
|
|
33
|
+
Object.values(tables).flatMap((table) => [table.dark, table.light]),
|
|
34
|
+
)
|
|
28
35
|
|
|
29
36
|
function select(context: Context, input?: never) {
|
|
30
37
|
const set = context.set ?? defaultVars
|
|
@@ -32,22 +39,12 @@ export function create<const tables extends Tables>(
|
|
|
32
39
|
if (!table) throw new Error(`Unknown native set: ${set}.`)
|
|
33
40
|
return table[context.colorScheme](input!).style
|
|
34
41
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
const defaults = props()
|
|
43
|
-
Object.freeze(defaults.style)
|
|
44
|
-
Object.freeze(defaults)
|
|
45
|
-
const callable = (input?: never) =>
|
|
46
|
-
input === undefined ? defaults : props(input)
|
|
47
|
-
Object.defineProperty(callable, binding, {
|
|
48
|
-
value: select,
|
|
49
|
-
})
|
|
50
|
-
return callable as tables[keyof tables]['light']
|
|
42
|
+
return bind(select, (context) => {
|
|
43
|
+
const table = tables[context.set ?? defaultVars] ?? fallback
|
|
44
|
+
if (!table)
|
|
45
|
+
throw new Error(`Unknown native set: ${context.set ?? defaultVars}.`)
|
|
46
|
+
return selections.size === 1 ? [] : [table[context.colorScheme]]
|
|
47
|
+
}) as tables[keyof tables]['light']
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
/** Resolves generated bindings and arrays while preserving caller-owned native objects. */
|
|
@@ -72,3 +69,77 @@ export function resolve(
|
|
|
72
69
|
return (...args: unknown[]) => resolve(value(...args), context)
|
|
73
70
|
return value
|
|
74
71
|
}
|
|
72
|
+
|
|
73
|
+
/** Selects a precompiled media alternative before applying its scoped styling. */
|
|
74
|
+
export function responsive<
|
|
75
|
+
const profiles extends Readonly<Record<string, Callable>>,
|
|
76
|
+
>(
|
|
77
|
+
queries: readonly Media.Query[],
|
|
78
|
+
profiles: profiles,
|
|
79
|
+
): profiles[keyof profiles] {
|
|
80
|
+
return bind(
|
|
81
|
+
(context, input) => {
|
|
82
|
+
const profile = profiles[Media.select(queries, context.viewport)]
|
|
83
|
+
if (!profile) throw new Error('Native media alternative is missing.')
|
|
84
|
+
return resolve(profile, context, input)
|
|
85
|
+
},
|
|
86
|
+
(context) => {
|
|
87
|
+
const profile = profiles[Media.select(queries, context.viewport)]
|
|
88
|
+
return [profile, ...key(profile, context)]
|
|
89
|
+
},
|
|
90
|
+
) as unknown as profiles[keyof profiles]
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Retains a compiled application and its input until a view selects its context. */
|
|
94
|
+
export function application(value: unknown, input?: unknown): unknown {
|
|
95
|
+
return {
|
|
96
|
+
[binding]: (context: Context) => resolve(value, context, input),
|
|
97
|
+
[dependency]: (context: Context) => [
|
|
98
|
+
...key(value, context),
|
|
99
|
+
...key(input, context),
|
|
100
|
+
],
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Returns compiler-owned alternatives consumed by a native style application. */
|
|
105
|
+
export function key(value: unknown, context: Context): readonly unknown[] {
|
|
106
|
+
if (Array.isArray(value)) return value.flatMap((entry) => key(entry, context))
|
|
107
|
+
if (
|
|
108
|
+
value &&
|
|
109
|
+
(typeof value === 'object' || typeof value === 'function') &&
|
|
110
|
+
dependency in value
|
|
111
|
+
) {
|
|
112
|
+
const read = value[dependency]
|
|
113
|
+
if (typeof read === 'function') return read(context)
|
|
114
|
+
}
|
|
115
|
+
if (value && typeof value === 'object' && 'style' in value)
|
|
116
|
+
return key(value.style, context)
|
|
117
|
+
return []
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function bind(
|
|
121
|
+
select: (context: Context, input?: never) => unknown,
|
|
122
|
+
read: (context: Context) => readonly unknown[],
|
|
123
|
+
) {
|
|
124
|
+
function props(input?: never) {
|
|
125
|
+
return {
|
|
126
|
+
style: {
|
|
127
|
+
[binding]: (context: Context) => select(context, input),
|
|
128
|
+
[dependency]: (context: Context) => [
|
|
129
|
+
...read(context),
|
|
130
|
+
...key(input, context),
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const defaults = props()
|
|
136
|
+
Object.freeze(defaults.style)
|
|
137
|
+
Object.freeze(defaults)
|
|
138
|
+
const callable = (input?: never) =>
|
|
139
|
+
input === undefined ? defaults : props(input)
|
|
140
|
+
Object.defineProperties(callable, {
|
|
141
|
+
[binding]: { value: select },
|
|
142
|
+
[dependency]: { value: read },
|
|
143
|
+
})
|
|
144
|
+
return callable
|
|
145
|
+
}
|