@hanzogui/static 7.3.0 → 8.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/check-dep-versions.cjs +1 -1
- package/dist/checkDeps.cjs +10 -10
- package/dist/constants.cjs +2 -2
- package/dist/exports.cjs +2 -0
- package/dist/extractor/bundle.cjs +14 -4
- package/dist/extractor/bundleConfig.cjs +40 -27
- package/dist/extractor/concatClassName.cjs +40 -11
- package/dist/extractor/createExtractor.cjs +137 -30
- package/dist/extractor/extractHelpers.cjs +1 -1
- package/dist/extractor/extractMediaStyle.cjs +5 -5
- package/dist/extractor/extractToClassNames.cjs +52 -4
- package/dist/extractor/extractToNative.cjs +16 -8
- package/dist/extractor/getPrefixLogs.cjs +1 -1
- package/dist/extractor/getStaticBindingsForScope.cjs +2 -2
- package/dist/extractor/loadGui.cjs +52 -46
- package/dist/extractor/regenerateConfig.cjs +17 -17
- package/dist/extractor/watchGuiConfig.cjs +9 -9
- package/dist/getPragmaOptions.cjs +4 -4
- package/dist/registerRequire.cjs +17 -16
- package/package.json +22 -24
- package/src/check-dep-versions.ts +1 -1
- package/src/checkDeps.ts +25 -25
- package/src/constants.ts +2 -2
- package/src/exports.ts +1 -0
- package/src/extractor/bundle.ts +35 -6
- package/src/extractor/bundleConfig.ts +48 -28
- package/src/extractor/concatClassName.ts +37 -20
- package/src/extractor/createExtractor.ts +256 -36
- package/src/extractor/extractHelpers.ts +2 -2
- package/src/extractor/extractMediaStyle.ts +5 -5
- package/src/extractor/extractToClassNames.ts +109 -7
- package/src/extractor/extractToNative.ts +27 -10
- package/src/extractor/getPrefixLogs.ts +1 -1
- package/src/extractor/getStaticBindingsForScope.ts +2 -2
- package/src/extractor/loadGui.ts +66 -51
- package/src/extractor/regenerateConfig.ts +17 -17
- package/src/extractor/watchGuiConfig.ts +14 -9
- package/src/getPragmaOptions.ts +4 -4
- package/src/registerRequire.ts +32 -19
- package/types/constants.d.ts.map +1 -1
- package/types/exports.d.ts +1 -0
- package/types/exports.d.ts.map +1 -1
- package/types/extractor/bundle.d.ts.map +1 -1
- package/types/extractor/bundleConfig.d.ts +1 -1
- package/types/extractor/bundleConfig.d.ts.map +1 -1
- package/types/extractor/createExtractor.d.ts.map +1 -1
- package/types/extractor/extractMediaStyle.d.ts +1 -1
- package/types/extractor/extractMediaStyle.d.ts.map +1 -1
- package/types/extractor/extractToClassNames.d.ts.map +1 -1
- package/types/extractor/extractToNative.d.ts.map +1 -1
- package/types/extractor/loadGui.d.ts +5 -5
- package/types/extractor/loadGui.d.ts.map +1 -1
- package/types/extractor/regenerateConfig.d.ts +3 -3
- package/types/extractor/regenerateConfig.d.ts.map +1 -1
- package/types/extractor/watchGuiConfig.d.ts +1 -1
- package/types/extractor/watchGuiConfig.d.ts.map +1 -1
- package/types/registerRequire.d.ts +1 -1
- package/types/registerRequire.d.ts.map +1 -1
- package/LICENSE +0 -42
|
@@ -76,6 +76,43 @@ function isFullyDisabled(props: GuiOptions) {
|
|
|
76
76
|
return props.disableExtraction && props.disableDebugAttr
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
+
// Walk up JSX ancestors looking for one that declares `group="<groupName>"` together
|
|
80
|
+
// with the `untilMeasured` prop. Used to deopt children whose styles depend on a
|
|
81
|
+
// parent that the runtime measures before emitting child styles (can't be modeled
|
|
82
|
+
// in static CSS).
|
|
83
|
+
function hasUntilMeasuredAncestor(path: NodePath<any>, groupName: string): boolean {
|
|
84
|
+
let current: NodePath<any> | null = path.parentPath
|
|
85
|
+
while (current) {
|
|
86
|
+
if (current.isJSXElement()) {
|
|
87
|
+
const opening = current.node.openingElement
|
|
88
|
+
let foundGroup = false
|
|
89
|
+
let foundUntilMeasured = false
|
|
90
|
+
for (const attr of opening.attributes) {
|
|
91
|
+
if (!t.isJSXAttribute(attr)) continue
|
|
92
|
+
if (!t.isJSXIdentifier(attr.name)) continue
|
|
93
|
+
const aName = attr.name.name
|
|
94
|
+
if (aName === 'group') {
|
|
95
|
+
// only literal string equality counts — dynamic group= is left to runtime
|
|
96
|
+
if (t.isStringLiteral(attr.value) && attr.value.value === groupName) {
|
|
97
|
+
foundGroup = true
|
|
98
|
+
} else if (
|
|
99
|
+
t.isJSXExpressionContainer(attr.value) &&
|
|
100
|
+
t.isStringLiteral(attr.value.expression) &&
|
|
101
|
+
attr.value.expression.value === groupName
|
|
102
|
+
) {
|
|
103
|
+
foundGroup = true
|
|
104
|
+
}
|
|
105
|
+
} else if (aName === 'untilMeasured') {
|
|
106
|
+
foundUntilMeasured = true
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (foundGroup && foundUntilMeasured) return true
|
|
110
|
+
}
|
|
111
|
+
current = current.parentPath
|
|
112
|
+
}
|
|
113
|
+
return false
|
|
114
|
+
}
|
|
115
|
+
|
|
79
116
|
export function createExtractor(
|
|
80
117
|
{ logger = console, platform = 'web' }: ExtractorOptions = { logger: console }
|
|
81
118
|
) {
|
|
@@ -217,7 +254,7 @@ export function createExtractor(
|
|
|
217
254
|
}
|
|
218
255
|
}
|
|
219
256
|
|
|
220
|
-
// we load
|
|
257
|
+
// we load hanzogui delayed because we need to set some global/env stuff before importing
|
|
221
258
|
// otherwise we'd import `rnw` and cause it to evaluate react-native-web which causes errors
|
|
222
259
|
|
|
223
260
|
function loadSync(props: GuiOptions) {
|
|
@@ -242,7 +279,7 @@ export function createExtractor(
|
|
|
242
279
|
loadGui: load,
|
|
243
280
|
loadGuiSync: loadSync,
|
|
244
281
|
getGui() {
|
|
245
|
-
return projectInfo?.
|
|
282
|
+
return projectInfo?.hanzoguiConfig
|
|
246
283
|
},
|
|
247
284
|
parseSync: (f: FileOrPath, props: ExtractorParseProps) => {
|
|
248
285
|
globalThis.expo ||= {} // expo-modules-core checks this and avoids loading "native" modules if exists
|
|
@@ -257,12 +294,12 @@ export function createExtractor(
|
|
|
257
294
|
}
|
|
258
295
|
|
|
259
296
|
function parseWithConfig(
|
|
260
|
-
{ components,
|
|
297
|
+
{ components, hanzoguiConfig }: GuiProjectInfo,
|
|
261
298
|
fileOrPath: FileOrPath,
|
|
262
299
|
options: ExtractorParseProps
|
|
263
300
|
) {
|
|
264
301
|
const {
|
|
265
|
-
config = '
|
|
302
|
+
config = 'hanzogui.config.ts',
|
|
266
303
|
importsWhitelist = ['constants.js'],
|
|
267
304
|
evaluateVars = true,
|
|
268
305
|
sourcePath = '',
|
|
@@ -288,7 +325,7 @@ export function createExtractor(
|
|
|
288
325
|
styledCheckCache.delete(sourcePath)
|
|
289
326
|
}
|
|
290
327
|
|
|
291
|
-
if (sourcePath.includes('.
|
|
328
|
+
if (sourcePath.includes('.hanzogui-dynamic-eval')) {
|
|
292
329
|
return null
|
|
293
330
|
}
|
|
294
331
|
|
|
@@ -355,10 +392,26 @@ export function createExtractor(
|
|
|
355
392
|
pseudoDescriptors[name] ||
|
|
356
393
|
// don't disable variants or else you lose many things flattening
|
|
357
394
|
staticConfig.variants?.[name] ||
|
|
358
|
-
projectInfo?.
|
|
395
|
+
projectInfo?.hanzoguiConfig?.shorthands[name]
|
|
359
396
|
)
|
|
360
397
|
}
|
|
361
398
|
|
|
399
|
+
function getGroupPseudo(name: string) {
|
|
400
|
+
const [_, groupName, a, b, c] = name.split('-')
|
|
401
|
+
if (!groupName) return
|
|
402
|
+
const m2 = a && b ? `${a}-${b}` : ''
|
|
403
|
+
const media = (m2 && mediaQueryConfig[m2] && m2) || (a && mediaQueryConfig[a] && a)
|
|
404
|
+
return media
|
|
405
|
+
? media === m2
|
|
406
|
+
? c
|
|
407
|
+
: b
|
|
408
|
+
? `${b}${c ? `-${c}` : ''}`
|
|
409
|
+
: undefined
|
|
410
|
+
: a
|
|
411
|
+
? `${a}${b ? `-${b}` : ''}${c ? `-${c}` : ''}`
|
|
412
|
+
: undefined
|
|
413
|
+
}
|
|
414
|
+
|
|
362
415
|
/**
|
|
363
416
|
* Step 1: Determine if importing any statically extractable components
|
|
364
417
|
*/
|
|
@@ -384,7 +437,7 @@ export function createExtractor(
|
|
|
384
437
|
].join(' ')
|
|
385
438
|
)
|
|
386
439
|
}
|
|
387
|
-
if (process.env.DEBUG?.startsWith('
|
|
440
|
+
if (process.env.DEBUG?.startsWith('hanzogui')) {
|
|
388
441
|
logger.info(
|
|
389
442
|
[
|
|
390
443
|
'loaded:',
|
|
@@ -394,12 +447,12 @@ export function createExtractor(
|
|
|
394
447
|
}
|
|
395
448
|
}
|
|
396
449
|
|
|
397
|
-
tm.mark('load-
|
|
450
|
+
tm.mark('load-hanzogui', !!shouldPrintDebug)
|
|
398
451
|
|
|
399
452
|
if (!isFullyDisabled(options)) {
|
|
400
|
-
if (!
|
|
453
|
+
if (!hanzoguiConfig?.themes) {
|
|
401
454
|
console.error(
|
|
402
|
-
`⛔️ Error: Missing "themes" in your
|
|
455
|
+
`⛔️ Error: Missing "themes" in your hanzogui.config file:
|
|
403
456
|
|
|
404
457
|
You may not need the compiler! Remember you can run Gui with no configuration at all.
|
|
405
458
|
|
|
@@ -410,17 +463,17 @@ export function createExtractor(
|
|
|
410
463
|
- or search your lockfile for mis-matches.
|
|
411
464
|
`
|
|
412
465
|
)
|
|
413
|
-
console.info(` Got config:`,
|
|
466
|
+
console.info(` Got config:`, hanzoguiConfig)
|
|
414
467
|
process.exit(0)
|
|
415
468
|
}
|
|
416
469
|
}
|
|
417
470
|
|
|
418
|
-
const firstThemeName = Object.keys(
|
|
419
|
-
const firstTheme =
|
|
471
|
+
const firstThemeName = Object.keys(hanzoguiConfig?.themes || {})[0]
|
|
472
|
+
const firstTheme = hanzoguiConfig?.themes[firstThemeName] || {}
|
|
420
473
|
|
|
421
474
|
if (!firstTheme || typeof firstTheme !== 'object') {
|
|
422
475
|
const err = `Missing theme ${firstThemeName}, an error occurred when importing your config`
|
|
423
|
-
console.info(err, `Got config:`,
|
|
476
|
+
console.info(err, `Got config:`, hanzoguiConfig)
|
|
424
477
|
console.info(`Looking for theme:`, firstThemeName)
|
|
425
478
|
throw new Error(err)
|
|
426
479
|
}
|
|
@@ -443,9 +496,9 @@ export function createExtractor(
|
|
|
443
496
|
if (!isFullyDisabled(options)) {
|
|
444
497
|
if (Object.keys(components || []).length === 0) {
|
|
445
498
|
console.warn(
|
|
446
|
-
`Warning: Gui didn't find any valid components (DEBUG=
|
|
499
|
+
`Warning: Gui didn't find any valid components (DEBUG=hanzogui for more)`
|
|
447
500
|
)
|
|
448
|
-
if (process.env.DEBUG === '
|
|
501
|
+
if (process.env.DEBUG === 'hanzogui') {
|
|
449
502
|
console.info(`components`, Object.keys(components || []), components)
|
|
450
503
|
}
|
|
451
504
|
}
|
|
@@ -487,7 +540,7 @@ export function createExtractor(
|
|
|
487
540
|
|
|
488
541
|
if (extractStyledDefinitions && enableDynamicEvaluation) {
|
|
489
542
|
// check all imports for `styled`, not just valid packages
|
|
490
|
-
// styled( is basically guaranteed to be
|
|
543
|
+
// styled( is basically guaranteed to be hanzogui regardless of source
|
|
491
544
|
if (node.specifiers.some((specifier) => specifier.local.name === 'styled')) {
|
|
492
545
|
doesUseValidImport = true
|
|
493
546
|
// don't break - need to collect all import declarations for the styled() handler
|
|
@@ -691,7 +744,7 @@ export function createExtractor(
|
|
|
691
744
|
} catch (err: any) {
|
|
692
745
|
if (shouldPrintDebug) {
|
|
693
746
|
logger.info(
|
|
694
|
-
`skip optimize styled(${variableName}), unable to pre-process (DEBUG=
|
|
747
|
+
`skip optimize styled(${variableName}), unable to pre-process (DEBUG=hanzogui for more)`
|
|
695
748
|
)
|
|
696
749
|
}
|
|
697
750
|
}
|
|
@@ -895,7 +948,7 @@ export function createExtractor(
|
|
|
895
948
|
return
|
|
896
949
|
}
|
|
897
950
|
|
|
898
|
-
// validate its a proper import from
|
|
951
|
+
// validate its a proper import from hanzogui (or internally inside hanzogui)
|
|
899
952
|
const binding = traversePath.scope.getBinding(node.name.name)
|
|
900
953
|
let moduleName = ''
|
|
901
954
|
let dynamicComponent: { staticConfig: any } | null = null
|
|
@@ -1086,15 +1139,28 @@ export function createExtractor(
|
|
|
1086
1139
|
...(staticConfig.inlineProps || []),
|
|
1087
1140
|
])
|
|
1088
1141
|
|
|
1142
|
+
const canFlattenTransition =
|
|
1143
|
+
isTargetingHTML &&
|
|
1144
|
+
hanzoguiConfig?.animations.outputStyle === 'css' &&
|
|
1145
|
+
!hanzoguiConfig.animationDrivers
|
|
1146
|
+
|
|
1089
1147
|
const deoptProps = new Set([
|
|
1090
|
-
//
|
|
1148
|
+
// css-only transitions lower to ordinary css; every runtime driver
|
|
1149
|
+
// needs the component preserved so it can respond to prop changes.
|
|
1091
1150
|
'animation',
|
|
1151
|
+
...(canFlattenTransition ? [] : ['transition']),
|
|
1092
1152
|
'animateOnly',
|
|
1093
1153
|
'animatePresence',
|
|
1094
1154
|
'disableOptimization',
|
|
1095
1155
|
|
|
1096
1156
|
...(!isTargetingHTML
|
|
1097
1157
|
? [
|
|
1158
|
+
// native has no css pseudo selectors; these are runtime-only on
|
|
1159
|
+
// rn (event listeners + style merge in createComponent), and if
|
|
1160
|
+
// we let them flatten into the stylesheet they get written
|
|
1161
|
+
// under a literal key that rn treats as an unknown style prop.
|
|
1162
|
+
// hover is intentionally excluded: it is no-op on native and
|
|
1163
|
+
// should be dropped rather than preserved as runtime work.
|
|
1098
1164
|
'pressStyle',
|
|
1099
1165
|
'focusStyle',
|
|
1100
1166
|
'focusVisibleStyle',
|
|
@@ -1104,7 +1170,7 @@ export function createExtractor(
|
|
|
1104
1170
|
: []),
|
|
1105
1171
|
|
|
1106
1172
|
// when using a non-CSS driver, de-opt on enterStyle/exitStyle
|
|
1107
|
-
...(
|
|
1173
|
+
...(hanzoguiConfig?.animations.isReactNative
|
|
1108
1174
|
? ['enterStyle', 'exitStyle']
|
|
1109
1175
|
: []),
|
|
1110
1176
|
])
|
|
@@ -1176,7 +1242,7 @@ export function createExtractor(
|
|
|
1176
1242
|
style: {},
|
|
1177
1243
|
theme: defaultTheme,
|
|
1178
1244
|
viewProps: defaultProps,
|
|
1179
|
-
conf:
|
|
1245
|
+
conf: hanzoguiConfig!,
|
|
1180
1246
|
props: defaultProps,
|
|
1181
1247
|
componentState,
|
|
1182
1248
|
styleProps: {
|
|
@@ -1288,9 +1354,9 @@ export function createExtractor(
|
|
|
1288
1354
|
|
|
1289
1355
|
const name = attribute.name.name
|
|
1290
1356
|
|
|
1291
|
-
// in
|
|
1357
|
+
// in hanzogui style is handled at the end of the style loop so its not as simple as just
|
|
1292
1358
|
// adding this as a "style" property
|
|
1293
|
-
// its not used often when using
|
|
1359
|
+
// its not used often when using hanzogui so not optimizing it for now
|
|
1294
1360
|
if (name === 'style') {
|
|
1295
1361
|
shouldDeopt = true
|
|
1296
1362
|
return null
|
|
@@ -1368,6 +1434,20 @@ export function createExtractor(
|
|
|
1368
1434
|
return [attribute.value!, path.get('value')!] as const
|
|
1369
1435
|
})()
|
|
1370
1436
|
|
|
1437
|
+
// these props have runtime-only meaning on native. decide from the
|
|
1438
|
+
// original jsx attr, before getSplitStyles has a chance to drop
|
|
1439
|
+
// native-dead work like hoverStyle from its static output.
|
|
1440
|
+
if (
|
|
1441
|
+
deoptProps.has(name) ||
|
|
1442
|
+
(platform === 'native' &&
|
|
1443
|
+
name[0] === '$' &&
|
|
1444
|
+
(name.startsWith('$theme-') ||
|
|
1445
|
+
(name.startsWith('$group-') && getGroupPseudo(name) !== 'hover')))
|
|
1446
|
+
) {
|
|
1447
|
+
inlined.set(name, true)
|
|
1448
|
+
return attr
|
|
1449
|
+
}
|
|
1450
|
+
|
|
1371
1451
|
const remove = () => {
|
|
1372
1452
|
Array.isArray(valuePath)
|
|
1373
1453
|
? valuePath.map((p) => p.remove())
|
|
@@ -1420,9 +1500,33 @@ export function createExtractor(
|
|
|
1420
1500
|
return attr
|
|
1421
1501
|
}
|
|
1422
1502
|
|
|
1503
|
+
// static `group="<literal>"` is handled at compile-time in
|
|
1504
|
+
// extractToClassNames (emits container CSS + adds `t_group_<name>`
|
|
1505
|
+
// className), so we drop the JSX attribute here without bailing
|
|
1506
|
+
// flattening. dynamic `group={expr}` falls through to runtime.
|
|
1507
|
+
if (isTargetingHTML && name === 'group' && t.isStringLiteral(value)) {
|
|
1508
|
+
return []
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1423
1511
|
// if value can be evaluated, extract it and filter it out
|
|
1424
1512
|
const styleValue = attemptEvalSafe(value)
|
|
1425
1513
|
|
|
1514
|
+
// media-like blocks with nested $-keys (eg $theme-dark={{ $sm: {…} }})
|
|
1515
|
+
// can't resolve to static CSS in one pass — keep them on the runtime path
|
|
1516
|
+
if (
|
|
1517
|
+
name[0] === '$' &&
|
|
1518
|
+
(name.startsWith('$theme-') || name.startsWith('$group-')) &&
|
|
1519
|
+
styleValue &&
|
|
1520
|
+
typeof styleValue === 'object' &&
|
|
1521
|
+
Object.keys(styleValue).some((k) => k[0] === '$')
|
|
1522
|
+
) {
|
|
1523
|
+
if (shouldPrintDebug) {
|
|
1524
|
+
logger.info(` ! nested media-like key inside ${name}, deopt to runtime`)
|
|
1525
|
+
}
|
|
1526
|
+
inlined.set(name, true)
|
|
1527
|
+
return attr
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1426
1530
|
// never flatten if a prop isn't a valid static attribute
|
|
1427
1531
|
// only post prop-mapping
|
|
1428
1532
|
if (!variants[name] && !isValidStyleKey(name, staticConfig)) {
|
|
@@ -1444,6 +1548,12 @@ export function createExtractor(
|
|
|
1444
1548
|
)
|
|
1445
1549
|
// remove className - we dont use rnw styling
|
|
1446
1550
|
delete out.className
|
|
1551
|
+
// remove style - rnw createDOMProps unconditionally emits a
|
|
1552
|
+
// (possibly empty) style key, but we passed it a single
|
|
1553
|
+
// non-style prop. Leaving it in causes Object.keys(out) to
|
|
1554
|
+
// iterate twice and emit the original JSXAttribute twice
|
|
1555
|
+
// (e.g. duplicate testID), breaking the DOM output.
|
|
1556
|
+
delete out.style
|
|
1447
1557
|
}
|
|
1448
1558
|
}
|
|
1449
1559
|
|
|
@@ -1467,6 +1577,23 @@ export function createExtractor(
|
|
|
1467
1577
|
key === '__source' ||
|
|
1468
1578
|
key === '__self'
|
|
1469
1579
|
) {
|
|
1580
|
+
if (
|
|
1581
|
+
styleValue === FAILED_EVAL &&
|
|
1582
|
+
key !== name &&
|
|
1583
|
+
t.isJSXAttribute(attr.value)
|
|
1584
|
+
) {
|
|
1585
|
+
// createDOMProps renamed the prop (e.g. testID -> data-testid).
|
|
1586
|
+
// preserve the original expression value but use the new
|
|
1587
|
+
// attribute name. restricted to FAILED_EVAL because the
|
|
1588
|
+
// later `case 'attr'` rename pass only runs on
|
|
1589
|
+
// statically-evaluable values; for static values that pass
|
|
1590
|
+
// intentionally preserves some prop names (e.g. focusable
|
|
1591
|
+
// in v2) instead of doing the createDOMProps rename.
|
|
1592
|
+
return {
|
|
1593
|
+
type: 'attr',
|
|
1594
|
+
value: t.jsxAttribute(t.jsxIdentifier(key), attr.value.value),
|
|
1595
|
+
} as const
|
|
1596
|
+
}
|
|
1470
1597
|
return attr
|
|
1471
1598
|
}
|
|
1472
1599
|
if (shouldPrintDebug) {
|
|
@@ -1502,15 +1629,25 @@ export function createExtractor(
|
|
|
1502
1629
|
}
|
|
1503
1630
|
|
|
1504
1631
|
if (isValidStyleKey(name, staticConfig)) {
|
|
1505
|
-
// $theme
|
|
1506
|
-
//
|
|
1632
|
+
// $theme- / $group- styles extract through the atomic-CSS pipeline
|
|
1633
|
+
// (extractToClassNames → createMediaStyle), so they fall through to
|
|
1634
|
+
// the normal style return below. The one case we still bail is
|
|
1635
|
+
// $group-<name>-* when an ancestor element declares `group="<name>"`
|
|
1636
|
+
// together with `untilMeasured` — the runtime measures the parent
|
|
1637
|
+
// and only then emits child styles, which can't be modeled in CSS.
|
|
1638
|
+
// $platform- can be flattened if the platform matches.
|
|
1507
1639
|
if (name[0] === '$') {
|
|
1508
|
-
if (name.startsWith('$
|
|
1509
|
-
|
|
1510
|
-
|
|
1640
|
+
if (name.startsWith('$group-')) {
|
|
1641
|
+
const groupName = name.slice('$group-'.length).split('-')[0]
|
|
1642
|
+
if (groupName && hasUntilMeasuredAncestor(path, groupName)) {
|
|
1643
|
+
if (shouldPrintDebug) {
|
|
1644
|
+
logger.info(
|
|
1645
|
+
` ! group="${groupName}" ancestor has untilMeasured, not flattening: ${name}`
|
|
1646
|
+
)
|
|
1647
|
+
}
|
|
1648
|
+
inlined.set(name, true)
|
|
1649
|
+
return attr
|
|
1511
1650
|
}
|
|
1512
|
-
inlined.set(name, true)
|
|
1513
|
-
return attr
|
|
1514
1651
|
}
|
|
1515
1652
|
|
|
1516
1653
|
// $platform-web, $platform-native, $platform-ios, $platform-android, $platform-tv, $platform-androidtv, $platform-tvos
|
|
@@ -1878,7 +2015,6 @@ export function createExtractor(
|
|
|
1878
2015
|
})
|
|
1879
2016
|
|
|
1880
2017
|
if (!shouldFlatten) {
|
|
1881
|
-
// were no longer partially optimizing, it adds a lot of complexity for dubious performance
|
|
1882
2018
|
if (shouldPrintDebug) {
|
|
1883
2019
|
logger.info(
|
|
1884
2020
|
`Deopting ${JSON.stringify({
|
|
@@ -1911,7 +2047,7 @@ export function createExtractor(
|
|
|
1911
2047
|
if (!isValidStyleKey(key, staticConfig)) {
|
|
1912
2048
|
return []
|
|
1913
2049
|
}
|
|
1914
|
-
const name =
|
|
2050
|
+
const name = hanzoguiConfig?.shorthands[key] || key
|
|
1915
2051
|
if (value === undefined) {
|
|
1916
2052
|
logger.warn(
|
|
1917
2053
|
`⚠️ Error evaluating default style for component, prop ${key} ${value}`
|
|
@@ -2155,6 +2291,10 @@ export function createExtractor(
|
|
|
2155
2291
|
)
|
|
2156
2292
|
// remove rnw className use ours
|
|
2157
2293
|
out.className = cn
|
|
2294
|
+
// see note in single-prop branch above; createDOMProps
|
|
2295
|
+
// also emits a stray style key here that would duplicate
|
|
2296
|
+
// emitted JSXAttributes downstream.
|
|
2297
|
+
delete out.style
|
|
2158
2298
|
}
|
|
2159
2299
|
if (shouldPrintDebug) {
|
|
2160
2300
|
logger.info([' - expanded variant', name, out].join(' '))
|
|
@@ -2194,7 +2334,7 @@ export function createExtractor(
|
|
|
2194
2334
|
|
|
2195
2335
|
let key = Object.keys(cur.value)[0]
|
|
2196
2336
|
const value = cur.value[key]
|
|
2197
|
-
const fullKey =
|
|
2337
|
+
const fullKey = hanzoguiConfig?.shorthands[key]
|
|
2198
2338
|
// expand shorthands
|
|
2199
2339
|
if (fullKey) {
|
|
2200
2340
|
cur.value = { [fullKey]: value }
|
|
@@ -2275,8 +2415,37 @@ export function createExtractor(
|
|
|
2275
2415
|
const before = process.env.IS_STATIC
|
|
2276
2416
|
process.env.IS_STATIC = 'is_static'
|
|
2277
2417
|
try {
|
|
2418
|
+
// $group-* / $theme-* keys carry block-form style objects that
|
|
2419
|
+
// getSplitStyles drops in static mode (no parent group context,
|
|
2420
|
+
// no theme value to read). Pluck them out so the atomic-CSS
|
|
2421
|
+
// pipeline in extractToClassNames can emit @container / theme
|
|
2422
|
+
// rules for them directly.
|
|
2423
|
+
let extractedMediaLikeProps: Record<string, any> | null = null
|
|
2424
|
+
let propsForSplit: any = props
|
|
2425
|
+
for (const k in props) {
|
|
2426
|
+
if (
|
|
2427
|
+
k[0] === '$' &&
|
|
2428
|
+
(k.startsWith('$group-') || k.startsWith('$theme-'))
|
|
2429
|
+
) {
|
|
2430
|
+
if (propsForSplit === props) {
|
|
2431
|
+
propsForSplit = { ...props }
|
|
2432
|
+
}
|
|
2433
|
+
if (
|
|
2434
|
+
platform === 'native' &&
|
|
2435
|
+
k.startsWith('$group-') &&
|
|
2436
|
+
getGroupPseudo(k) === 'hover'
|
|
2437
|
+
) {
|
|
2438
|
+
delete propsForSplit[k]
|
|
2439
|
+
continue
|
|
2440
|
+
}
|
|
2441
|
+
extractedMediaLikeProps ||= {}
|
|
2442
|
+
extractedMediaLikeProps[k] = propsForSplit[k]
|
|
2443
|
+
delete propsForSplit[k]
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2278
2447
|
const out = getSplitStyles(
|
|
2279
|
-
|
|
2448
|
+
propsForSplit,
|
|
2280
2449
|
staticConfig,
|
|
2281
2450
|
defaultTheme,
|
|
2282
2451
|
'',
|
|
@@ -2297,10 +2466,47 @@ export function createExtractor(
|
|
|
2297
2466
|
debugPropValue || shouldPrintDebug
|
|
2298
2467
|
)!
|
|
2299
2468
|
|
|
2469
|
+
// resolve tokens inside the plucked blocks: they skipped the main
|
|
2470
|
+
// split, so values like "$color5" would flow raw into the emitted
|
|
2471
|
+
// CSS where browsers reject the declaration. run each block through
|
|
2472
|
+
// its own static split so tokens become var(--x) references.
|
|
2473
|
+
// (native never extracts these — it deopts below — so web only.)
|
|
2474
|
+
if (extractedMediaLikeProps && platform !== 'native') {
|
|
2475
|
+
for (const k in extractedMediaLikeProps) {
|
|
2476
|
+
const block = extractedMediaLikeProps[k]
|
|
2477
|
+
if (!block || typeof block !== 'object') continue
|
|
2478
|
+
const blockOut = getSplitStyles(
|
|
2479
|
+
block,
|
|
2480
|
+
staticConfig,
|
|
2481
|
+
defaultTheme,
|
|
2482
|
+
'',
|
|
2483
|
+
componentState,
|
|
2484
|
+
{
|
|
2485
|
+
...styleProps,
|
|
2486
|
+
noClass: true,
|
|
2487
|
+
fallbackProps: completeProps,
|
|
2488
|
+
},
|
|
2489
|
+
undefined,
|
|
2490
|
+
undefined,
|
|
2491
|
+
undefined,
|
|
2492
|
+
undefined,
|
|
2493
|
+
false,
|
|
2494
|
+
debugPropValue || shouldPrintDebug
|
|
2495
|
+
)
|
|
2496
|
+
if (blockOut) {
|
|
2497
|
+
extractedMediaLikeProps[k] = {
|
|
2498
|
+
...blockOut.style,
|
|
2499
|
+
...blockOut.pseudos,
|
|
2500
|
+
}
|
|
2501
|
+
}
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2300
2505
|
let outProps = {
|
|
2301
2506
|
...(includeProps ? out.viewProps : {}),
|
|
2302
2507
|
...out.style,
|
|
2303
2508
|
...out.pseudos,
|
|
2509
|
+
...extractedMediaLikeProps,
|
|
2304
2510
|
}
|
|
2305
2511
|
|
|
2306
2512
|
// check de-opt props again
|
|
@@ -2308,6 +2514,20 @@ export function createExtractor(
|
|
|
2308
2514
|
if (deoptProps.has(key)) {
|
|
2309
2515
|
shouldFlatten = false
|
|
2310
2516
|
}
|
|
2517
|
+
// native has no atomic-CSS sink for theme- / group- pseudo
|
|
2518
|
+
// blocks; if they flatten they get serialized under the literal
|
|
2519
|
+
// `$theme-…` / `$group-…` key into the RN StyleSheet, where the
|
|
2520
|
+
// runtime's @container / theme-name matching never runs. de-opt
|
|
2521
|
+
// → preserve as inline prop so getSplitStyles handles them at
|
|
2522
|
+
// render time.
|
|
2523
|
+
if (
|
|
2524
|
+
platform === 'native' &&
|
|
2525
|
+
key[0] === '$' &&
|
|
2526
|
+
(key.startsWith('$theme-') ||
|
|
2527
|
+
(key.startsWith('$group-') && getGroupPseudo(key) !== 'hover'))
|
|
2528
|
+
) {
|
|
2529
|
+
shouldFlatten = false
|
|
2530
|
+
}
|
|
2311
2531
|
}
|
|
2312
2532
|
|
|
2313
2533
|
if (shouldPrintDebug) {
|
|
@@ -2622,7 +2842,7 @@ export function createExtractor(
|
|
|
2622
2842
|
node,
|
|
2623
2843
|
lineNumbers,
|
|
2624
2844
|
filePath,
|
|
2625
|
-
config:
|
|
2845
|
+
config: hanzoguiConfig!,
|
|
2626
2846
|
flatNodeName,
|
|
2627
2847
|
attemptEval,
|
|
2628
2848
|
jsxPath: traversePath,
|
|
@@ -198,8 +198,8 @@ export const isValidImport = (
|
|
|
198
198
|
}
|
|
199
199
|
|
|
200
200
|
const getValidComponentPackages = memoize((props: GuiOptionsWithFileInfo) => {
|
|
201
|
-
// just always look for `
|
|
202
|
-
return [...new Set(['@hanzogui/core', '
|
|
201
|
+
// just always look for `hanzogui` and `@hanzogui/core`
|
|
202
|
+
return [...new Set(['@hanzogui/core', 'hanzogui', ...(props.components || [])])]
|
|
203
203
|
})
|
|
204
204
|
|
|
205
205
|
export const getValidComponentsPaths = memoize((props: GuiOptionsWithFileInfo) => {
|
|
@@ -12,7 +12,7 @@ export function extractMediaStyle(
|
|
|
12
12
|
props: GuiOptionsWithFileInfo,
|
|
13
13
|
ternary: Ternary,
|
|
14
14
|
jsxPath: NodePath<t.JSXElement>,
|
|
15
|
-
|
|
15
|
+
hanzoguiConfig: GuiInternalConfig,
|
|
16
16
|
sourcePath: string,
|
|
17
17
|
importance = 0,
|
|
18
18
|
shouldPrintDebug: boolean | 'verbose' = false
|
|
@@ -23,9 +23,9 @@ export function extractMediaStyle(
|
|
|
23
23
|
return null
|
|
24
24
|
}
|
|
25
25
|
const { key } = mt
|
|
26
|
-
const mq =
|
|
26
|
+
const mq = hanzoguiConfig.media[key]
|
|
27
27
|
if (!mq) {
|
|
28
|
-
console.error(`Media query "${key}" not found: ${Object.keys(
|
|
28
|
+
console.error(`Media query "${key}" not found: ${Object.keys(hanzoguiConfig.media)}`)
|
|
29
29
|
return null
|
|
30
30
|
}
|
|
31
31
|
const getStyleObj = (styleObj: ViewStyle | null, negate = false) => {
|
|
@@ -40,7 +40,7 @@ export function extractMediaStyle(
|
|
|
40
40
|
return null
|
|
41
41
|
}
|
|
42
42
|
// for now order first strongest
|
|
43
|
-
const mediaKeys = Object.keys(
|
|
43
|
+
const mediaKeys = Object.keys(hanzoguiConfig.media)
|
|
44
44
|
const mediaKeyPrecendence = mediaKeys.reduce((acc, cur, i) => {
|
|
45
45
|
acc[cur] = new Array(importance + 1).fill(':root').join('')
|
|
46
46
|
return acc
|
|
@@ -57,7 +57,7 @@ export function extractMediaStyle(
|
|
|
57
57
|
const mediaStyle = core.createMediaStyle(
|
|
58
58
|
style,
|
|
59
59
|
key,
|
|
60
|
-
|
|
60
|
+
hanzoguiConfig.media,
|
|
61
61
|
true,
|
|
62
62
|
negate
|
|
63
63
|
)
|