@kbach/react-native 1.0.0-beta.20 → 1.0.0-beta.21

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.
@@ -1,10 +1,10 @@
1
- import "./chunk-45GOGUHJ.mjs";
1
+ import "./chunk-TS2EEVOE.mjs";
2
2
  import {
3
3
  Fragment,
4
4
  jsx,
5
5
  jsxs
6
- } from "./chunk-MJWWZJMH.mjs";
7
- import "./chunk-OGFB3OXS.mjs";
6
+ } from "./chunk-OS7EPBH5.mjs";
7
+ import "./chunk-AG7ZQ2K4.mjs";
8
8
 
9
9
  // src/jsxRuntimeCore.ts
10
10
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
@@ -32,7 +32,6 @@ var import_react = require("react");
32
32
  var import_react_native = require("react-native");
33
33
  var import_darkModeStore = require("./darkModeStore");
34
34
  var import_dynamicTokens = require("./dynamicTokens");
35
- var import_theme = require("./theme");
36
35
 
37
36
  // src/jsEngine/calc.ts
38
37
  function reduceConstantMath(raw) {
@@ -208,147 +207,6 @@ function resolvePercentRelativeCalc(basisPx, calc) {
208
207
  return basisPx * calc.percentCoefficient / 100 + calc.constantPx;
209
208
  }
210
209
 
211
- // src/jsxRuntimeCore.ts
212
- var DYNAMIC_TOKEN_MATCH_RE = /var\(--([a-zA-Z0-9-]+)\)/g;
213
- function substituteDynamicTokens(classStrRaw) {
214
- if (!classStrRaw.includes("var(--")) return classStrRaw;
215
- return classStrRaw.replace(DYNAMIC_TOKEN_MATCH_RE, (whole, name) => {
216
- const value = (0, import_dynamicTokens.getDynamicToken)(name);
217
- return value ?? whole;
218
- });
219
- }
220
- var PERCENT_RELATIVE_CALC_HINT_RE = /[wh]-\[calc\([^)]*%[^)]*\)\]/;
221
- function extractPercentRelativeCalcs(classStrRaw) {
222
- const found = [];
223
- for (const token of classStrRaw.split(/\s+/)) {
224
- const parsed = parsePercentRelativeCalc(token);
225
- if (parsed) found.push(parsed);
226
- }
227
- return found;
228
- }
229
- function stripPercentRelativeCalcTokens(classStrRaw) {
230
- return classStrRaw.split(/\s+/).filter((token) => token && parsePercentRelativeCalc(token) === null).join(" ");
231
- }
232
- function makeElement(isStaticChildren, type, props, key) {
233
- return (isStaticChildren ? import_jsx_runtime.jsxs : import_jsx_runtime.jsx)(type, props, key);
234
- }
235
- function resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, pressed, layoutOverrides) {
236
- const cleaned = stripPercentRelativeCalcTokens(substituteDynamicTokens(classStrRaw));
237
- const resolved = resolveStyle2(cleaned, pressed);
238
- if (layoutOverrides) {
239
- Object.assign(resolved, layoutOverrides);
240
- }
241
- if (userStyle === void 0) {
242
- return resolved;
243
- }
244
- if (typeof userStyle === "function") {
245
- return [resolved, userStyle({ pressed })];
246
- }
247
- return [resolved, userStyle];
248
- }
249
- var DARK_MODIFIER_RE = /(^|\s)dark:/;
250
- var BREAKPOINT_MODIFIER_RE = /(^|\s)(sm|md|lg|xl|2xl):/;
251
- var BREAKPOINT_MODIFIER_MATCH_RE = /(?:^|\s)(sm|md|lg|xl|2xl):/g;
252
- function darkModeKeySuffix(classStrRaw) {
253
- return DARK_MODIFIER_RE.test(classStrRaw) ? `:kb-dark-${(0, import_darkModeStore.getGlobalDarkMode)()}` : "";
254
- }
255
- function breakpointKeySuffix(classStrRaw, width) {
256
- const matches = classStrRaw.match(BREAKPOINT_MODIFIER_MATCH_RE);
257
- if (!matches) {
258
- return "";
259
- }
260
- const screens = (0, import_theme.getTheme)().screens;
261
- const present = Array.from(new Set(matches.map((m) => m.trim().slice(0, -1))));
262
- const state = present.map((name) => screens[name] !== void 0 && width >= screens[name] ? "1" : "0").join("");
263
- return `:kb-bp-${state}`;
264
- }
265
- function dynamicTokenKeySuffix(classStrRaw) {
266
- const matches = classStrRaw.match(DYNAMIC_TOKEN_MATCH_RE);
267
- if (!matches) return "";
268
- const values = matches.map((m) => (0, import_dynamicTokens.getDynamicToken)(m.slice("var(--".length, -1)) ?? "");
269
- return `:kb-dt-${values.join("|")}`;
270
- }
271
- function percentCalcKeySuffix(percentCalcs, measuredBasis) {
272
- if (percentCalcs.length === 0) return "";
273
- const values = percentCalcs.map((calc) => {
274
- const basis = measuredBasis?.[calc.property];
275
- return basis === void 0 ? "pending" : resolvePercentRelativeCalc(basis, calc);
276
- });
277
- return `:kb-pc-${values.join("|")}`;
278
- }
279
- function ReactiveElement({
280
- hostType,
281
- hostRest,
282
- classStrRaw,
283
- userStyle,
284
- resolveStyle: resolveStyle2,
285
- elementKey,
286
- isStaticChildren
287
- }) {
288
- (0, import_react.useSyncExternalStore)(import_darkModeStore.subscribeGlobalDarkMode, import_darkModeStore.getGlobalDarkMode);
289
- (0, import_react.useSyncExternalStore)(import_dynamicTokens.subscribeDynamicTokens, import_dynamicTokens.getDynamicTokensVersion);
290
- const { width } = (0, import_react_native.useWindowDimensions)();
291
- const [measuredBasis, setMeasuredBasis] = (0, import_react.useState)(null);
292
- const measure = (0, import_react.useCallback)((e) => {
293
- const { width: w, height: h } = e.nativeEvent.layout;
294
- setMeasuredBasis((prev) => prev && prev.width === w && prev.height === h ? prev : { width: w, height: h });
295
- }, []);
296
- const percentCalcs = extractPercentRelativeCalcs(classStrRaw);
297
- let layoutOverrides;
298
- let hostRestWithLayout = hostRest;
299
- if (percentCalcs.length > 0) {
300
- layoutOverrides = {};
301
- for (const calc of percentCalcs) {
302
- const basis = measuredBasis?.[calc.property];
303
- layoutOverrides[calc.property] = basis === void 0 ? "100%" : resolvePercentRelativeCalc(basis, calc);
304
- }
305
- const userOnLayout = hostRest.onLayout;
306
- hostRestWithLayout = {
307
- ...hostRest,
308
- onLayout: userOnLayout ? (e) => {
309
- measure(e);
310
- userOnLayout(e);
311
- } : measure
312
- };
313
- }
314
- const finalStyle = hostType === import_react_native.Pressable ? (state) => resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, state.pressed, layoutOverrides) : resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, false, layoutOverrides);
315
- const suffix = darkModeKeySuffix(classStrRaw) + breakpointKeySuffix(classStrRaw, width) + dynamicTokenKeySuffix(classStrRaw) + percentCalcKeySuffix(percentCalcs, measuredBasis);
316
- const finalKey = suffix ? `${elementKey ?? ""}${suffix}` : elementKey;
317
- return makeElement(isStaticChildren, hostType, { ...hostRestWithLayout, style: finalStyle }, finalKey);
318
- }
319
- function processElement(resolveStyle2, type, rawProps, key, isStaticChildren) {
320
- if (type === null || typeof type === "symbol" || !rawProps) {
321
- return makeElement(isStaticChildren, type, rawProps ?? {}, key);
322
- }
323
- const { className: classStrRaw, style: userStyle, ...rest } = rawProps;
324
- if (typeof classStrRaw !== "string") {
325
- return makeElement(isStaticChildren, type, rawProps, key);
326
- }
327
- if (DARK_MODIFIER_RE.test(classStrRaw) || BREAKPOINT_MODIFIER_RE.test(classStrRaw) || classStrRaw.includes("var(--") || PERCENT_RELATIVE_CALC_HINT_RE.test(classStrRaw)) {
328
- return (0, import_jsx_runtime.jsx)(
329
- ReactiveElement,
330
- { hostType: type, hostRest: rest, classStrRaw, userStyle, resolveStyle: resolveStyle2, elementKey: key, isStaticChildren },
331
- key
332
- );
333
- }
334
- const finalStyle = type === import_react_native.Pressable ? (state) => resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, state.pressed) : resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, false);
335
- return makeElement(isStaticChildren, type, { ...rest, style: finalStyle }, key);
336
- }
337
- function createJsxFunctions(resolveStyle2) {
338
- function jsx2(type, props, key) {
339
- return processElement(resolveStyle2, type, props, key, false);
340
- }
341
- function jsxs2(type, props, key) {
342
- return processElement(resolveStyle2, type, props, key, true);
343
- }
344
- return { jsx: jsx2, jsxs: jsxs2 };
345
- }
346
-
347
- // src/nativeBridge.ts
348
- var import_react_native2 = require("react-native");
349
- var import_theme2 = require("./theme");
350
- var import_darkModeStore2 = require("./darkModeStore");
351
-
352
210
  // src/jsEngine/parser.ts
353
211
  var VALUE_PREFIXES = [
354
212
  "bg-opacity-",
@@ -436,11 +294,21 @@ var VALUE_PREFIXES = [
436
294
  "tracking-",
437
295
  "font-",
438
296
  "z-",
297
+ "inset-x-",
298
+ "inset-y-",
439
299
  "inset-",
440
300
  "top-",
441
301
  "right-",
442
302
  "bottom-",
443
303
  "left-",
304
+ "start-",
305
+ "end-",
306
+ "overflow-x-",
307
+ "overflow-y-",
308
+ "overscroll-x-",
309
+ "overscroll-y-",
310
+ "overscroll-",
311
+ "aspect-",
444
312
  "divide-color-",
445
313
  "space-x-",
446
314
  "space-y-",
@@ -595,6 +463,179 @@ function parseClass(token) {
595
463
  };
596
464
  }
597
465
 
466
+ // src/jsxRuntimeCore.ts
467
+ var DYNAMIC_TOKEN_MATCH_RE = /var\(--([a-zA-Z0-9-]+)\)/g;
468
+ function substituteDynamicTokens(classStrRaw) {
469
+ if (!classStrRaw.includes("var(--")) return classStrRaw;
470
+ return classStrRaw.replace(DYNAMIC_TOKEN_MATCH_RE, (whole, name) => {
471
+ const value = (0, import_dynamicTokens.getDynamicToken)(name);
472
+ return value ?? whole;
473
+ });
474
+ }
475
+ var PERCENT_RELATIVE_CALC_HINT_RE = /[wh]-\[calc\([^)]*%[^)]*\)\]/;
476
+ function extractPercentRelativeCalcs(classStrRaw) {
477
+ const found = [];
478
+ for (const token of classStrRaw.split(/\s+/)) {
479
+ const parsed = parsePercentRelativeCalc(token);
480
+ if (parsed) found.push(parsed);
481
+ }
482
+ return found;
483
+ }
484
+ function stripPercentRelativeCalcTokens(classStrRaw) {
485
+ return classStrRaw.split(/\s+/).filter((token) => token && parsePercentRelativeCalc(token) === null).join(" ");
486
+ }
487
+ var STATE_MODIFIER_NAMES = /* @__PURE__ */ new Set(["hover", "focus", "disabled"]);
488
+ var STATE_MODIFIER_HINT_RE = /(^|\s|:)(hover|focus|disabled):/;
489
+ function stripModifiers(parts, namesToStrip) {
490
+ const utility = parts[parts.length - 1] ?? "";
491
+ const modifiers = parts.slice(0, -1).filter((m) => !namesToStrip.has(m));
492
+ return [...modifiers, utility].join(":");
493
+ }
494
+ function substituteStateModifiers(classStrRaw, states) {
495
+ if (!STATE_MODIFIER_HINT_RE.test(classStrRaw)) return classStrRaw;
496
+ const kept = [];
497
+ for (const token of classStrRaw.split(/\s+/)) {
498
+ if (!token) continue;
499
+ const parts = splitRespectingBrackets(token);
500
+ const modifiers = parts.slice(0, -1);
501
+ const required = modifiers.filter((m) => STATE_MODIFIER_NAMES.has(m));
502
+ if (required.length === 0) {
503
+ kept.push(token);
504
+ continue;
505
+ }
506
+ if (required.every((m) => states[m])) {
507
+ kept.push(stripModifiers(parts, STATE_MODIFIER_NAMES));
508
+ }
509
+ }
510
+ return kept.join(" ");
511
+ }
512
+ function makeElement(isStaticChildren, type, props, key) {
513
+ return (isStaticChildren ? import_jsx_runtime.jsxs : import_jsx_runtime.jsx)(type, props, key);
514
+ }
515
+ function resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, pressed, layoutOverrides, states = { hover: false, focus: false, disabled: false }) {
516
+ const stateResolved = substituteStateModifiers(classStrRaw, states);
517
+ const cleaned = stripPercentRelativeCalcTokens(substituteDynamicTokens(stateResolved));
518
+ const resolved = resolveStyle2(cleaned, pressed);
519
+ if (layoutOverrides) {
520
+ Object.assign(resolved, layoutOverrides);
521
+ }
522
+ if (userStyle === void 0) {
523
+ return resolved;
524
+ }
525
+ if (typeof userStyle === "function") {
526
+ return [resolved, userStyle({ pressed })];
527
+ }
528
+ return [resolved, userStyle];
529
+ }
530
+ var DARK_MODIFIER_RE = /(^|\s|:)dark:/;
531
+ var BREAKPOINT_MODIFIER_RE = /(^|\s|:)(sm|md|lg|xl|2xl):/;
532
+ var HOVER_MODIFIER_RE = /(^|\s|:)hover:/;
533
+ var FOCUS_MODIFIER_RE = /(^|\s|:)focus:/;
534
+ function ReactiveElement({
535
+ hostType,
536
+ hostRest,
537
+ classStrRaw,
538
+ userStyle,
539
+ resolveStyle: resolveStyle2,
540
+ elementKey,
541
+ isStaticChildren
542
+ }) {
543
+ (0, import_react.useSyncExternalStore)(import_darkModeStore.subscribeGlobalDarkMode, import_darkModeStore.getGlobalDarkMode);
544
+ (0, import_react.useSyncExternalStore)(import_dynamicTokens.subscribeDynamicTokens, import_dynamicTokens.getDynamicTokensVersion);
545
+ (0, import_react_native.useWindowDimensions)();
546
+ const [measuredBasis, setMeasuredBasis] = (0, import_react.useState)(null);
547
+ const measure = (0, import_react.useCallback)((e) => {
548
+ const { width: w, height: h } = e.nativeEvent.layout;
549
+ setMeasuredBasis((prev) => prev && prev.width === w && prev.height === h ? prev : { width: w, height: h });
550
+ }, []);
551
+ const [isHovered, setIsHovered] = (0, import_react.useState)(false);
552
+ const [isFocused, setIsFocused] = (0, import_react.useState)(false);
553
+ const percentCalcs = extractPercentRelativeCalcs(classStrRaw);
554
+ let layoutOverrides;
555
+ let hostRestWithLayout = hostRest;
556
+ if (percentCalcs.length > 0) {
557
+ layoutOverrides = {};
558
+ for (const calc of percentCalcs) {
559
+ const basis = measuredBasis?.[calc.property];
560
+ layoutOverrides[calc.property] = basis === void 0 ? "100%" : resolvePercentRelativeCalc(basis, calc);
561
+ }
562
+ const userOnLayout = hostRest.onLayout;
563
+ hostRestWithLayout = {
564
+ ...hostRest,
565
+ onLayout: userOnLayout ? (e) => {
566
+ measure(e);
567
+ userOnLayout(e);
568
+ } : measure
569
+ };
570
+ }
571
+ if (HOVER_MODIFIER_RE.test(classStrRaw)) {
572
+ const userOnHoverIn = hostRestWithLayout.onHoverIn;
573
+ const userOnHoverOut = hostRestWithLayout.onHoverOut;
574
+ hostRestWithLayout = {
575
+ ...hostRestWithLayout,
576
+ onHoverIn: (e) => {
577
+ setIsHovered(true);
578
+ userOnHoverIn?.(e);
579
+ },
580
+ onHoverOut: (e) => {
581
+ setIsHovered(false);
582
+ userOnHoverOut?.(e);
583
+ }
584
+ };
585
+ }
586
+ if (FOCUS_MODIFIER_RE.test(classStrRaw)) {
587
+ const userOnFocus = hostRestWithLayout.onFocus;
588
+ const userOnBlur = hostRestWithLayout.onBlur;
589
+ hostRestWithLayout = {
590
+ ...hostRestWithLayout,
591
+ onFocus: (e) => {
592
+ setIsFocused(true);
593
+ userOnFocus?.(e);
594
+ },
595
+ onBlur: (e) => {
596
+ setIsFocused(false);
597
+ userOnBlur?.(e);
598
+ }
599
+ };
600
+ }
601
+ const states = { hover: isHovered, focus: isFocused, disabled: hostRest.disabled === true };
602
+ const finalStyle = hostType === import_react_native.Pressable ? (state) => resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, state.pressed, layoutOverrides, states) : resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, false, layoutOverrides, states);
603
+ return makeElement(isStaticChildren, hostType, { ...hostRestWithLayout, style: finalStyle }, elementKey);
604
+ }
605
+ function processElement(resolveStyle2, type, rawProps, key, isStaticChildren) {
606
+ if (type === null || typeof type === "symbol" || !rawProps) {
607
+ return makeElement(isStaticChildren, type, rawProps ?? {}, key);
608
+ }
609
+ const { className: classStrRaw, style: userStyle, ...rest } = rawProps;
610
+ if (typeof classStrRaw !== "string") {
611
+ return makeElement(isStaticChildren, type, rawProps, key);
612
+ }
613
+ if (DARK_MODIFIER_RE.test(classStrRaw) || BREAKPOINT_MODIFIER_RE.test(classStrRaw) || HOVER_MODIFIER_RE.test(classStrRaw) || FOCUS_MODIFIER_RE.test(classStrRaw) || classStrRaw.includes("var(--") || PERCENT_RELATIVE_CALC_HINT_RE.test(classStrRaw)) {
614
+ return (0, import_jsx_runtime.jsx)(
615
+ ReactiveElement,
616
+ { hostType: type, hostRest: rest, classStrRaw, userStyle, resolveStyle: resolveStyle2, elementKey: key, isStaticChildren },
617
+ key
618
+ );
619
+ }
620
+ const staticStates = { hover: false, focus: false, disabled: rest.disabled === true };
621
+ const finalStyle = type === import_react_native.Pressable ? (state) => resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, state.pressed, void 0, staticStates) : resolvedStyleFor(resolveStyle2, classStrRaw, userStyle, false, void 0, staticStates);
622
+ return makeElement(isStaticChildren, type, { ...rest, style: finalStyle }, key);
623
+ }
624
+ function createJsxFunctions(resolveStyle2) {
625
+ function jsx2(type, props, key) {
626
+ return processElement(resolveStyle2, type, props, key, false);
627
+ }
628
+ function jsxs2(type, props, key) {
629
+ return processElement(resolveStyle2, type, props, key, true);
630
+ }
631
+ return { jsx: jsx2, jsxs: jsxs2 };
632
+ }
633
+
634
+ // src/nativeBridge.ts
635
+ var import_react_native2 = require("react-native");
636
+ var import_theme = require("./theme");
637
+ var import_darkModeStore2 = require("./darkModeStore");
638
+
598
639
  // src/jsEngine/shared.ts
599
640
  function decl(property, value) {
600
641
  return { property, value };
@@ -625,11 +666,42 @@ function resolveNegatableLength(theme, parsed) {
625
666
  if (px === 0) return "0px";
626
667
  return `-${px}px`;
627
668
  }
669
+ function resolvePercent(parsed) {
670
+ if (parsed.negative) return null;
671
+ const value = parsed.value;
672
+ if (value === null) return null;
673
+ if (parsed.isArbitrary) return value;
674
+ const pct = Number(value);
675
+ if (!Number.isFinite(pct) || value.trim() === "") return null;
676
+ return String(pct / 100);
677
+ }
628
678
 
629
679
  // src/jsEngine/resolvers/layout.ts
630
680
  function negateRaw(value, negative) {
631
681
  return negative ? `-${value}` : value;
632
682
  }
683
+ function overflowAxisValue(property, value) {
684
+ switch (value) {
685
+ case "auto":
686
+ case "hidden":
687
+ case "clip":
688
+ case "visible":
689
+ case "scroll":
690
+ return [decl(property, value)];
691
+ default:
692
+ return null;
693
+ }
694
+ }
695
+ function overscrollValue(property, value) {
696
+ switch (value) {
697
+ case "auto":
698
+ case "contain":
699
+ case "none":
700
+ return [decl(property, value)];
701
+ default:
702
+ return null;
703
+ }
704
+ }
633
705
  function resolve(parsed, theme) {
634
706
  switch (parsed.utility) {
635
707
  case "flex":
@@ -676,6 +748,12 @@ function resolve(parsed, theme) {
676
748
  return [decl("justify-content", "space-around")];
677
749
  case "justify-evenly":
678
750
  return [decl("justify-content", "space-evenly")];
751
+ case "justify-normal":
752
+ return [decl("justify-content", "normal")];
753
+ case "justify-stretch":
754
+ return [decl("justify-content", "stretch")];
755
+ case "content-normal":
756
+ return [decl("align-content", "normal")];
679
757
  case "content-start":
680
758
  return [decl("align-content", "flex-start")];
681
759
  case "content-end":
@@ -710,6 +788,18 @@ function resolve(parsed, theme) {
710
788
  return [decl("overflow", "scroll")];
711
789
  case "overflow-visible":
712
790
  return [decl("overflow", "visible")];
791
+ case "overflow-clip":
792
+ return [decl("overflow", "clip")];
793
+ case "overflow-x":
794
+ return parsed.value === null ? null : overflowAxisValue("overflow-x", parsed.value);
795
+ case "overflow-y":
796
+ return parsed.value === null ? null : overflowAxisValue("overflow-y", parsed.value);
797
+ case "overscroll":
798
+ return parsed.value === null ? null : overscrollValue("overscroll-behavior", parsed.value);
799
+ case "overscroll-x":
800
+ return parsed.value === null ? null : overscrollValue("overscroll-behavior-x", parsed.value);
801
+ case "overscroll-y":
802
+ return parsed.value === null ? null : overscrollValue("overscroll-behavior-y", parsed.value);
713
803
  case "static":
714
804
  return [decl("position", "static")];
715
805
  case "relative":
@@ -750,10 +840,43 @@ function resolve(parsed, theme) {
750
840
  const v = resolveNegatableLength(theme, parsed);
751
841
  return v === null ? null : [decl("inset", v)];
752
842
  }
753
- case "aspect-square":
754
- return [decl("aspect-ratio", "1 / 1")];
755
- case "aspect-video":
756
- return [decl("aspect-ratio", "16 / 9")];
843
+ case "inset-x": {
844
+ const v = resolveNegatableLength(theme, parsed);
845
+ return v === null ? null : [decl("left", v), decl("right", v)];
846
+ }
847
+ case "inset-y": {
848
+ const v = resolveNegatableLength(theme, parsed);
849
+ return v === null ? null : [decl("top", v), decl("bottom", v)];
850
+ }
851
+ // Logical inset — just a different CSS property name, same reasoning
852
+ // as Rust's layout.rs (no direction-tracking logic needed here).
853
+ case "start": {
854
+ const v = resolveNegatableLength(theme, parsed);
855
+ return v === null ? null : [decl("inset-inline-start", v)];
856
+ }
857
+ case "end": {
858
+ const v = resolveNegatableLength(theme, parsed);
859
+ return v === null ? null : [decl("inset-inline-end", v)];
860
+ }
861
+ // "aspect-" is a registered VALUE_PREFIXES entry (parser.ts), so
862
+ // "aspect-square"/"aspect-video"/"aspect-auto"/arbitrary all arrive
863
+ // here as utility="aspect" + a value, mirroring layout.rs's own
864
+ // "aspect" arm.
865
+ case "aspect": {
866
+ const value = parsed.value;
867
+ if (value === null) return null;
868
+ if (parsed.isArbitrary) return [decl("aspect-ratio", value)];
869
+ switch (value) {
870
+ case "square":
871
+ return [decl("aspect-ratio", "1 / 1")];
872
+ case "video":
873
+ return [decl("aspect-ratio", "16 / 9")];
874
+ case "auto":
875
+ return [decl("aspect-ratio", "auto")];
876
+ default:
877
+ return null;
878
+ }
879
+ }
757
880
  default:
758
881
  return null;
759
882
  }
@@ -1280,6 +1403,16 @@ function textSize(key) {
1280
1403
  return "1.875rem";
1281
1404
  case "4xl":
1282
1405
  return "2.25rem";
1406
+ case "5xl":
1407
+ return "3rem";
1408
+ case "6xl":
1409
+ return "3.75rem";
1410
+ case "7xl":
1411
+ return "4.5rem";
1412
+ case "8xl":
1413
+ return "6rem";
1414
+ case "9xl":
1415
+ return "8rem";
1283
1416
  default:
1284
1417
  return null;
1285
1418
  }
@@ -1316,6 +1449,12 @@ function textAlign(key) {
1316
1449
  return "right";
1317
1450
  case "justify":
1318
1451
  return "justify";
1452
+ // Logical alignment — same "no direction-tracking logic needed" reasoning
1453
+ // as layout.rs's start/end inset properties.
1454
+ case "start":
1455
+ return "start";
1456
+ case "end":
1457
+ return "end";
1319
1458
  default:
1320
1459
  return null;
1321
1460
  }
@@ -1324,6 +1463,10 @@ function fontWeight(key) {
1324
1463
  switch (key) {
1325
1464
  case "thin":
1326
1465
  return "100";
1466
+ case "extralight":
1467
+ return "200";
1468
+ case "light":
1469
+ return "300";
1327
1470
  case "normal":
1328
1471
  return "400";
1329
1472
  case "medium":
@@ -1334,6 +1477,22 @@ function fontWeight(key) {
1334
1477
  return "700";
1335
1478
  case "extrabold":
1336
1479
  return "800";
1480
+ case "black":
1481
+ return "900";
1482
+ default:
1483
+ return null;
1484
+ }
1485
+ }
1486
+ function fontFamilyValue(theme, key) {
1487
+ const fromTheme = theme.fontFamily?.[key];
1488
+ if (fromTheme !== void 0) return fromTheme;
1489
+ switch (key) {
1490
+ case "sans":
1491
+ return 'ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"';
1492
+ case "serif":
1493
+ return 'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif';
1494
+ case "mono":
1495
+ return 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
1337
1496
  default:
1338
1497
  return null;
1339
1498
  }
@@ -1376,12 +1535,21 @@ function nativeShadowDeclarations(parsed) {
1376
1535
  }
1377
1536
 
1378
1537
  // src/jsEngine/resolveUtilityNative.ts
1379
- function resolveTypographyNative(parsed) {
1538
+ function firstFontName(stack) {
1539
+ const first = stack.split(",")[0] ?? stack;
1540
+ return first.trim().replace(/^["']|["']$/g, "");
1541
+ }
1542
+ function resolveTypographyNative(parsed, theme) {
1380
1543
  switch (parsed.utility) {
1381
1544
  case "font": {
1382
1545
  if (parsed.value === null) return null;
1546
+ if (parsed.isArbitrary) {
1547
+ return [decl("font-family", firstFontName(parsed.value))];
1548
+ }
1383
1549
  const w = fontWeight(parsed.value);
1384
- return w === null ? null : [decl("font-weight", w)];
1550
+ if (w !== null) return [decl("font-weight", w)];
1551
+ const family = fontFamilyValue(theme, parsed.value);
1552
+ return family === null ? null : [decl("font-family", firstFontName(family))];
1385
1553
  }
1386
1554
  case "uppercase":
1387
1555
  return [decl("text-transform", "uppercase")];
@@ -1441,8 +1609,13 @@ function resolveColorNative(parsed, theme) {
1441
1609
  return null;
1442
1610
  }
1443
1611
  }
1612
+ function resolveOpacityNative(parsed) {
1613
+ if (parsed.utility !== "opacity") return null;
1614
+ const v = resolvePercent(parsed);
1615
+ return v === null ? null : [decl("opacity", v)];
1616
+ }
1444
1617
  function resolveUtilityNative(parsed, theme) {
1445
- return resolveFlex(parsed, false) ?? resolve(parsed, theme) ?? resolve2(parsed, theme) ?? resolve3(parsed, theme) ?? resolveColorNative(parsed, theme) ?? resolveLeadingTrackingNative(parsed) ?? resolveTypographyNative(parsed) ?? nativeShadowDeclarations(parsed);
1618
+ return resolveFlex(parsed, false) ?? resolve(parsed, theme) ?? resolve2(parsed, theme) ?? resolve3(parsed, theme) ?? resolveColorNative(parsed, theme) ?? resolveLeadingTrackingNative(parsed) ?? resolveTypographyNative(parsed, theme) ?? resolveOpacityNative(parsed) ?? nativeShadowDeclarations(parsed);
1446
1619
  }
1447
1620
 
1448
1621
  // src/jsEngine/resolveStyle.ts
@@ -1499,6 +1672,7 @@ var NUMERIC_LENGTH_PROPS = /* @__PURE__ */ new Set([
1499
1672
  "shadow-opacity",
1500
1673
  "shadow-radius",
1501
1674
  "elevation",
1675
+ "opacity",
1502
1676
  // Per-side border width + per-corner radius — see resolvers/border.ts's
1503
1677
  // new borderSideValue/borderAxisValue/resolveRadiusSide additions; RN's
1504
1678
  // style system wants plain numbers for these exactly like the generic
@@ -1586,11 +1760,11 @@ function resolveStyle(classString, pressed = false) {
1586
1760
  const width = import_react_native2.Dimensions.get("window").width;
1587
1761
  const KbachModule = import_react_native2.TurboModuleRegistry.get("KbachModule");
1588
1762
  if (!KbachModule) {
1589
- const { style: style2, warnings: warnings2 } = resolveStyleJsWithWarnings(classString, (0, import_theme2.getTheme)(), colorScheme, pressed, width);
1763
+ const { style: style2, warnings: warnings2 } = resolveStyleJsWithWarnings(classString, (0, import_theme.getTheme)(), colorScheme, pressed, width);
1590
1764
  warnIfDev(classString, warnings2);
1591
1765
  return style2;
1592
1766
  }
1593
- const json = KbachModule.resolveStyle(classString, (0, import_theme2.getThemeJson)(), colorScheme, pressed, width);
1767
+ const json = KbachModule.resolveStyle(classString, (0, import_theme.getThemeJson)(), colorScheme, pressed, width);
1594
1768
  const style = JSON.parse(json);
1595
1769
  const warnings = style.__kbachWarnings;
1596
1770
  if (warnings !== void 0) {