zyzz 0.0.21 → 0.0.23
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 +217 -15
- 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 +107 -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/Dynamic.d.ts.map +1 -1
- package/dist/compiler/internal/Dynamic.js +3 -0
- package/dist/compiler/internal/Dynamic.js.map +1 -1
- package/dist/compiler/internal/Expression.js +2 -2
- package/dist/compiler/internal/Expression.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 +62 -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 +160 -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 +24 -1
- package/dist/compiler/internal/Themes.d.ts.map +1 -1
- package/dist/compiler/internal/Themes.js +120 -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 +188 -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 +8 -3
- package/dist/react-native/StyleSheet.d.ts.map +1 -1
- package/dist/react-native/StyleSheet.js +25 -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 +218 -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 +16 -0
- package/dist/react-native/internal/Scalar.d.ts.map +1 -1
- package/dist/react-native/internal/Scalar.js +62 -4
- 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/Styles.d.ts +19 -0
- package/dist/react-native/internal/Styles.d.ts.map +1 -0
- package/dist/react-native/internal/Styles.js +35 -0
- package/dist/react-native/internal/Styles.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 +102 -14
- package/dist/react-native/react.d.ts.map +1 -1
- package/dist/react-native/react.js +86 -18
- 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 +37 -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 +319 -33
- package/src/babel/index.ts +21 -3
- package/src/compiler/Graph.ts +126 -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/Dynamic.ts +4 -0
- package/src/compiler/internal/Expression.ts +2 -2
- package/src/compiler/internal/NativeBindings.ts +99 -15
- package/src/compiler/internal/NativeMedia.ts +342 -0
- package/src/compiler/internal/NativeVars.ts +231 -0
- package/src/compiler/internal/PackedStyles.ts +4 -0
- package/src/compiler/internal/Themes.ts +193 -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 +250 -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 +56 -49
- 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 +297 -0
- package/src/react-native/internal/NativeZyzz.ts +20 -0
- package/src/react-native/internal/Scalar.ts +86 -4
- package/src/react-native/internal/Store.ts +78 -0
- package/src/react-native/internal/Styles.ts +77 -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 +218 -26
- package/src/react-native/reanimated.ts +162 -0
- package/src/runtime/NativeContext.ts +88 -17
- package/src/runtime/NativeDynamic.ts +42 -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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/** Converts portable scalar values without source parsing or device state. @module */
|
|
2
2
|
import * as Color from './Color.js'
|
|
3
|
+
import * as Calculation from './Calculation.js'
|
|
3
4
|
|
|
4
5
|
/** Portable property domains shared by static and dynamic native conversion. */
|
|
5
6
|
export const properties = {
|
|
@@ -47,6 +48,7 @@ export const properties = {
|
|
|
47
48
|
columnGap: 'length',
|
|
48
49
|
direction: ['ltr', 'rtl'],
|
|
49
50
|
display: ['contents', 'flex', 'none'],
|
|
51
|
+
flex: 'flex',
|
|
50
52
|
flexBasis: 'size',
|
|
51
53
|
flexDirection: ['column', 'column-reverse', 'row', 'row-reverse'],
|
|
52
54
|
flexGrow: 'number',
|
|
@@ -59,6 +61,7 @@ export const properties = {
|
|
|
59
61
|
fontWeight: 'weight',
|
|
60
62
|
gap: 'length',
|
|
61
63
|
height: 'size',
|
|
64
|
+
inset: 'boxOffset',
|
|
62
65
|
justifyContent: [
|
|
63
66
|
'center',
|
|
64
67
|
'flex-end',
|
|
@@ -205,18 +208,87 @@ export function convert(
|
|
|
205
208
|
return value
|
|
206
209
|
fail('unsupported_value', 'Invalid native percentage.', path)
|
|
207
210
|
}
|
|
208
|
-
if (kind === '
|
|
211
|
+
if (kind === 'flex') {
|
|
212
|
+
flex(value, options, path)
|
|
213
|
+
return 0
|
|
214
|
+
}
|
|
215
|
+
if (kind === 'box' || kind === 'boxOffset' || kind === 'boxSigned') {
|
|
209
216
|
const values =
|
|
210
|
-
typeof value === 'string' ?
|
|
217
|
+
typeof value === 'string' ? Calculation.parts(value) : [value]
|
|
211
218
|
if (!values.length || values.length > 4)
|
|
212
219
|
fail('unsupported_value', 'Use one to four scalar lengths.', path)
|
|
213
220
|
for (const value of values)
|
|
214
|
-
|
|
221
|
+
if (kind === 'boxOffset') convert('offset', value, options, path)
|
|
222
|
+
else length(value, options, kind === 'boxSigned', path)
|
|
215
223
|
return 0
|
|
216
224
|
}
|
|
217
225
|
return length(value, options, kind === 'signed' || kind === 'offset', path)
|
|
218
226
|
}
|
|
219
227
|
|
|
228
|
+
/**
|
|
229
|
+
* Expands the CSS `flex` shorthand to native longhands with CSS semantics.
|
|
230
|
+
* Omitted factors default to 1 and an omitted basis to 0, unlike the React Native `flex` prop.
|
|
231
|
+
*/
|
|
232
|
+
export function flex(
|
|
233
|
+
value: number | string,
|
|
234
|
+
options: Options,
|
|
235
|
+
path: readonly string[],
|
|
236
|
+
): flex.ReturnType {
|
|
237
|
+
const keyword = typeof value === 'string' ? value.trim() : undefined
|
|
238
|
+
if (keyword === 'none')
|
|
239
|
+
return { flexBasis: 'auto', flexGrow: 0, flexShrink: 0 }
|
|
240
|
+
if (keyword === 'auto')
|
|
241
|
+
return { flexBasis: 'auto', flexGrow: 1, flexShrink: 1 }
|
|
242
|
+
if (keyword === 'initial')
|
|
243
|
+
return { flexBasis: 'auto', flexGrow: 0, flexShrink: 1 }
|
|
244
|
+
|
|
245
|
+
const parts = typeof value === 'string' ? Calculation.parts(value) : [value]
|
|
246
|
+
const kinds: ('basis' | 'factor')[] = []
|
|
247
|
+
for (const part of parts) {
|
|
248
|
+
const numeric =
|
|
249
|
+
typeof part === 'number' ||
|
|
250
|
+
/^[+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?$/.test(part)
|
|
251
|
+
// A unitless zero after two factors is the basis, as in CSS.
|
|
252
|
+
const basis =
|
|
253
|
+
!numeric || (kinds.join(' ') === 'factor factor' && Number(part) === 0)
|
|
254
|
+
kinds.push(basis ? 'basis' : 'factor')
|
|
255
|
+
}
|
|
256
|
+
// Factors stay adjacent, and the basis may precede or follow them.
|
|
257
|
+
if (
|
|
258
|
+
![
|
|
259
|
+
'basis',
|
|
260
|
+
'basis factor',
|
|
261
|
+
'basis factor factor',
|
|
262
|
+
'factor',
|
|
263
|
+
'factor basis',
|
|
264
|
+
'factor factor',
|
|
265
|
+
'factor factor basis',
|
|
266
|
+
].includes(kinds.join(' '))
|
|
267
|
+
)
|
|
268
|
+
fail('unsupported_value', 'Invalid flex shorthand.', path)
|
|
269
|
+
|
|
270
|
+
const factors = parts
|
|
271
|
+
.filter((_, index) => kinds[index] === 'factor')
|
|
272
|
+
.map((part) => convert('number', Number(part), options, path) as number)
|
|
273
|
+
const basis = parts.find((_, index) => kinds[index] === 'basis')
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
flexBasis: basis === undefined ? 0 : convert('size', basis, options, path),
|
|
277
|
+
flexGrow: factors[0] ?? 1,
|
|
278
|
+
flexShrink: factors[1] ?? 1,
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Native longhands produced by the `flex` shorthand. */
|
|
283
|
+
export declare namespace flex {
|
|
284
|
+
/** Grow and shrink factors with a converted basis. */
|
|
285
|
+
type ReturnType = {
|
|
286
|
+
readonly flexBasis: number | string
|
|
287
|
+
readonly flexGrow: number
|
|
288
|
+
readonly flexShrink: number
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
220
292
|
/** Converts a portable length to logical units. */
|
|
221
293
|
export function length(
|
|
222
294
|
value: number | string,
|
|
@@ -225,9 +297,19 @@ export function length(
|
|
|
225
297
|
path: readonly string[],
|
|
226
298
|
): number {
|
|
227
299
|
if (value === 0 || value === '0') return 0
|
|
300
|
+
if (typeof value === 'string' && /^\s*calc\(/i.test(value)) {
|
|
301
|
+
const result = Calculation.length(value.trim(), options)
|
|
302
|
+
if (!signed && result < 0)
|
|
303
|
+
fail(
|
|
304
|
+
'unsupported_value',
|
|
305
|
+
'Converted length is outside the native property domain.',
|
|
306
|
+
path,
|
|
307
|
+
)
|
|
308
|
+
return result
|
|
309
|
+
}
|
|
228
310
|
const match =
|
|
229
311
|
typeof value === 'string' &&
|
|
230
|
-
/^([+-]?(?:\d+(?:\.\d+)?|\.\d+))(px|rem)$/.exec(value)
|
|
312
|
+
/^([+-]?(?:\d+(?:\.\d+)?|\.\d+)(?:[eE][+-]?\d+)?)(px|rem)$/.exec(value)
|
|
231
313
|
if (!match)
|
|
232
314
|
fail(
|
|
233
315
|
'unsupported_value',
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/** Owns scoped React subscriptions and committed native style readers. @module */
|
|
2
|
+
import type * as NativeContext from '../../runtime/NativeContext.js'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
|
|
5
|
+
/** Internal view update payload shared with the native bridge. */
|
|
6
|
+
export type Patch = {
|
|
7
|
+
/** Runtime-local mounted view identifier. */
|
|
8
|
+
readonly id: number
|
|
9
|
+
/** Processed native style properties. */
|
|
10
|
+
readonly props: Record<string, unknown>
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type Selection = {
|
|
14
|
+
readonly commit: () => void
|
|
15
|
+
readonly patch?: Patch | undefined
|
|
16
|
+
}
|
|
17
|
+
type Reader = (value: NativeContext.Context) => Selection
|
|
18
|
+
type Writer = (patches: readonly Patch[]) => void
|
|
19
|
+
|
|
20
|
+
/** Nearest configuration-owned selection. */
|
|
21
|
+
export const context = React.createContext<
|
|
22
|
+
ReturnType<typeof create> | undefined
|
|
23
|
+
>(undefined)
|
|
24
|
+
|
|
25
|
+
/** Creates subscriptions owned by a Provider or a provider-free style consumer. */
|
|
26
|
+
export function create(initial: NativeContext.Context) {
|
|
27
|
+
let snapshot = Object.freeze(initial)
|
|
28
|
+
const bindings = new Map<Reader, Writer>()
|
|
29
|
+
const listeners = new Set<() => void>()
|
|
30
|
+
|
|
31
|
+
return {
|
|
32
|
+
bind(read: Reader, write: Writer) {
|
|
33
|
+
bindings.set(read, write)
|
|
34
|
+
return () => {
|
|
35
|
+
bindings.delete(read)
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
getSnapshot: () => snapshot,
|
|
39
|
+
subscribe(listener: () => void) {
|
|
40
|
+
const entry = () => listener()
|
|
41
|
+
listeners.add(entry)
|
|
42
|
+
return () => {
|
|
43
|
+
listeners.delete(entry)
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
update(value: NativeContext.Context) {
|
|
47
|
+
if (
|
|
48
|
+
snapshot.colorScheme === value.colorScheme &&
|
|
49
|
+
snapshot.set === value.set &&
|
|
50
|
+
snapshot.viewport?.height === value.viewport?.height &&
|
|
51
|
+
snapshot.viewport?.width === value.viewport?.width
|
|
52
|
+
)
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
// Resolve every binding before applying a scope change that can fail.
|
|
56
|
+
const selections: Selection[] = []
|
|
57
|
+
const batches = new Map<Writer, Patch[]>()
|
|
58
|
+
for (const [read, write] of bindings) {
|
|
59
|
+
const selection = read(value)
|
|
60
|
+
selections.push(selection)
|
|
61
|
+
if (!selection.patch) continue
|
|
62
|
+
let batch = batches.get(write)
|
|
63
|
+
if (!batch) {
|
|
64
|
+
batch = []
|
|
65
|
+
batches.set(write, batch)
|
|
66
|
+
}
|
|
67
|
+
batch.push(selection.patch)
|
|
68
|
+
}
|
|
69
|
+
for (const [write, patches] of batches) write(patches)
|
|
70
|
+
|
|
71
|
+
snapshot = Object.freeze(value)
|
|
72
|
+
for (const selection of selections) selection.commit()
|
|
73
|
+
// Subscriptions added during notification wait for the next change.
|
|
74
|
+
for (const listener of Array.from(listeners))
|
|
75
|
+
if (listeners.has(listener)) listener()
|
|
76
|
+
},
|
|
77
|
+
}
|
|
78
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/** Resolves compiled style applications for consumers outside native view bindings. @module */
|
|
2
|
+
import * as NativeContext from '../../runtime/NativeContext.js'
|
|
3
|
+
import * as React from 'react'
|
|
4
|
+
import type { useStyles } from '../react.js'
|
|
5
|
+
import type * as Store from './Store.js'
|
|
6
|
+
|
|
7
|
+
/** Subscribes to a selection and returns its style resolvers. */
|
|
8
|
+
export function use(
|
|
9
|
+
store: ReturnType<typeof Store.create>,
|
|
10
|
+
): useStyles.ReturnType {
|
|
11
|
+
const value = React.useSyncExternalStore(
|
|
12
|
+
store.subscribe,
|
|
13
|
+
store.getSnapshot,
|
|
14
|
+
store.getSnapshot,
|
|
15
|
+
)
|
|
16
|
+
return React.useMemo(
|
|
17
|
+
() => ({
|
|
18
|
+
props: (props) =>
|
|
19
|
+
props && Object.hasOwn(props, 'style')
|
|
20
|
+
? { ...props, style: NativeContext.resolve(props.style, value) }
|
|
21
|
+
: props,
|
|
22
|
+
style: <style>(style: style, input?: unknown) =>
|
|
23
|
+
NativeContext.resolve(style, value, input) as useStyles.Style<style>,
|
|
24
|
+
}),
|
|
25
|
+
[value],
|
|
26
|
+
)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Wraps a component so its style props resolve through an entrypoint's selection hook.
|
|
31
|
+
* @throws For invalid style prop names.
|
|
32
|
+
*/
|
|
33
|
+
export function wrap<const component extends React.ElementType>(
|
|
34
|
+
Component: component,
|
|
35
|
+
options: wrap.Options,
|
|
36
|
+
useStyles: () => useStyles.ReturnType,
|
|
37
|
+
) {
|
|
38
|
+
const additional = options.styleProps ?? []
|
|
39
|
+
if (
|
|
40
|
+
!Array.isArray(additional) ||
|
|
41
|
+
additional.some(
|
|
42
|
+
(name) =>
|
|
43
|
+
typeof name !== 'string' || !name || name === 'key' || name === 'ref',
|
|
44
|
+
)
|
|
45
|
+
)
|
|
46
|
+
throw new Error(
|
|
47
|
+
'withStyles requires style prop names excluding key and ref.',
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
const names = [...new Set(['style', 'contentContainerStyle', ...additional])]
|
|
51
|
+
const Wrapped = React.forwardRef<
|
|
52
|
+
React.ComponentRef<component>,
|
|
53
|
+
React.ComponentPropsWithoutRef<component>
|
|
54
|
+
>((props, ref) => {
|
|
55
|
+
const selected = useStyles()
|
|
56
|
+
const resolved: Record<string, unknown> = { ...props, ref }
|
|
57
|
+
for (const name of names)
|
|
58
|
+
if (Object.hasOwn(props, name))
|
|
59
|
+
resolved[name] = selected.style(
|
|
60
|
+
(props as Record<string, unknown>)[name],
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return React.createElement(Component, resolved)
|
|
64
|
+
})
|
|
65
|
+
Wrapped.displayName = `withStyles(${typeof Component === 'string' ? Component : Component.displayName || Component.name || 'Component'})`
|
|
66
|
+
|
|
67
|
+
return Wrapped
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Style-bearing prop names accepted by a wrapper. */
|
|
71
|
+
export declare namespace wrap {
|
|
72
|
+
/** Entrypoints narrow these names to the wrapped component's props. */
|
|
73
|
+
type Options = {
|
|
74
|
+
/** Additional style props declared by the wrapped component. */
|
|
75
|
+
readonly styleProps?: readonly string[] | undefined
|
|
76
|
+
}
|
|
77
|
+
}
|
|
@@ -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
|
|
1
|
+
/** React subscriptions for compiled native styles and variable values. @module */
|
|
2
|
+
import * as Config from '../Config.js'
|
|
3
|
+
import type * as NativeContext from '../runtime/NativeContext.js'
|
|
4
|
+
import * as NativeVars from '../runtime/NativeVars.js'
|
|
2
5
|
import * as React from 'react'
|
|
3
|
-
import * as
|
|
6
|
+
import type * as Vars from '../Vars.js'
|
|
7
|
+
import * as Store from './internal/Store.js'
|
|
8
|
+
import * as Styles from './internal/Styles.js'
|
|
9
|
+
import * as Viewport from './internal/Viewport.js'
|
|
4
10
|
|
|
5
|
-
|
|
11
|
+
/** Creates native authoring helpers and a Provider typed to the configured variables. */
|
|
12
|
+
export function defineConfig<const options extends Config.create.Options = {}>(
|
|
13
|
+
options: options & Parameters<typeof Config.create<options>>[0] = {} as never,
|
|
14
|
+
): defineConfig.ReturnType<options> {
|
|
15
|
+
const config = Config.create<options>(options)
|
|
16
|
+
const defaultVars = (options as Config.VariableOptions).defaultVars
|
|
17
|
+
const names =
|
|
18
|
+
defaultVars === undefined
|
|
19
|
+
? undefined
|
|
20
|
+
: new Set(Object.keys((options as Config.VariableOptions).vars))
|
|
6
21
|
|
|
7
|
-
|
|
22
|
+
function BoundProvider(props: defineConfig.ProviderProps<options>) {
|
|
23
|
+
if (props.vars !== undefined && !names?.has(props.vars))
|
|
24
|
+
throw new Error(`Unknown native vars: ${props.vars}.`)
|
|
25
|
+
|
|
26
|
+
return React.createElement(Provider, {
|
|
27
|
+
...props,
|
|
28
|
+
vars: props.vars ?? defaultVars,
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return Object.freeze({
|
|
33
|
+
...config,
|
|
34
|
+
Provider: BoundProvider,
|
|
35
|
+
}) as defineConfig.ReturnType<options>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Native configuration helpers and inferred Provider props. */
|
|
39
|
+
export declare namespace defineConfig {
|
|
40
|
+
/** Resolved scheme and variable names from the owning configuration. */
|
|
41
|
+
type ProviderProps<options extends Config.create.Options> = Omit<
|
|
42
|
+
Provider.Props,
|
|
43
|
+
'vars'
|
|
44
|
+
> & {
|
|
45
|
+
/** Selected variables. Omission uses the owning configuration's default. */
|
|
46
|
+
readonly vars?:
|
|
47
|
+
| (options extends { defaultVars: string; vars: infer catalog }
|
|
48
|
+
? Extract<keyof catalog, string>
|
|
49
|
+
: never)
|
|
50
|
+
| undefined
|
|
51
|
+
}
|
|
52
|
+
/** Existing authoring helpers plus a configuration-scoped Provider. */
|
|
53
|
+
type ReturnType<options extends Config.create.Options = {}> =
|
|
54
|
+
Config.create.ReturnType<options> & {
|
|
55
|
+
/** Provides this configuration's typed selection to native consumers. */
|
|
56
|
+
readonly Provider: React.FunctionComponent<ProviderProps<options>>
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** Supplies selected variables, appearance, and adapter measurements to this subtree. */
|
|
8
61
|
export function Provider(props: Provider.Props) {
|
|
62
|
+
if (Object.hasOwn(props, 'set'))
|
|
63
|
+
throw new Error('Provider uses vars instead of set.')
|
|
9
64
|
if (
|
|
10
65
|
(props.colorScheme !== 'light' && props.colorScheme !== 'dark') ||
|
|
11
|
-
(props.
|
|
12
|
-
(typeof props.
|
|
66
|
+
(props.vars !== undefined &&
|
|
67
|
+
(typeof props.vars !== 'string' || !props.vars.trim()))
|
|
13
68
|
)
|
|
14
69
|
throw new Error(
|
|
15
|
-
'Native appearance requires a resolved light/dark scheme and a nonempty
|
|
70
|
+
'Native appearance requires a resolved light/dark scheme and a nonempty vars name.',
|
|
16
71
|
)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
72
|
+
|
|
73
|
+
const viewport = React.useContext(Viewport.context)
|
|
74
|
+
const [store] = React.useState(() =>
|
|
75
|
+
Store.create({ colorScheme: props.colorScheme, set: props.vars, viewport }),
|
|
20
76
|
)
|
|
21
|
-
|
|
77
|
+
const [, publish] = React.useReducer((version: number) => version + 1, 0)
|
|
78
|
+
const committed = React.useRef(props.children)
|
|
79
|
+
const snapshot = store.getSnapshot()
|
|
80
|
+
const pending =
|
|
81
|
+
snapshot.colorScheme !== props.colorScheme ||
|
|
82
|
+
snapshot.set !== props.vars ||
|
|
83
|
+
snapshot.viewport?.width !== viewport?.width ||
|
|
84
|
+
snapshot.viewport?.height !== viewport?.height
|
|
85
|
+
const children = pending ? committed.current : props.children
|
|
86
|
+
React.useLayoutEffect(() => {
|
|
87
|
+
committed.current = children
|
|
88
|
+
if (!pending) return
|
|
89
|
+
// Keep the committed subtree until its selection is published. This avoids
|
|
90
|
+
// rendering new application props with the previous store snapshot, without
|
|
91
|
+
// mutating an external store during a potentially abandoned React render.
|
|
92
|
+
store.update({ colorScheme: props.colorScheme, set: props.vars, viewport })
|
|
93
|
+
publish()
|
|
94
|
+
}, [children, pending, props.colorScheme, props.vars, store, viewport])
|
|
95
|
+
|
|
96
|
+
return React.createElement(Store.context.Provider, { value: store }, children)
|
|
22
97
|
}
|
|
23
98
|
|
|
24
|
-
/** Application boundary
|
|
99
|
+
/** Application boundary for native variable selection. */
|
|
25
100
|
export declare namespace Provider {
|
|
26
|
-
/**
|
|
27
|
-
type Props =
|
|
28
|
-
/** Components that consume compiled native
|
|
101
|
+
/** Resolved appearance and a configuration-relative variable name. */
|
|
102
|
+
type Props = {
|
|
103
|
+
/** Components that consume compiled native styling or values. */
|
|
29
104
|
readonly children?: React.ReactNode | undefined
|
|
105
|
+
/** Resolved device scheme or an application override. */
|
|
106
|
+
readonly colorScheme: 'dark' | 'light'
|
|
107
|
+
/** Selected variables. Omission uses each configuration's default. */
|
|
108
|
+
readonly vars?: string | undefined
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Compiler-inserted subscription for resolving native style applications.
|
|
114
|
+
* Outside a Provider, selections use default variables and the light scheme.
|
|
115
|
+
*/
|
|
116
|
+
export function useStyles(): useStyles.ReturnType {
|
|
117
|
+
const [fallback] = React.useState(() =>
|
|
118
|
+
Store.create({ colorScheme: 'light' }),
|
|
119
|
+
)
|
|
120
|
+
return Styles.use(React.useContext(Store.context) ?? fallback)
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Resolver types for Provider-selected native styles. */
|
|
124
|
+
export declare namespace useStyles {
|
|
125
|
+
/** Resolvers bound to the nearest Provider selection. */
|
|
126
|
+
type ReturnType = {
|
|
127
|
+
/** Resolves the `style` prop of applied props and preserves other props. */
|
|
128
|
+
readonly props: <
|
|
129
|
+
props extends Readonly<Record<string, unknown>> | null | undefined,
|
|
130
|
+
>(
|
|
131
|
+
props: props,
|
|
132
|
+
) => props
|
|
133
|
+
/** Resolves an applied style, native style, style array, or style callback. */
|
|
134
|
+
readonly style: <style>(style: style, input?: unknown) => Style<style>
|
|
30
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Resolved style type. Caller-owned values keep their types. Native applications
|
|
138
|
+
* always carry `style`, so an applied style drops the `undefined` allowed by the shared props type.
|
|
139
|
+
*/
|
|
140
|
+
type Style<style> = [
|
|
141
|
+
style extends object ? (string extends keyof style ? style : never) : never,
|
|
142
|
+
] extends [never]
|
|
143
|
+
? style
|
|
144
|
+
: Exclude<style, undefined>
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** Compiler fallback for native view bindings when no native adapter is installed. */
|
|
148
|
+
export function useNativeStyles() {
|
|
149
|
+
const selected = useStyles()
|
|
150
|
+
return { ...selected, view: selected.props }
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Reads readonly native variables using the nearest Provider's selection.
|
|
155
|
+
* @throws For missing providers, uncompiled definitions, or unsupported field reads.
|
|
156
|
+
*/
|
|
157
|
+
export function useVars<const variables extends Vars.Definition>(
|
|
158
|
+
variables: variables,
|
|
159
|
+
select?: undefined,
|
|
160
|
+
): NativeVars.Values<Vars.Extract<variables>>
|
|
161
|
+
/**
|
|
162
|
+
* Subscribes to a selection, comparing results with Object.is.
|
|
163
|
+
* @throws For invalid variable selection or unsupported field reads.
|
|
164
|
+
*/
|
|
165
|
+
export function useVars<const variables extends Vars.Definition, selected>(
|
|
166
|
+
variables: variables,
|
|
167
|
+
select: (values: NativeVars.Values<Vars.Extract<variables>>) => selected,
|
|
168
|
+
): selected
|
|
169
|
+
export function useVars(
|
|
170
|
+
variables: Vars.Definition,
|
|
171
|
+
select: (values: never) => unknown = (values) => values,
|
|
172
|
+
) {
|
|
173
|
+
const store = React.useContext(Store.context)
|
|
174
|
+
if (!store) throw new Error('useVars requires a Zyzz Provider.')
|
|
175
|
+
|
|
176
|
+
const read = React.useMemo(() => {
|
|
177
|
+
let previous: NativeContext.Context | undefined
|
|
178
|
+
let selected: unknown
|
|
179
|
+
return () => {
|
|
180
|
+
const snapshot = store.getSnapshot()
|
|
181
|
+
if (snapshot !== previous) {
|
|
182
|
+
const next = select(NativeVars.read(variables, snapshot) as never)
|
|
183
|
+
if (!previous || !Object.is(selected, next)) selected = next
|
|
184
|
+
previous = snapshot
|
|
185
|
+
}
|
|
186
|
+
return selected
|
|
187
|
+
}
|
|
188
|
+
}, [select, store, variables])
|
|
189
|
+
|
|
190
|
+
return React.useSyncExternalStore(store.subscribe, read, read)
|
|
31
191
|
}
|
|
32
192
|
|
|
33
|
-
/**
|
|
34
|
-
|
|
35
|
-
|
|
193
|
+
/**
|
|
194
|
+
* Resolves compiled style props for function components using React updates.
|
|
195
|
+
* @param Component - Function, memo, or ref-forwarding component receiving native styles.
|
|
196
|
+
* @param options - Additional style-bearing prop names.
|
|
197
|
+
* @returns A component with the original call signature and ref. Type parameters remain when `styleProps` is omitted.
|
|
198
|
+
* @throws For invalid style prop names.
|
|
199
|
+
*/
|
|
200
|
+
export function withStyles<
|
|
201
|
+
props extends object,
|
|
202
|
+
result extends React.ReactNode,
|
|
203
|
+
>(
|
|
204
|
+
Component: (props: props) => result,
|
|
205
|
+
options?: NoInfer<withStyles.Options<(props: props) => result>>,
|
|
206
|
+
): (props: props) => result
|
|
207
|
+
/**
|
|
208
|
+
* Resolves compiled style props for class and host components using React updates.
|
|
209
|
+
* @param Component - Class component or host element type receiving native styles.
|
|
210
|
+
* @param options - Additional style-bearing prop names.
|
|
211
|
+
* @returns A component preserving the original props and instance ref.
|
|
212
|
+
* @throws For invalid style prop names.
|
|
213
|
+
*/
|
|
214
|
+
export function withStyles<const component extends React.ElementType>(
|
|
215
|
+
Component: component,
|
|
216
|
+
options?: withStyles.Options<component>,
|
|
217
|
+
): React.ForwardRefExoticComponent<React.ComponentPropsWithRef<component>>
|
|
218
|
+
export function withStyles(
|
|
219
|
+
Component: React.ElementType,
|
|
220
|
+
options: withStyles.Options<
|
|
221
|
+
(props: Readonly<Record<string, unknown>>) => React.ReactNode
|
|
222
|
+
> = {},
|
|
223
|
+
): React.ElementType {
|
|
224
|
+
return Styles.wrap(Component, options, useStyles)
|
|
36
225
|
}
|
|
37
226
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
227
|
+
/** Style-bearing component properties resolved by the wrapper. */
|
|
228
|
+
export declare namespace withStyles {
|
|
229
|
+
/** Additional names are resolved alongside style and contentContainerStyle. */
|
|
230
|
+
type Options<component extends React.ElementType> = {
|
|
231
|
+
/** Additional style props declared by the wrapped component. */
|
|
232
|
+
readonly styleProps?:
|
|
233
|
+
| readonly Exclude<
|
|
234
|
+
Extract<keyof React.ComponentProps<component>, string>,
|
|
235
|
+
'key' | 'ref'
|
|
236
|
+
>[]
|
|
237
|
+
| undefined
|
|
46
238
|
}
|
|
47
239
|
}
|