@kbach/react 0.5.38 → 0.5.41

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.
@@ -543,12 +543,13 @@ var defaultTheme = {
543
543
 
544
544
  // src/core/platform.ts
545
545
  var isWeb = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
546
+ var isNative = !isWeb && (typeof globalThis.HermesInternal !== "undefined" || typeof globalThis.__fbBatchedBridge !== "undefined" || typeof navigator !== "undefined" && navigator.product === "ReactNative");
546
547
  var _cssGenMode = false;
547
548
  function setCSSGenMode(on) {
548
549
  _cssGenMode = on;
549
550
  }
550
551
  function getEffectiveIsWeb() {
551
- return isWeb || _cssGenMode;
552
+ return isWeb || _cssGenMode || !isNative;
552
553
  }
553
554
  function toNativeValue(raw) {
554
555
  if (/^-?\d+(\.\d+)?px$/.test(raw)) return parseFloat(raw);
@@ -561,773 +562,116 @@ function escapeCSSSelector(cls) {
561
562
  return cls.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
562
563
  }
563
564
 
564
- // src/core/parser.ts
565
- var PLUGIN_MODIFIERS = /* @__PURE__ */ new Set();
566
- function registerModifier(name) {
567
- PLUGIN_MODIFIERS.add(name);
565
+ // src/core/registry.ts
566
+ var BUILTIN_MODIFIERS = {
567
+ // ── Mode ─────────────────────────────────────────────────────────────────
568
+ dark: { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
569
+ "not-light": { darkScheme: "dark", jsBehavior: "mode", jsMatch: (d) => d },
570
+ light: { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
571
+ "not-dark": { darkScheme: "light", jsBehavior: "mode", jsMatch: (d) => !d },
572
+ // ── Interactive — JS state + CSS pseudo ───────────────────────────────────
573
+ hover: { pseudo: ":hover", jsBehavior: "interactive", jsMatch: (_, s) => !!s.hover },
574
+ "not-hover": { pseudo: ":not(:hover)", jsBehavior: "interactive", jsMatch: (_, s) => !s.hover },
575
+ focus: { pseudo: ":focus", jsBehavior: "interactive", jsMatch: (_, s) => !!s.focus },
576
+ "not-focus": { pseudo: ":not(:focus)", jsBehavior: "interactive", jsMatch: (_, s) => !s.focus },
577
+ active: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.active || !!s.pressed },
578
+ "not-active": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.active && !s.pressed },
579
+ pressed: { pseudo: ":active", jsBehavior: "interactive", jsMatch: (_, s) => !!s.pressed || !!s.active },
580
+ "not-pressed": { pseudo: ":not(:active)", jsBehavior: "interactive", jsMatch: (_, s) => !s.pressed && !s.active },
581
+ disabled: { pseudo: ":disabled", jsBehavior: "interactive", jsMatch: (_, s) => !!s.disabled },
582
+ "not-disabled": { pseudo: ":not(:disabled)", jsBehavior: "interactive", jsMatch: (_, s) => !s.disabled },
583
+ checked: { pseudo: ":checked", jsBehavior: "interactive", jsMatch: (_, s) => !!s.checked },
584
+ "not-checked": { pseudo: ":not(:checked)", jsBehavior: "interactive", jsMatch: (_, s) => !s.checked },
585
+ visited: { pseudo: ":visited", jsBehavior: "interactive", jsMatch: (_, s) => !!s.visited },
586
+ "not-visited": { pseudo: ":not(:visited)", jsBehavior: "interactive", jsMatch: (_, s) => !s.visited },
587
+ placeholder: { pseudo: "::placeholder", jsBehavior: "interactive", jsMatch: (_, s) => !!s.placeholder },
588
+ // ── CSS-only pseudo-classes (structural) ──────────────────────────────────
589
+ first: { pseudo: ":first-child", jsBehavior: "css-only", forcesImportant: true },
590
+ last: { pseudo: ":last-child", jsBehavior: "css-only", forcesImportant: true },
591
+ odd: { pseudo: ":nth-child(odd)", jsBehavior: "css-only", forcesImportant: true },
592
+ even: { pseudo: ":nth-child(even)", jsBehavior: "css-only", forcesImportant: true },
593
+ only: { pseudo: ":only-child", jsBehavior: "css-only", forcesImportant: true },
594
+ "focus-within": { pseudo: ":focus-within", jsBehavior: "css-only", forcesImportant: true },
595
+ "focus-visible": { pseudo: ":focus-visible", jsBehavior: "css-only", forcesImportant: true },
596
+ // ── CSS-only pseudo-elements ───────────────────────────────────────────────
597
+ before: { pseudo: "::before", jsBehavior: "css-only" },
598
+ after: { pseudo: "::after", jsBehavior: "css-only" },
599
+ selection: { pseudo: "::selection", jsBehavior: "css-only" },
600
+ "first-letter": { pseudo: "::first-letter", jsBehavior: "css-only" },
601
+ "first-line": { pseudo: "::first-line", jsBehavior: "css-only" },
602
+ marker: { pseudo: "::marker", jsBehavior: "css-only" },
603
+ // ── Group / peer ancestor selectors (CSS-only) ─────────────────────────────
604
+ "group-hover": { ancestorSelector: ".group:hover ", jsBehavior: "css-only", forcesImportant: true },
605
+ "group-focus": { ancestorSelector: ".group:focus ", jsBehavior: "css-only", forcesImportant: true },
606
+ "peer-hover": { ancestorSelector: ".peer:hover ~ ", jsBehavior: "css-only", forcesImportant: true },
607
+ "peer-focus": { ancestorSelector: ".peer:focus ~ ", jsBehavior: "css-only", forcesImportant: true },
608
+ // ── Responsive — both CSS (@media min-width) and JS (breakpoints set) ──────
609
+ sm: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("sm") },
610
+ md: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("md") },
611
+ lg: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("lg") },
612
+ xl: { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("xl") },
613
+ "2xl": { isResponsive: true, jsBehavior: "responsive", jsMatch: (_, __, bp) => bp.has("2xl") },
614
+ // ── Print media (CSS-only) ─────────────────────────────────────────────────
615
+ print: { mediaQuery: "print", jsBehavior: "css-only", forcesImportant: true },
616
+ // ── Orientation / accessibility media (CSS-only) ───────────────────────────
617
+ landscape: { mediaQuery: "(orientation: landscape)", jsBehavior: "css-only", forcesImportant: true },
618
+ portrait: { mediaQuery: "(orientation: portrait)", jsBehavior: "css-only", forcesImportant: true },
619
+ "motion-reduce": { mediaQuery: "(prefers-reduced-motion: reduce)", jsBehavior: "css-only", forcesImportant: true },
620
+ "motion-safe": { mediaQuery: "(prefers-reduced-motion: no-preference)", jsBehavior: "css-only", forcesImportant: true },
621
+ "contrast-more": { mediaQuery: "(prefers-contrast: more)", jsBehavior: "css-only", forcesImportant: true },
622
+ "contrast-less": { mediaQuery: "(prefers-contrast: less)", jsBehavior: "css-only", forcesImportant: true },
623
+ // ── Directionality (CSS-only) ──────────────────────────────────────────────
624
+ rtl: { dirSelector: '[dir="rtl"] ', jsBehavior: "css-only", forcesImportant: true },
625
+ ltr: { dirSelector: '[dir="ltr"] ', jsBehavior: "css-only", forcesImportant: true }
626
+ };
627
+ var _pluginModifiers = {};
628
+ var _allNames = null;
629
+ var _interactiveNames = null;
630
+ var _modeNames = null;
631
+ var _responsiveNames = null;
632
+ function _invalidate() {
633
+ _allNames = null;
634
+ _interactiveNames = null;
635
+ _modeNames = null;
636
+ _responsiveNames = null;
637
+ }
638
+ function registerModifier(name, def) {
639
+ _pluginModifiers[name] = def;
640
+ _invalidate();
568
641
  }
569
642
  function clearPluginModifiers() {
570
- PLUGIN_MODIFIERS.clear();
571
- }
572
- var MODIFIERS = /* @__PURE__ */ new Set([
573
- // Theme
574
- "dark",
575
- "light",
576
- "not-dark",
577
- "not-light",
578
- // Interaction
579
- "hover",
580
- "focus",
581
- "active",
582
- "visited",
583
- "disabled",
584
- "checked",
585
- "pressed",
586
- "placeholder",
587
- "focus-within",
588
- "focus-visible",
589
- // Negated interaction
590
- "not-hover",
591
- "not-focus",
592
- "not-active",
593
- "not-visited",
594
- "not-disabled",
595
- "not-checked",
596
- "not-pressed",
597
- // Structural
598
- "first",
599
- "last",
600
- "odd",
601
- "even",
602
- "only",
603
- // Group / peer
604
- "group-hover",
605
- "group-focus",
606
- "peer-hover",
607
- "peer-focus",
608
- // Responsive (handled separately but accepted)
609
- "sm",
610
- "md",
611
- "lg",
612
- "xl",
613
- "2xl",
614
- // Pseudo-elements (CSS-injection only; matchesMods returns false for these)
615
- "before",
616
- "after",
617
- "selection",
618
- "first-letter",
619
- "first-line",
620
- "marker",
621
- // Print media modifier
622
- "print",
623
- // Orientation media modifiers (CSS-injection only)
624
- "landscape",
625
- "portrait",
626
- // Accessibility media modifiers (CSS-injection only)
627
- "motion-reduce",
628
- "motion-safe",
629
- "contrast-more",
630
- "contrast-less",
631
- // Directionality modifiers (CSS-injection only)
632
- "rtl",
633
- "ltr"
634
- ]);
635
- var UTILITY_PREFIXES = [
636
- // Multi-word flex
637
- "flex-row-reverse",
638
- "flex-col-reverse",
639
- "flex-row",
640
- "flex-col",
641
- "flex-wrap-reverse",
642
- "flex-wrap",
643
- "flex-nowrap",
644
- "flex-shrink-0",
645
- "flex-shrink",
646
- "flex-grow-0",
647
- "flex-grow",
648
- "items-start",
649
- "items-end",
650
- "items-center",
651
- "items-baseline",
652
- "items-stretch",
653
- "justify-start",
654
- "justify-end",
655
- "justify-center",
656
- "justify-between",
657
- "justify-around",
658
- "justify-evenly",
659
- "content-start",
660
- "content-end",
661
- "content-center",
662
- "content-between",
663
- "content-around",
664
- "content-evenly",
665
- "self-start",
666
- "self-end",
667
- "self-center",
668
- "self-auto",
669
- "self-stretch",
670
- "text-left",
671
- "text-right",
672
- "text-center",
673
- "text-justify",
674
- "font-thin",
675
- "font-extralight",
676
- "font-light",
677
- "font-normal",
678
- "font-medium",
679
- "font-semibold",
680
- "font-bold",
681
- "font-extrabold",
682
- "font-black",
683
- "overflow-hidden",
684
- "overflow-visible",
685
- "overflow-scroll",
686
- "overflow-auto",
687
- "overflow-x-hidden",
688
- "overflow-x-scroll",
689
- "overflow-x-auto",
690
- "overflow-y-hidden",
691
- "overflow-y-scroll",
692
- "overflow-y-auto",
693
- "object-contain",
694
- "object-cover",
695
- "object-fill",
696
- "object-none",
697
- "object-scale-down",
698
- "border-solid",
699
- "border-dashed",
700
- "border-dotted",
701
- "border-none",
702
- "border-t",
703
- "border-r",
704
- "border-b",
705
- "border-l",
706
- "rounded-tl",
707
- "rounded-tr",
708
- "rounded-bl",
709
- "rounded-br",
710
- "rounded-t",
711
- "rounded-r",
712
- "rounded-b",
713
- "rounded-l",
714
- "list-none",
715
- "list-disc",
716
- "list-decimal",
717
- "cursor-auto",
718
- "cursor-default",
719
- "cursor-pointer",
720
- "cursor-wait",
721
- "cursor-text",
722
- "cursor-move",
723
- "cursor-not-allowed",
724
- "select-none",
725
- "select-text",
726
- "select-all",
727
- "select-auto",
728
- "pointer-events-none",
729
- "pointer-events-auto",
730
- "whitespace-normal",
731
- "whitespace-nowrap",
732
- "whitespace-pre-wrap",
733
- "whitespace-pre-line",
734
- "whitespace-pre",
735
- "break-normal",
736
- "break-words",
737
- "break-all",
738
- "break-keep",
739
- "bg-clip-border",
740
- "bg-clip-padding",
741
- "bg-clip-content",
742
- "bg-clip-text",
743
- "bg-gradient-to",
744
- "resize-none",
745
- "resize-y",
746
- "resize-x",
747
- "box-border",
748
- "box-content",
749
- "gap-x",
750
- "gap-y",
751
- "inset-x",
752
- "inset-y",
753
- "divide-x",
754
- "divide-y",
755
- "space-x",
756
- "space-y",
757
- "translate-x",
758
- "translate-y",
759
- "scale-x",
760
- "scale-y",
761
- "skew-x",
762
- "skew-y",
763
- // Transform origin (single prefix, value carries direction)
764
- "origin",
765
- "min-w",
766
- "min-h",
767
- "max-w",
768
- "max-h",
769
- "ring-offset",
770
- "bg-opacity",
771
- "text-opacity",
772
- "border-opacity",
773
- // Grid placement
774
- "col-span",
775
- "col-start",
776
- "col-end",
777
- "row-span",
778
- "row-start",
779
- "row-end",
780
- "grid-cols",
781
- "grid-rows",
782
- "grid-flow",
783
- "auto-cols",
784
- "auto-rows",
785
- // Grid alignment
786
- "place-items",
787
- "place-content",
788
- "place-self",
789
- "justify-items",
790
- "justify-self",
791
- // Backdrop filters (longer than 'backdrop' alone)
792
- "backdrop-blur",
793
- "backdrop-brightness",
794
- "backdrop-contrast",
795
- "backdrop-grayscale",
796
- "backdrop-hue-rotate",
797
- "backdrop-invert",
798
- "backdrop-opacity",
799
- "backdrop-saturate",
800
- "backdrop-sepia",
801
- "backdrop-filter",
802
- // Filters
803
- "drop-shadow",
804
- "hue-rotate",
805
- "text-shadow",
806
- "underline-offset",
807
- "outline-offset",
808
- "will-change",
809
- "mix-blend",
810
- "bg-blend",
811
- "decoration",
812
- "perspective",
813
- "tint",
814
- "animate",
815
- // Single-word prefixes last
816
- "appearance-none",
817
- "outline-none",
818
- "outline",
819
- "inline-flex",
820
- "inline-block",
821
- "inline-grid",
822
- "italic",
823
- "non-italic",
824
- "underline",
825
- "overline",
826
- "line-through",
827
- "no-underline",
828
- "uppercase",
829
- "lowercase",
830
- "capitalize",
831
- "normal-case",
832
- "antialiased",
833
- "subpixel-antialiased",
834
- "overflow-ellipsis",
835
- "truncate",
836
- "sr-only",
837
- "not-sr-only",
838
- "relative",
839
- "absolute",
840
- "fixed",
841
- "sticky",
842
- "static",
843
- "visible",
844
- "invisible",
845
- "hidden",
846
- "contents",
847
- "flow-root",
848
- "block",
849
- "inline",
850
- "flex",
851
- "grid",
852
- "resize",
853
- "appearance",
854
- "border",
855
- "rounded",
856
- "shadow",
857
- "size",
858
- "opacity",
859
- "leading",
860
- "tracking",
861
- "line-clamp",
862
- "basis",
863
- "grow",
864
- "shrink",
865
- "order",
866
- "delay",
867
- "duration",
868
- "scale",
869
- "rotate",
870
- "aspect",
871
- "columns",
872
- "ring",
873
- "gap",
874
- "inset",
875
- "filter",
876
- "transform",
877
- "blur",
878
- "brightness",
879
- "contrast",
880
- "grayscale",
881
- "invert",
882
- "saturate",
883
- "sepia",
884
- "bg",
885
- "text",
886
- "font",
887
- "caret",
888
- "accent",
889
- "from",
890
- "via",
891
- "to",
892
- "divide",
893
- "space",
894
- "transition",
895
- "px",
896
- "py",
897
- "pt",
898
- "pr",
899
- "pb",
900
- "pl",
901
- "p",
902
- "mx",
903
- "my",
904
- "mt",
905
- "mr",
906
- "mb",
907
- "ml",
908
- "m",
909
- "w",
910
- "h",
911
- "top",
912
- "right",
913
- "bottom",
914
- "left",
915
- "z",
916
- "col",
917
- "row"
918
- ];
919
- var SORTED_PREFIXES = [...new Set(UTILITY_PREFIXES)].sort((a, b) => b.length - a.length);
920
- var STANDALONE_UTILITIES = /* @__PURE__ */ new Set([
921
- // Display
922
- "flex",
923
- "block",
924
- "inline-block",
925
- "inline",
926
- "grid",
927
- "inline-flex",
928
- "inline-grid",
929
- "grd",
930
- "hidden",
931
- "contents",
932
- "flow-root",
933
- // Position
934
- "relative",
935
- "absolute",
936
- "fixed",
937
- "sticky",
938
- "static",
939
- // Visibility
940
- "visible",
941
- "invisible",
942
- // Typography
943
- "uppercase",
944
- "lowercase",
945
- "capitalize",
946
- "normal-case",
947
- "italic",
948
- "non-italic",
949
- "underline",
950
- "overline",
951
- "line-through",
952
- "no-underline",
953
- "truncate",
954
- "antialiased",
955
- "sr-only",
956
- "not-sr-only",
957
- // Font variant numeric
958
- "normal-nums",
959
- "ordinal",
960
- "slashed-zero",
961
- "lining-nums",
962
- "oldstyle-nums",
963
- "proportional-nums",
964
- "tabular-nums",
965
- "diagonal-fractions",
966
- "stacked-fractions",
967
- // Flexbox
968
- "flex-row",
969
- "flex-col",
970
- "flex-row-reverse",
971
- "flex-col-reverse",
972
- "flex-wrap",
973
- "flex-wrap-reverse",
974
- "flex-nowrap",
975
- "flex-shrink",
976
- "flex-shrink-0",
977
- "flex-grow",
978
- "flex-grow-0",
979
- "items-start",
980
- "items-end",
981
- "items-center",
982
- "items-baseline",
983
- "items-stretch",
984
- "justify-start",
985
- "justify-end",
986
- "justify-center",
987
- "justify-between",
988
- "justify-around",
989
- "justify-evenly",
990
- "content-start",
991
- "content-end",
992
- "content-center",
993
- "content-between",
994
- "content-around",
995
- "content-evenly",
996
- "content-stretch",
997
- "self-start",
998
- "self-end",
999
- "self-center",
1000
- "self-auto",
1001
- "self-stretch",
1002
- "self-baseline",
1003
- // Text align
1004
- "text-left",
1005
- "text-right",
1006
- "text-center",
1007
- "text-justify",
1008
- // Font weight shortcuts
1009
- "font-thin",
1010
- "font-extralight",
1011
- "font-light",
1012
- "font-normal",
1013
- "font-medium",
1014
- "font-semibold",
1015
- "font-bold",
1016
- "font-extrabold",
1017
- "font-black",
1018
- // Overflow
1019
- "overflow-hidden",
1020
- "overflow-visible",
1021
- "overflow-scroll",
1022
- "overflow-auto",
1023
- "overflow-x-hidden",
1024
- "overflow-x-scroll",
1025
- "overflow-x-auto",
1026
- "overflow-y-hidden",
1027
- "overflow-y-scroll",
1028
- "overflow-y-auto",
1029
- // Object fit
1030
- "object-contain",
1031
- "object-cover",
1032
- "object-fill",
1033
- "object-none",
1034
- "object-scale-down",
1035
- // Object position
1036
- "object-center",
1037
- "object-top",
1038
- "object-bottom",
1039
- "object-left",
1040
- "object-right",
1041
- "object-left-top",
1042
- "object-left-bottom",
1043
- "object-right-top",
1044
- "object-right-bottom",
1045
- // Border
1046
- "border-solid",
1047
- "border-dashed",
1048
- "border-dotted",
1049
- "border-none",
1050
- "border-t",
1051
- "border-r",
1052
- "border-b",
1053
- "border-l",
1054
- "border-collapse",
1055
- "border-separate",
1056
- // Lists
1057
- "list-none",
1058
- "list-disc",
1059
- "list-decimal",
1060
- "list-inside",
1061
- "list-outside",
1062
- // Cursor / select
1063
- "cursor-auto",
1064
- "cursor-default",
1065
- "cursor-pointer",
1066
- "cursor-wait",
1067
- "cursor-text",
1068
- "cursor-move",
1069
- "cursor-not-allowed",
1070
- "select-none",
1071
- "select-text",
1072
- "select-all",
1073
- "select-auto",
1074
- "pointer-events-none",
1075
- "pointer-events-auto",
1076
- // Whitespace / word break
1077
- "whitespace-normal",
1078
- "whitespace-nowrap",
1079
- "whitespace-pre",
1080
- "whitespace-pre-wrap",
1081
- "whitespace-pre-line",
1082
- "break-normal",
1083
- "break-words",
1084
- "break-all",
1085
- // Background clip
1086
- "bg-clip-border",
1087
- "bg-clip-padding",
1088
- "bg-clip-content",
1089
- "bg-clip-text",
1090
- // Background size
1091
- "bg-auto",
1092
- "bg-cover",
1093
- "bg-contain",
1094
- // Background position
1095
- "bg-center",
1096
- "bg-top",
1097
- "bg-bottom",
1098
- "bg-left",
1099
- "bg-right",
1100
- "bg-left-top",
1101
- "bg-left-bottom",
1102
- "bg-right-top",
1103
- "bg-right-bottom",
1104
- // Background repeat
1105
- "bg-repeat",
1106
- "bg-no-repeat",
1107
- "bg-repeat-x",
1108
- "bg-repeat-y",
1109
- "bg-repeat-round",
1110
- "bg-repeat-space",
1111
- // Background attachment
1112
- "bg-fixed",
1113
- "bg-local",
1114
- "bg-scroll",
1115
- // Background image
1116
- "bg-none",
1117
- // Box sizing
1118
- "box-border",
1119
- "box-content",
1120
- // Resize
1121
- "resize",
1122
- "resize-none",
1123
- "resize-y",
1124
- "resize-x",
1125
- // Outline
1126
- "appearance-none",
1127
- "outline-none",
1128
- "outline",
1129
- // Table
1130
- "table",
1131
- "table-auto",
1132
- "table-fixed",
1133
- "caption-top",
1134
- "caption-bottom",
1135
- // CSS filters (standalone = default/full effect)
1136
- "grayscale",
1137
- "invert",
1138
- "sepia",
1139
- // Isolation
1140
- "isolate",
1141
- "isolation-auto",
1142
- // Backface visibility (both platforms)
1143
- "backface-visible",
1144
- "backface-hidden",
1145
- // Divide none
1146
- "divide-none",
1147
- // Group / peer markers (no-op style; needed so isKnownUtility recognises them)
1148
- "group",
1149
- "peer",
1150
- // Text-wrap (web-only)
1151
- "text-wrap",
1152
- "text-nowrap",
1153
- "text-balance",
1154
- "text-pretty",
1155
- // Screen sizing
1156
- "w-screen",
1157
- "min-h-screen",
1158
- "max-h-screen",
1159
- "min-w-screen",
1160
- "max-w-screen",
1161
- // max-w named container sizes (Tailwind compat)
1162
- "max-w-none",
1163
- "max-w-xs",
1164
- "max-w-sm",
1165
- "max-w-md",
1166
- "max-w-lg",
1167
- "max-w-xl",
1168
- "max-w-2xl",
1169
- "max-w-3xl",
1170
- "max-w-4xl",
1171
- "max-w-5xl",
1172
- "max-w-6xl",
1173
- "max-w-7xl",
1174
- "max-w-prose",
1175
- // Extended cursors (web-only)
1176
- "cursor-grab",
1177
- "cursor-grabbing",
1178
- "cursor-zoom-in",
1179
- "cursor-zoom-out",
1180
- "cursor-crosshair",
1181
- "cursor-help",
1182
- "cursor-none",
1183
- // Overflow clip (web-only)
1184
- "overflow-clip",
1185
- "overflow-x-clip",
1186
- "overflow-y-clip",
1187
- // Scroll behavior (web-only)
1188
- "scroll-smooth",
1189
- "scroll-auto",
1190
- // Float & clear (web-only)
1191
- "float-left",
1192
- "float-right",
1193
- "float-start",
1194
- "float-end",
1195
- "float-none",
1196
- "clear-left",
1197
- "clear-right",
1198
- "clear-both",
1199
- "clear-start",
1200
- "clear-end",
1201
- "clear-none",
1202
- // Vertical align (web-only)
1203
- "align-baseline",
1204
- "align-top",
1205
- "align-middle",
1206
- "align-bottom",
1207
- "align-text-top",
1208
- "align-text-bottom",
1209
- "align-sub",
1210
- "align-super",
1211
- // Touch action (web-only)
1212
- "touch-auto",
1213
- "touch-none",
1214
- "touch-pan-x",
1215
- "touch-pan-y",
1216
- "touch-pan-left",
1217
- "touch-pan-right",
1218
- "touch-pan-up",
1219
- "touch-pan-down",
1220
- "touch-pinch-zoom",
1221
- "touch-manipulation"
1222
- ]);
1223
- function parseClass(className) {
1224
- const trimmed = className.trim();
1225
- if (!trimmed) return null;
1226
- const modifiers = [];
1227
- let remaining = trimmed;
1228
- for (let i = 0; i < 3; i++) {
1229
- const colonIdx = findOuterColon(remaining);
1230
- if (colonIdx === -1) break;
1231
- const candidate = remaining.slice(0, colonIdx);
1232
- if (MODIFIERS.has(candidate) || PLUGIN_MODIFIERS.has(candidate)) {
1233
- modifiers.push(candidate);
1234
- remaining = remaining.slice(colonIdx + 1);
1235
- } else {
1236
- break;
1237
- }
1238
- }
1239
- let important = false;
1240
- if (remaining.startsWith("!") && remaining.length > 1) {
1241
- important = true;
1242
- remaining = remaining.slice(1);
1243
- }
1244
- let negative = false;
1245
- if (remaining.startsWith("-") && remaining.length > 1 && remaining[1] !== "-") {
1246
- negative = true;
1247
- remaining = remaining.slice(1);
1248
- }
1249
- const bracketStart = remaining.lastIndexOf("-[");
1250
- if (bracketStart > 0 && remaining.endsWith("]")) {
1251
- const utility = remaining.slice(0, bracketStart);
1252
- const value = remaining.slice(bracketStart + 2, -1).replace(/_/g, " ");
1253
- return { original: trimmed, modifiers, negative, important, utility, value, isArbitrary: true };
1254
- }
1255
- if (STANDALONE_UTILITIES.has(remaining)) {
1256
- return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
1257
- }
1258
- for (const prefix of SORTED_PREFIXES) {
1259
- if (remaining === prefix) {
1260
- return { original: trimmed, modifiers, negative, important, utility: prefix, value: "", isArbitrary: false };
1261
- }
1262
- if (remaining.startsWith(prefix + "-")) {
1263
- const value = remaining.slice(prefix.length + 1);
1264
- return { original: trimmed, modifiers, negative, important, utility: prefix, value, isArbitrary: false };
1265
- }
1266
- }
1267
- const firstDash = remaining.indexOf("-");
1268
- if (firstDash > 0) {
1269
- return {
1270
- original: trimmed,
1271
- modifiers,
1272
- negative,
1273
- important,
1274
- utility: remaining.slice(0, firstDash),
1275
- value: remaining.slice(firstDash + 1),
1276
- isArbitrary: false
1277
- };
1278
- }
1279
- return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
643
+ for (const k of Object.keys(_pluginModifiers)) delete _pluginModifiers[k];
644
+ _invalidate();
1280
645
  }
1281
- function splitClassTokens(classString) {
1282
- const tokens = [];
1283
- let current = "";
1284
- let depth = 0;
1285
- for (let i = 0; i < classString.length; i++) {
1286
- const ch = classString[i];
1287
- if (ch === "[") {
1288
- depth++;
1289
- current += ch;
1290
- continue;
1291
- }
1292
- if (ch === "]") {
1293
- depth--;
1294
- current += ch;
1295
- continue;
1296
- }
1297
- if (/\s/.test(ch)) {
1298
- if (depth === 0) {
1299
- if (current) {
1300
- tokens.push(current);
1301
- current = "";
1302
- }
1303
- }
1304
- } else {
1305
- current += ch;
1306
- }
1307
- }
1308
- if (current) tokens.push(current);
1309
- return tokens;
646
+ function getModifier(name) {
647
+ return BUILTIN_MODIFIERS[name] ?? _pluginModifiers[name];
1310
648
  }
1311
- function normalizeClassString(classString) {
1312
- return splitClassTokens(classString).join(" ");
649
+ function isKnownModifier(name) {
650
+ return name in BUILTIN_MODIFIERS || name in _pluginModifiers;
1313
651
  }
1314
- function parseClasses(classString) {
1315
- const results = [];
1316
- for (const token of splitClassTokens(classString)) {
1317
- const parsed = parseClass(token);
1318
- if (parsed) results.push(parsed);
652
+ function _allEntries() {
653
+ return [...Object.entries(BUILTIN_MODIFIERS), ...Object.entries(_pluginModifiers)];
654
+ }
655
+ function getInteractiveModifiers() {
656
+ if (!_interactiveNames) {
657
+ _interactiveNames = new Set(_allEntries().filter(([, d]) => d.jsBehavior === "interactive").map(([k]) => k));
1319
658
  }
1320
- return results;
659
+ return _interactiveNames;
1321
660
  }
1322
- function findOuterColon(s) {
1323
- let depth = 0;
1324
- for (let i = 0; i < s.length; i++) {
1325
- const ch = s[i];
1326
- if (ch === "[") depth++;
1327
- else if (ch === "]") depth--;
1328
- else if (ch === ":" && depth === 0) return i;
661
+ function getModeModifiers() {
662
+ if (!_modeNames) {
663
+ _modeNames = new Set(_allEntries().filter(([, d]) => d.jsBehavior === "mode").map(([k]) => k));
1329
664
  }
1330
- return -1;
665
+ return _modeNames;
666
+ }
667
+ function getResponsiveModifiers() {
668
+ if (!_responsiveNames) {
669
+ _responsiveNames = new Set(_allEntries().filter(([, d]) => d.jsBehavior === "responsive").map(([k]) => k));
670
+ }
671
+ return _responsiveNames;
672
+ }
673
+ function matchModifier(name, isDark, state, breakpoints) {
674
+ return getModifier(name)?.jsMatch?.(isDark, state, breakpoints) ?? false;
1331
675
  }
1332
676
 
1333
677
  // src/core/utilities.ts
@@ -1421,6 +765,7 @@ function resolveSizing(value, spacing, isArbitrary) {
1421
765
  if (raw !== void 0) return raw;
1422
766
  if (/^\d+\/\d+$/.test(value)) {
1423
767
  const [num, den] = value.split("/").map(Number);
768
+ if (!den) return null;
1424
769
  return `${(num / den * 100).toFixed(6)}%`;
1425
770
  }
1426
771
  return null;
@@ -2935,10 +2280,10 @@ function resolveUtility(parsed, theme) {
2935
2280
  if (!parsed.value) {
2936
2281
  if (parsed.utility in PLUGIN_STANDALONE) return PLUGIN_STANDALONE[parsed.utility] ?? null;
2937
2282
  if (parsed.utility === "grd" || parsed.utility === "grid") {
2938
- return { display: "grid" };
2283
+ return getEffectiveIsWeb() ? { display: "grid" } : null;
2939
2284
  }
2940
2285
  if (parsed.utility === "inline-grid") {
2941
- return { display: "inline-grid" };
2286
+ return getEffectiveIsWeb() ? { display: "inline-grid" } : null;
2942
2287
  }
2943
2288
  if (parsed.utility in getStandalone()) return getStandalone()[parsed.utility] ?? null;
2944
2289
  }
@@ -2951,6 +2296,8 @@ var PLUGIN_RESOLVERS = {};
2951
2296
  function clearPluginUtilities() {
2952
2297
  for (const key of Object.keys(PLUGIN_STANDALONE)) delete PLUGIN_STANDALONE[key];
2953
2298
  for (const key of Object.keys(PLUGIN_RESOLVERS)) delete PLUGIN_RESOLVERS[key];
2299
+ _sortedPrefixes = null;
2300
+ _standaloneNames = null;
2954
2301
  }
2955
2302
  function getPluginStandaloneMap() {
2956
2303
  return PLUGIN_STANDALONE;
@@ -2958,6 +2305,129 @@ function getPluginStandaloneMap() {
2958
2305
  function isKnownUtility(utility) {
2959
2306
  return utility in getStandalone() || utility in RESOLVERS || utility in PLUGIN_STANDALONE || utility in PLUGIN_RESOLVERS;
2960
2307
  }
2308
+ var _sortedPrefixes = null;
2309
+ var _standaloneNames = null;
2310
+ function getBuiltinUtilityPrefixes() {
2311
+ if (!_sortedPrefixes) {
2312
+ const all = [.../* @__PURE__ */ new Set([...Object.keys(RESOLVERS), ...Object.keys(PLUGIN_RESOLVERS)])];
2313
+ _sortedPrefixes = all.sort((a, b) => b.length - a.length);
2314
+ }
2315
+ return _sortedPrefixes;
2316
+ }
2317
+ function getBuiltinStandaloneNames() {
2318
+ if (!_standaloneNames) {
2319
+ _standaloneNames = /* @__PURE__ */ new Set([...Object.keys(getStandalone()), ...Object.keys(PLUGIN_STANDALONE)]);
2320
+ }
2321
+ return _standaloneNames;
2322
+ }
2323
+
2324
+ // src/core/parser.ts
2325
+ function parseClass(className) {
2326
+ const trimmed = className.trim();
2327
+ if (!trimmed) return null;
2328
+ const modifiers = [];
2329
+ let remaining = trimmed;
2330
+ while (true) {
2331
+ const colonIdx = findOuterColon(remaining);
2332
+ if (colonIdx === -1) break;
2333
+ const candidate = remaining.slice(0, colonIdx);
2334
+ if (!isKnownModifier(candidate)) break;
2335
+ modifiers.push(candidate);
2336
+ remaining = remaining.slice(colonIdx + 1);
2337
+ }
2338
+ let important = false;
2339
+ if (remaining.startsWith("!") && remaining.length > 1) {
2340
+ important = true;
2341
+ remaining = remaining.slice(1);
2342
+ }
2343
+ let negative = false;
2344
+ if (remaining.startsWith("-") && remaining.length > 1 && remaining[1] !== "-") {
2345
+ negative = true;
2346
+ remaining = remaining.slice(1);
2347
+ }
2348
+ const bracketStart = remaining.lastIndexOf("-[");
2349
+ if (bracketStart > 0 && remaining.endsWith("]")) {
2350
+ const utility = remaining.slice(0, bracketStart);
2351
+ const value = remaining.slice(bracketStart + 2, -1).replace(/_/g, " ");
2352
+ return { original: trimmed, modifiers, negative, important, utility, value, isArbitrary: true };
2353
+ }
2354
+ if (getBuiltinStandaloneNames().has(remaining)) {
2355
+ return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
2356
+ }
2357
+ for (const prefix of getBuiltinUtilityPrefixes()) {
2358
+ if (remaining === prefix) {
2359
+ return { original: trimmed, modifiers, negative, important, utility: prefix, value: "", isArbitrary: false };
2360
+ }
2361
+ if (remaining.startsWith(prefix + "-")) {
2362
+ const value = remaining.slice(prefix.length + 1);
2363
+ return { original: trimmed, modifiers, negative, important, utility: prefix, value, isArbitrary: false };
2364
+ }
2365
+ }
2366
+ const firstDash = remaining.indexOf("-");
2367
+ if (firstDash > 0) {
2368
+ return {
2369
+ original: trimmed,
2370
+ modifiers,
2371
+ negative,
2372
+ important,
2373
+ utility: remaining.slice(0, firstDash),
2374
+ value: remaining.slice(firstDash + 1),
2375
+ isArbitrary: false
2376
+ };
2377
+ }
2378
+ return { original: trimmed, modifiers, negative, important, utility: remaining, value: "", isArbitrary: false };
2379
+ }
2380
+ function splitClassTokens(classString) {
2381
+ const tokens = [];
2382
+ let current = "";
2383
+ let depth = 0;
2384
+ for (let i = 0; i < classString.length; i++) {
2385
+ const ch = classString[i];
2386
+ if (ch === "[") {
2387
+ depth++;
2388
+ current += ch;
2389
+ continue;
2390
+ }
2391
+ if (ch === "]") {
2392
+ depth--;
2393
+ current += ch;
2394
+ continue;
2395
+ }
2396
+ if (/\s/.test(ch)) {
2397
+ if (depth === 0) {
2398
+ if (current) {
2399
+ tokens.push(current);
2400
+ current = "";
2401
+ }
2402
+ }
2403
+ } else {
2404
+ current += ch;
2405
+ }
2406
+ }
2407
+ if (current) tokens.push(current);
2408
+ return tokens;
2409
+ }
2410
+ function normalizeClassString(classString) {
2411
+ return splitClassTokens(classString).join(" ");
2412
+ }
2413
+ function parseClasses(classString) {
2414
+ const results = [];
2415
+ for (const token of splitClassTokens(classString)) {
2416
+ const parsed = parseClass(token);
2417
+ if (parsed) results.push(parsed);
2418
+ }
2419
+ return results;
2420
+ }
2421
+ function findOuterColon(s) {
2422
+ let depth = 0;
2423
+ for (let i = 0; i < s.length; i++) {
2424
+ const ch = s[i];
2425
+ if (ch === "[") depth++;
2426
+ else if (ch === "]") depth--;
2427
+ else if (ch === ":" && depth === 0) return i;
2428
+ }
2429
+ return -1;
2430
+ }
2961
2431
 
2962
2432
  // src/core/cache.ts
2963
2433
  var LRUCache = class {
@@ -2982,7 +2452,11 @@ var LRUCache = class {
2982
2452
  return this;
2983
2453
  }
2984
2454
  has(key) {
2985
- return this.cache.has(key);
2455
+ if (!this.cache.has(key)) return false;
2456
+ const value = this.cache.get(key);
2457
+ this.cache.delete(key);
2458
+ this.cache.set(key, value);
2459
+ return true;
2986
2460
  }
2987
2461
  delete(key) {
2988
2462
  return this.cache.delete(key);
@@ -3038,7 +2512,30 @@ function getActiveBreakpoints(width) {
3038
2512
  }
3039
2513
 
3040
2514
  // src/core/resolver.ts
3041
- var styleCache = new LRUCache(1e4);
2515
+ var _themeCache = /* @__PURE__ */ new WeakMap();
2516
+ function getThemeCache(theme) {
2517
+ let cache = _themeCache.get(theme);
2518
+ if (!cache) {
2519
+ cache = new LRUCache(1e4);
2520
+ _themeCache.set(theme, cache);
2521
+ }
2522
+ return cache;
2523
+ }
2524
+ var _sortCache = /* @__PURE__ */ new WeakMap();
2525
+ function getSortedEntries(resolved) {
2526
+ let sorted = _sortCache.get(resolved);
2527
+ if (!sorted) {
2528
+ const entries = Object.entries(resolved);
2529
+ entries.sort((a, b) => {
2530
+ const pa = a[0] === "base" ? -1 : a[0].split(":").length;
2531
+ const pb = b[0] === "base" ? -1 : b[0].split(":").length;
2532
+ return pa - pb;
2533
+ });
2534
+ sorted = entries;
2535
+ _sortCache.set(resolved, sorted);
2536
+ }
2537
+ return sorted;
2538
+ }
3042
2539
  var FONT_KEY = "__kbach_default_font__";
3043
2540
  function setDefaultFontFamily(font) {
3044
2541
  globalThis[FONT_KEY] = font;
@@ -3047,7 +2544,7 @@ function getDefaultFontFamily() {
3047
2544
  return globalThis[FONT_KEY];
3048
2545
  }
3049
2546
  var _styleEl = null;
3050
- var _injectedRules = /* @__PURE__ */ new Set();
2547
+ var _injectedRules = new LRUCache(5e4);
3051
2548
  function getStyleEl() {
3052
2549
  if (_styleEl) return _styleEl;
3053
2550
  _styleEl = document.createElement("style");
@@ -3057,7 +2554,7 @@ function getStyleEl() {
3057
2554
  }
3058
2555
  function injectRule(rule) {
3059
2556
  if (_injectedRules.has(rule)) return;
3060
- _injectedRules.add(rule);
2557
+ _injectedRules.set(rule, true);
3061
2558
  try {
3062
2559
  getStyleEl().sheet?.insertRule(rule, getStyleEl().sheet.cssRules.length);
3063
2560
  } catch {
@@ -3081,160 +2578,20 @@ function injectGlobalStyles(theme) {
3081
2578
  }
3082
2579
  getGlobalStyleEl().textContent = rules.join("\n");
3083
2580
  }
3084
- var MODIFIER_TO_PSEUDO = {
3085
- hover: ":hover",
3086
- focus: ":focus",
3087
- "focus-within": ":focus-within",
3088
- "focus-visible": ":focus-visible",
3089
- active: ":active",
3090
- pressed: ":active",
3091
- disabled: ":disabled",
3092
- checked: ":checked",
3093
- visited: ":visited",
3094
- placeholder: "::placeholder",
3095
- first: ":first-child",
3096
- last: ":last-child",
3097
- odd: ":nth-child(odd)",
3098
- even: ":nth-child(even)",
3099
- only: ":only-child",
3100
- "not-hover": ":not(:hover)",
3101
- "not-focus": ":not(:focus)",
3102
- "not-active": ":not(:active)",
3103
- "not-pressed": ":not(:active)",
3104
- "not-disabled": ":not(:disabled)",
3105
- "not-checked": ":not(:checked)",
3106
- "not-visited": ":not(:visited)",
3107
- // Pseudo-elements (CSS-injection only; never applied as inline styles)
3108
- before: "::before",
3109
- after: "::after",
3110
- selection: "::selection",
3111
- "first-letter": "::first-letter",
3112
- "first-line": "::first-line",
3113
- marker: "::marker"
3114
- };
3115
- var GROUP_PEER_PREFIX = {
3116
- "group-hover": ".group:hover",
3117
- "group-focus": ".group:focus",
3118
- "peer-hover": ".peer:hover ~",
3119
- "peer-focus": ".peer:focus ~"
3120
- };
3121
- var MODE_MODS = /* @__PURE__ */ new Set(["dark", "light", "not-dark", "not-light"]);
3122
- var RESPONSIVE_MODS = /* @__PURE__ */ new Set(["sm", "md", "lg", "xl", "2xl"]);
3123
- var PRINT_MODS = /* @__PURE__ */ new Set(["print"]);
3124
- var MEDIA_MODS = {
3125
- landscape: "(orientation: landscape)",
3126
- portrait: "(orientation: portrait)",
3127
- "motion-reduce": "(prefers-reduced-motion: reduce)",
3128
- "motion-safe": "(prefers-reduced-motion: no-preference)",
3129
- "contrast-more": "(prefers-contrast: more)",
3130
- "contrast-less": "(prefers-contrast: less)"
3131
- };
3132
- var DIR_MODS = {
3133
- rtl: '[dir="rtl"]',
3134
- ltr: '[dir="ltr"]'
3135
- };
3136
2581
  function buildDivideDecls(styles) {
3137
2582
  const parts = [];
3138
2583
  if ("__divideX" in styles) {
3139
2584
  const w = Number(styles.__divideX);
3140
- parts.push(`border-left-width: ${w}px`);
3141
- parts.push("border-right-width: 0px");
2585
+ parts.push(`border-left-width: ${w}px`, "border-right-width: 0px");
3142
2586
  }
3143
2587
  if ("__divideY" in styles) {
3144
2588
  const w = Number(styles.__divideY);
3145
- parts.push(`border-top-width: ${w}px`);
3146
- parts.push("border-bottom-width: 0px");
2589
+ parts.push(`border-top-width: ${w}px`, "border-bottom-width: 0px");
3147
2590
  }
3148
2591
  if ("__divideColor" in styles) parts.push(`border-color: ${String(styles.__divideColor)}`);
3149
2592
  if ("__divideStyle" in styles) parts.push(`border-style: ${String(styles.__divideStyle)}`);
3150
2593
  return parts.join("; ");
3151
2594
  }
3152
- function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens) {
3153
- const rules = [];
3154
- if ("__keyframe" in styles && typeof styles.__keyframe === "string") {
3155
- rules.push(styles.__keyframe);
3156
- }
3157
- const isDivide = "__divideX" in styles || "__divideY" in styles || "__divideColor" in styles || "__divideStyle" in styles;
3158
- const escaped = escapeCSSSelector(cls);
3159
- const childSuffix = isDivide ? " > * + *" : "";
3160
- if (bucketKey === "base") {
3161
- const baseCssDecls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, important);
3162
- if (!baseCssDecls) return rules;
3163
- rules.push(`.${escaped}${childSuffix} { ${baseCssDecls} }`);
3164
- return rules;
3165
- }
3166
- const mods = bucketKey.split(":");
3167
- const responsiveMods = mods.filter((m) => RESPONSIVE_MODS.has(m));
3168
- const nonResponsiveMods = mods.filter((m) => !RESPONSIVE_MODS.has(m));
3169
- const hasDark = nonResponsiveMods.includes("dark") || nonResponsiveMods.includes("not-light");
3170
- const hasLight = nonResponsiveMods.includes("light") || nonResponsiveMods.includes("not-dark");
3171
- const hasPrint = nonResponsiveMods.includes("print");
3172
- const mediaMods = nonResponsiveMods.filter((m) => m in MEDIA_MODS);
3173
- const dirMods = nonResponsiveMods.filter((m) => m in DIR_MODS);
3174
- const ancestorMods = nonResponsiveMods.filter((m) => m in GROUP_PEER_PREFIX);
3175
- const pseudoMods = nonResponsiveMods.filter(
3176
- (m) => !MODE_MODS.has(m) && !(m in GROUP_PEER_PREFIX) && !PRINT_MODS.has(m) && !(m in MEDIA_MODS) && !(m in DIR_MODS)
3177
- );
3178
- const pseudoSuffix = pseudoMods.map((p) => MODIFIER_TO_PSEUDO[p] ?? `:${p}`).join("");
3179
- const elementSelector = `.${escaped}${pseudoSuffix}${childSuffix}`;
3180
- const ancestorPrefix = ancestorMods.length ? ancestorMods.map((m) => GROUP_PEER_PREFIX[m]).join(" ") + " " : "";
3181
- const dirPrefix = dirMods.length ? dirMods.map((m) => DIR_MODS[m]).join(" ") + " " : "";
3182
- const selector = `${dirPrefix}${ancestorPrefix}${elementSelector}`;
3183
- const CSS_ONLY_PSEUDOS = /* @__PURE__ */ new Set([
3184
- "first",
3185
- "last",
3186
- "odd",
3187
- "even",
3188
- "only",
3189
- "focus-within",
3190
- "focus-visible"
3191
- ]);
3192
- const needsImportant = important || hasPrint || mediaMods.length > 0 || dirMods.length > 0 || ancestorMods.length > 0 || pseudoMods.some((m) => CSS_ONLY_PSEUDOS.has(m));
3193
- const cssDecls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, needsImportant);
3194
- if (!cssDecls) return rules;
3195
- let rule;
3196
- if (hasDark) {
3197
- if (darkMode === "media") {
3198
- rule = `@media (prefers-color-scheme: dark) { ${selector} { ${cssDecls} } }`;
3199
- } else if (darkMode === "class") {
3200
- rule = `.dark ${selector} { ${cssDecls} }`;
3201
- } else {
3202
- rule = `[data-theme="dark"] ${selector} { ${cssDecls} }`;
3203
- }
3204
- } else if (hasLight) {
3205
- if (darkMode === "media") {
3206
- rule = `@media (prefers-color-scheme: light) { ${selector} { ${cssDecls} } }`;
3207
- } else if (darkMode === "class") {
3208
- rule = `:not(.dark) ${selector} { ${cssDecls} }`;
3209
- } else {
3210
- rule = `[data-theme="light"] ${selector} { ${cssDecls} }`;
3211
- }
3212
- } else {
3213
- rule = `${selector} { ${cssDecls} }`;
3214
- }
3215
- if (hasPrint) rule = `@media print { ${rule} }`;
3216
- for (const m of mediaMods) rule = `@media ${MEDIA_MODS[m]} { ${rule} }`;
3217
- if (responsiveMods.length > 0) {
3218
- const minWidth = Math.max(...responsiveMods.map((m) => screens[m] ?? 0));
3219
- if (minWidth > 0) rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
3220
- }
3221
- rules.push(rule);
3222
- return rules;
3223
- }
3224
- function injectClassRule(cls, bucketKey, styles, darkMode, important = false) {
3225
- const cssRules = buildClassCSSRules(cls, bucketKey, styles, darkMode, important, getGlobalScreens());
3226
- for (const r of cssRules) injectRule(r);
3227
- }
3228
- function generateClassCSS(classString, theme, darkMode = "attribute", screens = {}) {
3229
- const rules = [];
3230
- for (const parsed of parseClasses(classString)) {
3231
- const styles = resolveUtility(parsed, theme);
3232
- if (!styles) continue;
3233
- const bucketKey = parsed.modifiers.length === 0 ? "base" : parsed.modifiers.join(":");
3234
- rules.push(...buildClassCSSRules(parsed.original, bucketKey, styles, darkMode, parsed.important, screens));
3235
- }
3236
- return rules.join("\n");
3237
- }
3238
2595
  var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
3239
2596
  "shadowColor",
3240
2597
  "shadowOffset",
@@ -3244,13 +2601,10 @@ var RN_ONLY_PROPS = /* @__PURE__ */ new Set([
3244
2601
  "includeFontPadding",
3245
2602
  "textAlignVertical",
3246
2603
  "writingDirection",
3247
- // Text shadow native props — web uses the textShadow CSS shorthand instead
3248
2604
  "textShadowColor",
3249
2605
  "textShadowOffset",
3250
2606
  "textShadowRadius",
3251
- // tintColor is native-only (Image/icon tinting)
3252
2607
  "tintColor",
3253
- // Internal markers — handled specially, never serialized as CSS props
3254
2608
  "__divideX",
3255
2609
  "__divideY",
3256
2610
  "__divideColor",
@@ -3292,8 +2646,7 @@ function styleValueToCSS(styles, forceImportant = false) {
3292
2646
  const imp = forceImportant || prop === "display" && (cssVal === "grid" || cssVal === "inline-grid") || prop === "position" && (cssVal === "sticky" || cssVal === "fixed" || cssVal === "static") ? " !important" : "";
3293
2647
  if (prop in RN_SHORTHAND_EXPAND) {
3294
2648
  const [p1, p2] = RN_SHORTHAND_EXPAND[prop];
3295
- parts.push(`${p1}: ${cssVal}${imp}`);
3296
- parts.push(`${p2}: ${cssVal}${imp}`);
2649
+ parts.push(`${p1}: ${cssVal}${imp}`, `${p2}: ${cssVal}${imp}`);
3297
2650
  continue;
3298
2651
  }
3299
2652
  parts.push(`${camelToKebab(prop)}: ${cssVal}${imp}`);
@@ -3303,14 +2656,97 @@ function styleValueToCSS(styles, forceImportant = false) {
3303
2656
  function camelToKebab(str) {
3304
2657
  return str.replace(/([A-Z])/g, "-$1").toLowerCase();
3305
2658
  }
2659
+ function buildClassCSSRules(cls, bucketKey, styles, darkMode, important, screens) {
2660
+ const rules = [];
2661
+ if ("__keyframe" in styles && typeof styles.__keyframe === "string") {
2662
+ rules.push(styles.__keyframe);
2663
+ }
2664
+ const isDivide = "__divideX" in styles || "__divideY" in styles || "__divideColor" in styles || "__divideStyle" in styles;
2665
+ const escaped = escapeCSSSelector(cls);
2666
+ const childSuffix = isDivide ? " > * + *" : "";
2667
+ if (bucketKey === "base") {
2668
+ const decls2 = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, important);
2669
+ if (!decls2) return rules;
2670
+ rules.push(`.${escaped}${childSuffix} { ${decls2} }`);
2671
+ return rules;
2672
+ }
2673
+ const mods = bucketKey.split(":");
2674
+ let darkScheme;
2675
+ let needsImportant = important;
2676
+ const pseudoParts = [];
2677
+ const ancestorParts = [];
2678
+ const dirParts = [];
2679
+ const mediaWrappers = [];
2680
+ let minWidth = 0;
2681
+ for (const mod of mods) {
2682
+ const def = getModifier(mod);
2683
+ if (!def) continue;
2684
+ if (def.darkScheme) darkScheme = def.darkScheme;
2685
+ if (def.pseudo) pseudoParts.push(def.pseudo);
2686
+ if (def.ancestorSelector) {
2687
+ ancestorParts.push(def.ancestorSelector);
2688
+ needsImportant = true;
2689
+ }
2690
+ if (def.dirSelector) {
2691
+ dirParts.push(def.dirSelector);
2692
+ needsImportant = true;
2693
+ }
2694
+ if (def.mediaQuery) {
2695
+ mediaWrappers.push(`@media ${def.mediaQuery}`);
2696
+ needsImportant = true;
2697
+ }
2698
+ if (def.isResponsive) {
2699
+ const w = screens[mod] ?? 0;
2700
+ if (w > minWidth) minWidth = w;
2701
+ }
2702
+ if (def.forcesImportant) needsImportant = true;
2703
+ }
2704
+ const pseudoSuffix = pseudoParts.join("");
2705
+ const elementSelector = `.${escaped}${pseudoSuffix}${childSuffix}`;
2706
+ const ancestorPrefix = ancestorParts.join("");
2707
+ const dirPrefix = dirParts.join("");
2708
+ const selector = `${dirPrefix}${ancestorPrefix}${elementSelector}`;
2709
+ const decls = isDivide ? buildDivideDecls(styles) : styleValueToCSS(styles, needsImportant);
2710
+ if (!decls) return rules;
2711
+ let rule;
2712
+ if (darkScheme === "dark") {
2713
+ if (darkMode === "media") rule = `@media (prefers-color-scheme: dark) { ${selector} { ${decls} } }`;
2714
+ else if (darkMode === "class") rule = `.dark ${selector} { ${decls} }`;
2715
+ else rule = `[data-theme="dark"] ${selector} { ${decls} }`;
2716
+ } else if (darkScheme === "light") {
2717
+ if (darkMode === "media") rule = `@media (prefers-color-scheme: light) { ${selector} { ${decls} } }`;
2718
+ else if (darkMode === "class") rule = `:not(.dark) ${selector} { ${decls} }`;
2719
+ else rule = `[data-theme="light"] ${selector} { ${decls} }`;
2720
+ } else {
2721
+ rule = `${selector} { ${decls} }`;
2722
+ }
2723
+ for (const mw of mediaWrappers) rule = `${mw} { ${rule} }`;
2724
+ if (minWidth > 0) rule = `@media (min-width: ${minWidth}px) { ${rule} }`;
2725
+ rules.push(rule);
2726
+ return rules;
2727
+ }
2728
+ function injectClassRule(cls, bucketKey, styles, darkMode, important) {
2729
+ const cssRules = buildClassCSSRules(cls, bucketKey, styles, darkMode, important, getGlobalScreens());
2730
+ for (const r of cssRules) injectRule(r);
2731
+ }
2732
+ function generateClassCSS(classString, theme, darkMode = "attribute", screens = {}) {
2733
+ const rules = [];
2734
+ for (const parsed of parseClasses(classString)) {
2735
+ const styles = resolveUtility(parsed, theme);
2736
+ if (!styles) continue;
2737
+ const bucketKey = parsed.modifiers.length === 0 ? "base" : parsed.modifiers.join(":");
2738
+ rules.push(...buildClassCSSRules(parsed.original, bucketKey, styles, darkMode, parsed.important, screens));
2739
+ }
2740
+ return rules.join("\n");
2741
+ }
3306
2742
  function resolve(classString, theme, darkMode = "attribute") {
2743
+ const cache = getThemeCache(theme);
3307
2744
  const cacheKey = `${classString}::${darkMode}`;
3308
- const cached = styleCache.get(cacheKey);
2745
+ const cached = cache.get(cacheKey);
3309
2746
  if (cached) return cached;
3310
2747
  const result = {};
3311
- const parsedClasses = parseClasses(classString);
3312
- const injectQueue = [];
3313
- for (const parsed of parsedClasses) {
2748
+ const onWeb = typeof document !== "undefined";
2749
+ for (const parsed of parseClasses(classString)) {
3314
2750
  const styles = resolveUtility(parsed, theme);
3315
2751
  if (!styles) {
3316
2752
  if (process.env.NODE_ENV !== "production" && !parsed.isArbitrary && !isKnownUtility(parsed.utility)) {
@@ -3321,132 +2757,60 @@ function resolve(classString, theme, darkMode = "attribute") {
3321
2757
  const bucketKey = parsed.modifiers.length === 0 ? "base" : parsed.modifiers.join(":");
3322
2758
  if (!result[bucketKey]) result[bucketKey] = {};
3323
2759
  Object.assign(result[bucketKey], styles);
3324
- if (typeof document !== "undefined") {
3325
- injectQueue.push({ cls: parsed.original, bucketKey, styles, important: parsed.important });
3326
- }
3327
- }
3328
- styleCache.set(cacheKey, result);
3329
- if (typeof document !== "undefined") {
3330
- for (const { cls, bucketKey, styles, important } of injectQueue) {
3331
- injectClassRule(cls, bucketKey, styles, darkMode, important);
2760
+ if (onWeb) {
2761
+ injectClassRule(parsed.original, bucketKey, styles, darkMode, parsed.important);
3332
2762
  }
3333
2763
  }
2764
+ cache.set(cacheKey, result);
3334
2765
  return result;
3335
2766
  }
3336
2767
  function flatten(resolved, isDark, state = {}, breakpoints = /* @__PURE__ */ new Set()) {
3337
2768
  const result = {};
3338
- const entries = Object.entries(resolved);
3339
- entries.sort((a, b) => {
3340
- const pa = a[0] === "base" ? -1 : a[0].split(":").length;
3341
- const pb = b[0] === "base" ? -1 : b[0].split(":").length;
3342
- return pa - pb;
3343
- });
3344
- for (const [key, styles] of entries) {
2769
+ for (const [key, styles] of getSortedEntries(resolved)) {
3345
2770
  if (!styles) continue;
3346
2771
  if (key === "base") {
3347
2772
  Object.assign(result, styles);
3348
2773
  continue;
3349
2774
  }
3350
2775
  const mods = key.split(":");
3351
- if (matchesMods(mods, isDark, state, breakpoints)) {
2776
+ if (mods.every((mod) => matchModifier(mod, isDark, state, breakpoints))) {
3352
2777
  Object.assign(result, styles);
3353
2778
  }
3354
2779
  }
3355
- const _df = getDefaultFontFamily();
3356
- if (_df && !("fontFamily" in result)) {
3357
- result.fontFamily = _df;
2780
+ const defaultFont = getDefaultFontFamily();
2781
+ if (defaultFont && !("fontFamily" in result)) {
2782
+ result.fontFamily = defaultFont;
3358
2783
  }
3359
- if (isWeb) {
2784
+ if (!isNative) {
3360
2785
  const r = result;
3361
- const v0 = r.paddingHorizontal;
3362
- if (v0 !== void 0) {
3363
- r.paddingLeft = v0;
3364
- r.paddingRight = v0;
2786
+ const ph = r.paddingHorizontal;
2787
+ if (ph !== void 0) {
2788
+ r.paddingLeft = ph;
2789
+ r.paddingRight = ph;
3365
2790
  delete r.paddingHorizontal;
3366
2791
  }
3367
- const v1 = r.paddingVertical;
3368
- if (v1 !== void 0) {
3369
- r.paddingTop = v1;
3370
- r.paddingBottom = v1;
2792
+ const pv = r.paddingVertical;
2793
+ if (pv !== void 0) {
2794
+ r.paddingTop = pv;
2795
+ r.paddingBottom = pv;
3371
2796
  delete r.paddingVertical;
3372
2797
  }
3373
- const v2 = r.marginHorizontal;
3374
- if (v2 !== void 0) {
3375
- r.marginLeft = v2;
3376
- r.marginRight = v2;
2798
+ const mh = r.marginHorizontal;
2799
+ if (mh !== void 0) {
2800
+ r.marginLeft = mh;
2801
+ r.marginRight = mh;
3377
2802
  delete r.marginHorizontal;
3378
2803
  }
3379
- const v3 = r.marginVertical;
3380
- if (v3 !== void 0) {
3381
- r.marginTop = v3;
3382
- r.marginBottom = v3;
2804
+ const mv = r.marginVertical;
2805
+ if (mv !== void 0) {
2806
+ r.marginTop = mv;
2807
+ r.marginBottom = mv;
3383
2808
  delete r.marginVertical;
3384
2809
  }
3385
2810
  }
3386
2811
  return result;
3387
2812
  }
3388
- function matchesMods(mods, isDark, state, breakpoints) {
3389
- return mods.every((mod) => {
3390
- switch (mod) {
3391
- case "dark":
3392
- return isDark;
3393
- case "light":
3394
- case "not-dark":
3395
- return !isDark;
3396
- case "not-light":
3397
- return isDark;
3398
- case "hover":
3399
- return !!state.hover;
3400
- case "not-hover":
3401
- return !state.hover;
3402
- case "focus":
3403
- return !!state.focus;
3404
- case "not-focus":
3405
- return !state.focus;
3406
- case "pressed":
3407
- case "active":
3408
- return !!state.pressed || !!state.active;
3409
- case "not-pressed":
3410
- case "not-active":
3411
- return !state.pressed && !state.active;
3412
- case "disabled":
3413
- return !!state.disabled;
3414
- case "not-disabled":
3415
- return !state.disabled;
3416
- case "checked":
3417
- return !!state.checked;
3418
- case "not-checked":
3419
- return !state.checked;
3420
- case "visited":
3421
- return !!state.visited;
3422
- case "not-visited":
3423
- return !state.visited;
3424
- case "placeholder":
3425
- return !!state.placeholder;
3426
- case "sm":
3427
- case "md":
3428
- case "lg":
3429
- case "xl":
3430
- case "2xl":
3431
- return breakpoints.has(mod);
3432
- // CSS-only modifiers — never applied as inline styles
3433
- case "print":
3434
- case "landscape":
3435
- case "portrait":
3436
- case "motion-reduce":
3437
- case "motion-safe":
3438
- case "contrast-more":
3439
- case "contrast-less":
3440
- case "rtl":
3441
- case "ltr":
3442
- return false;
3443
- default:
3444
- return false;
3445
- }
3446
- });
3447
- }
3448
2813
  function clearCache() {
3449
- styleCache.clear();
3450
2814
  _injectedRules.clear();
3451
2815
  if (_styleEl) {
3452
2816
  _styleEl.remove();
@@ -3493,14 +2857,24 @@ function resolveOneRef(ref, colors) {
3493
2857
  return entry[m[2]] ?? null;
3494
2858
  }
3495
2859
  function resolveColorRefs(colors) {
2860
+ const MAX_DEPTH = 5;
2861
+ function resolveChain(raw) {
2862
+ let current = raw;
2863
+ for (let i = 0; i < MAX_DEPTH; i++) {
2864
+ const next = resolveOneRef(current, colors);
2865
+ if (!next || next === current) break;
2866
+ current = next;
2867
+ }
2868
+ return current;
2869
+ }
3496
2870
  const out = {};
3497
2871
  for (const [key, val] of Object.entries(colors)) {
3498
2872
  if (typeof val === "string") {
3499
- out[key] = resolveOneRef(val, colors) ?? val;
2873
+ out[key] = resolveChain(val);
3500
2874
  } else {
3501
2875
  const shades = {};
3502
2876
  for (const [shade, hex] of Object.entries(val)) {
3503
- shades[shade] = resolveOneRef(hex, colors) ?? hex;
2877
+ shades[shade] = resolveChain(hex);
3504
2878
  }
3505
2879
  out[key] = shades;
3506
2880
  }
@@ -3548,15 +2922,26 @@ function buildConfig(userConfig) {
3548
2922
  injectGlobalStyles(resolved.theme);
3549
2923
  return resolved;
3550
2924
  }
2925
+ function _selectorToModifierDef(selector) {
2926
+ const s = selector.trim();
2927
+ if (s.startsWith("@media ")) {
2928
+ return { mediaQuery: s.slice(7), jsBehavior: "css-only", forcesImportant: true };
2929
+ }
2930
+ if (s.startsWith("::") || s.startsWith(":")) {
2931
+ return { pseudo: s, jsBehavior: "css-only", forcesImportant: true };
2932
+ }
2933
+ return { ancestorSelector: s.endsWith(" ") ? s : `${s} `, jsBehavior: "css-only", forcesImportant: true };
2934
+ }
3551
2935
  function makePluginAPI(theme) {
3552
2936
  const standalone = getPluginStandaloneMap();
3553
2937
  return {
3554
2938
  addUtility(name, styles) {
3555
2939
  standalone[name] = styles;
3556
2940
  },
3557
- addVariant(name, selector) {
3558
- customVariants[name] = selector;
3559
- registerModifier(name);
2941
+ addVariant(name, selectorOrDef) {
2942
+ const def = typeof selectorOrDef === "string" ? _selectorToModifierDef(selectorOrDef) : selectorOrDef;
2943
+ customVariants[name] = typeof selectorOrDef === "string" ? selectorOrDef : name;
2944
+ registerModifier(name, def);
3560
2945
  },
3561
2946
  theme(path, defaultValue) {
3562
2947
  const parts = path.replace(/\[([^\]]+)\]/g, ".$1").split(".");
@@ -3616,7 +3001,11 @@ export {
3616
3001
  defaultColors,
3617
3002
  defaultTheme,
3618
3003
  isWeb,
3004
+ isNative,
3619
3005
  setCSSGenMode,
3006
+ getInteractiveModifiers,
3007
+ getModeModifiers,
3008
+ getResponsiveModifiers,
3620
3009
  parseClass,
3621
3010
  splitClassTokens,
3622
3011
  normalizeClassString,