@nori-ui/core 1.4.0 → 1.6.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.
Files changed (176) hide show
  1. package/dist/Table.shared-BymRgTnY.d.cts +54 -0
  2. package/dist/Table.shared-BymRgTnY.d.ts +54 -0
  3. package/dist/{chunk-HZKXPN6B.js → chunk-2HMQDJ22.js} +4 -4
  4. package/dist/{chunk-HZKXPN6B.js.map → chunk-2HMQDJ22.js.map} +1 -1
  5. package/dist/{chunk-KCLWPSV5.js → chunk-2RL6WCFC.js} +4 -4
  6. package/dist/{chunk-KCLWPSV5.js.map → chunk-2RL6WCFC.js.map} +1 -1
  7. package/dist/{chunk-FDBQOQMW.js → chunk-3BDDPFCI.js} +3 -3
  8. package/dist/{chunk-FDBQOQMW.js.map → chunk-3BDDPFCI.js.map} +1 -1
  9. package/dist/{chunk-WOF67PKT.js → chunk-3CEJ5TB4.js} +3 -3
  10. package/dist/{chunk-WOF67PKT.js.map → chunk-3CEJ5TB4.js.map} +1 -1
  11. package/dist/{chunk-BNDUQNG7.js → chunk-3OIWAS2P.js} +3 -3
  12. package/dist/{chunk-BNDUQNG7.js.map → chunk-3OIWAS2P.js.map} +1 -1
  13. package/dist/{chunk-6JVUVBZH.js → chunk-4PUPKWEP.js} +5 -5
  14. package/dist/{chunk-6JVUVBZH.js.map → chunk-4PUPKWEP.js.map} +1 -1
  15. package/dist/{chunk-6PO2IWB3.js → chunk-4UFAZLSZ.js} +5 -3
  16. package/dist/chunk-4UFAZLSZ.js.map +1 -0
  17. package/dist/{chunk-V2AWSDDZ.js → chunk-5PSC5HT4.js} +8 -125
  18. package/dist/chunk-5PSC5HT4.js.map +1 -0
  19. package/dist/{chunk-LWQZ257T.js → chunk-5XEGZFG5.js} +3 -3
  20. package/dist/{chunk-LWQZ257T.js.map → chunk-5XEGZFG5.js.map} +1 -1
  21. package/dist/{chunk-WAKKQROH.js → chunk-6AD6KCVB.js} +3 -3
  22. package/dist/{chunk-WAKKQROH.js.map → chunk-6AD6KCVB.js.map} +1 -1
  23. package/dist/chunk-73CUV7MW.js +125 -0
  24. package/dist/chunk-73CUV7MW.js.map +1 -0
  25. package/dist/{chunk-GRDVE3IR.js → chunk-BZLT6R62.js} +3 -3
  26. package/dist/{chunk-GRDVE3IR.js.map → chunk-BZLT6R62.js.map} +1 -1
  27. package/dist/{chunk-Y4ZRSW35.js → chunk-CCUXO2HN.js} +3 -3
  28. package/dist/{chunk-Y4ZRSW35.js.map → chunk-CCUXO2HN.js.map} +1 -1
  29. package/dist/{chunk-2UXKXUX2.js → chunk-CPIKN4BX.js} +3 -3
  30. package/dist/{chunk-2UXKXUX2.js.map → chunk-CPIKN4BX.js.map} +1 -1
  31. package/dist/{chunk-46OT4PA6.js → chunk-DDGMLLS3.js} +3 -3
  32. package/dist/{chunk-46OT4PA6.js.map → chunk-DDGMLLS3.js.map} +1 -1
  33. package/dist/{chunk-XP55RZ3D.js → chunk-FEPTH5RV.js} +3 -3
  34. package/dist/{chunk-XP55RZ3D.js.map → chunk-FEPTH5RV.js.map} +1 -1
  35. package/dist/{chunk-MJ4AGXS7.js → chunk-GJMHNEQ3.js} +3 -3
  36. package/dist/{chunk-MJ4AGXS7.js.map → chunk-GJMHNEQ3.js.map} +1 -1
  37. package/dist/{chunk-VCJF75T2.js → chunk-JQQ3FBN7.js} +3 -3
  38. package/dist/{chunk-VCJF75T2.js.map → chunk-JQQ3FBN7.js.map} +1 -1
  39. package/dist/chunk-JXLEMBDB.js +11 -0
  40. package/dist/chunk-JXLEMBDB.js.map +1 -0
  41. package/dist/{chunk-W3HMOOON.js → chunk-JZ774T7U.js} +3 -3
  42. package/dist/{chunk-W3HMOOON.js.map → chunk-JZ774T7U.js.map} +1 -1
  43. package/dist/{chunk-SINLREQV.js → chunk-MKSDYRWQ.js} +3 -3
  44. package/dist/{chunk-SINLREQV.js.map → chunk-MKSDYRWQ.js.map} +1 -1
  45. package/dist/{chunk-AFQIK6JI.js → chunk-MRJWPRCX.js} +3 -3
  46. package/dist/{chunk-AFQIK6JI.js.map → chunk-MRJWPRCX.js.map} +1 -1
  47. package/dist/{chunk-EFK7726V.js → chunk-NF7XG2FG.js} +3 -3
  48. package/dist/{chunk-EFK7726V.js.map → chunk-NF7XG2FG.js.map} +1 -1
  49. package/dist/{chunk-WTNDPO2V.js → chunk-NNFJKRXZ.js} +3 -3
  50. package/dist/{chunk-WTNDPO2V.js.map → chunk-NNFJKRXZ.js.map} +1 -1
  51. package/dist/{chunk-CGQIVFCN.js → chunk-NRYWNOG5.js} +3 -3
  52. package/dist/{chunk-CGQIVFCN.js.map → chunk-NRYWNOG5.js.map} +1 -1
  53. package/dist/{chunk-HTF6FDB6.js → chunk-OMU4R4Y5.js} +3 -3
  54. package/dist/{chunk-HTF6FDB6.js.map → chunk-OMU4R4Y5.js.map} +1 -1
  55. package/dist/{chunk-C6TRLHMW.js → chunk-PABG3IJ6.js} +3 -3
  56. package/dist/{chunk-C6TRLHMW.js.map → chunk-PABG3IJ6.js.map} +1 -1
  57. package/dist/{chunk-RM5TSXVE.js → chunk-PNP7L4TA.js} +3 -3
  58. package/dist/{chunk-RM5TSXVE.js.map → chunk-PNP7L4TA.js.map} +1 -1
  59. package/dist/{chunk-L5X4SYJ4.js → chunk-PZS4A4VQ.js} +3 -3
  60. package/dist/{chunk-L5X4SYJ4.js.map → chunk-PZS4A4VQ.js.map} +1 -1
  61. package/dist/{chunk-4I37QSEM.js → chunk-QJVS2VXS.js} +5 -5
  62. package/dist/{chunk-4I37QSEM.js.map → chunk-QJVS2VXS.js.map} +1 -1
  63. package/dist/{chunk-H7MFAFV4.js → chunk-RUWD35UI.js} +4 -4
  64. package/dist/{chunk-H7MFAFV4.js.map → chunk-RUWD35UI.js.map} +1 -1
  65. package/dist/{chunk-5BM6H2CD.js → chunk-SFNDR6DI.js} +3 -3
  66. package/dist/{chunk-5BM6H2CD.js.map → chunk-SFNDR6DI.js.map} +1 -1
  67. package/dist/{chunk-UF5OENHV.js → chunk-TLS54G6Y.js} +3 -3
  68. package/dist/{chunk-UF5OENHV.js.map → chunk-TLS54G6Y.js.map} +1 -1
  69. package/dist/{chunk-UUXWRDWW.js → chunk-UJWCEGQY.js} +3 -3
  70. package/dist/{chunk-UUXWRDWW.js.map → chunk-UJWCEGQY.js.map} +1 -1
  71. package/dist/{chunk-UJ5KFRDE.js → chunk-UZD77M3J.js} +3 -3
  72. package/dist/{chunk-UJ5KFRDE.js.map → chunk-UZD77M3J.js.map} +1 -1
  73. package/dist/chunk-VP7DRJUZ.js +3 -0
  74. package/dist/chunk-VP7DRJUZ.js.map +1 -0
  75. package/dist/{chunk-UPVNZPFV.js → chunk-VYRJ7OE5.js} +3 -3
  76. package/dist/{chunk-UPVNZPFV.js.map → chunk-VYRJ7OE5.js.map} +1 -1
  77. package/dist/{chunk-IGLMPAWE.js → chunk-WGT345SV.js} +3 -3
  78. package/dist/{chunk-IGLMPAWE.js.map → chunk-WGT345SV.js.map} +1 -1
  79. package/dist/{chunk-XXBN6CIK.js → chunk-WP2Z2ATO.js} +5 -5
  80. package/dist/{chunk-XXBN6CIK.js.map → chunk-WP2Z2ATO.js.map} +1 -1
  81. package/dist/chunk-WYPGQVDV.js +145 -0
  82. package/dist/chunk-WYPGQVDV.js.map +1 -0
  83. package/dist/{chunk-GELLSU64.js → chunk-XALU6LOT.js} +3 -3
  84. package/dist/{chunk-GELLSU64.js.map → chunk-XALU6LOT.js.map} +1 -1
  85. package/dist/{chunk-VMAGFYHG.js → chunk-Y5TJ7CAX.js} +3 -3
  86. package/dist/{chunk-VMAGFYHG.js.map → chunk-Y5TJ7CAX.js.map} +1 -1
  87. package/dist/chunk-YZ27OS2R.js +202 -0
  88. package/dist/chunk-YZ27OS2R.js.map +1 -0
  89. package/dist/client.cjs +453 -119
  90. package/dist/client.cjs.map +1 -1
  91. package/dist/client.d.cts +4 -0
  92. package/dist/client.d.ts +4 -0
  93. package/dist/client.js +50 -45
  94. package/dist/client.js.map +1 -1
  95. package/dist/components/Accordion/index.js +2 -2
  96. package/dist/components/Alert/index.js +2 -2
  97. package/dist/components/AlertDialog/index.js +2 -2
  98. package/dist/components/Avatar/index.js +2 -2
  99. package/dist/components/Badge/index.js +2 -2
  100. package/dist/components/Box/index.js +4 -4
  101. package/dist/components/Breadcrumb/index.cjs +3 -1
  102. package/dist/components/Breadcrumb/index.cjs.map +1 -1
  103. package/dist/components/Breadcrumb/index.js +5 -5
  104. package/dist/components/Button/index.js +2 -2
  105. package/dist/components/Calendar/index.cjs +3 -1
  106. package/dist/components/Calendar/index.cjs.map +1 -1
  107. package/dist/components/Calendar/index.js +5 -5
  108. package/dist/components/Card/index.js +2 -2
  109. package/dist/components/Checkbox/index.js +2 -2
  110. package/dist/components/Combobox/index.cjs +1374 -0
  111. package/dist/components/Combobox/index.cjs.map +1 -0
  112. package/dist/components/Combobox/index.d.cts +17 -0
  113. package/dist/components/Combobox/index.d.ts +17 -0
  114. package/dist/components/Combobox/index.js +9 -0
  115. package/dist/components/Combobox/index.js.map +1 -0
  116. package/dist/components/ContextMenu/index.js +4 -4
  117. package/dist/components/DataTable/index.cjs +770 -0
  118. package/dist/components/DataTable/index.cjs.map +1 -0
  119. package/dist/components/DataTable/index.d.cts +53 -0
  120. package/dist/components/DataTable/index.d.ts +53 -0
  121. package/dist/components/DataTable/index.js +8 -0
  122. package/dist/components/DataTable/index.js.map +1 -0
  123. package/dist/components/DatePicker/index.cjs +3 -1
  124. package/dist/components/DatePicker/index.cjs.map +1 -1
  125. package/dist/components/DatePicker/index.js +7 -7
  126. package/dist/components/Dialog/index.js +2 -2
  127. package/dist/components/DropdownMenu/index.js +3 -3
  128. package/dist/components/Field/index.cjs +3 -1
  129. package/dist/components/Field/index.cjs.map +1 -1
  130. package/dist/components/Field/index.d.cts +2 -2
  131. package/dist/components/Field/index.d.ts +2 -2
  132. package/dist/components/Field/index.js +3 -3
  133. package/dist/components/FloatButton/index.cjs +3 -1
  134. package/dist/components/FloatButton/index.cjs.map +1 -1
  135. package/dist/components/FloatButton/index.js +5 -5
  136. package/dist/components/HStack/index.js +4 -4
  137. package/dist/components/InputGroup/index.js +2 -2
  138. package/dist/components/Label/index.cjs +3 -1
  139. package/dist/components/Label/index.cjs.map +1 -1
  140. package/dist/components/Label/index.js +3 -3
  141. package/dist/components/Pagination/index.cjs +3 -1
  142. package/dist/components/Pagination/index.cjs.map +1 -1
  143. package/dist/components/Pagination/index.js +6 -5
  144. package/dist/components/Popover/index.js +2 -2
  145. package/dist/components/Progress/index.js +2 -2
  146. package/dist/components/Radio/index.js +2 -2
  147. package/dist/components/SegmentedControl/index.js +2 -2
  148. package/dist/components/Select/index.js +2 -2
  149. package/dist/components/Sheet/index.js +2 -2
  150. package/dist/components/Switch/index.js +2 -2
  151. package/dist/components/Table/index.cjs +461 -0
  152. package/dist/components/Table/index.cjs.map +1 -0
  153. package/dist/components/Table/index.d.cts +16 -0
  154. package/dist/components/Table/index.d.ts +16 -0
  155. package/dist/components/Table/index.js +7 -0
  156. package/dist/components/Table/index.js.map +1 -0
  157. package/dist/components/Tabs/index.js +2 -2
  158. package/dist/components/Text/index.js +2 -2
  159. package/dist/components/TextArea/index.js +3 -3
  160. package/dist/components/TextInput/index.js +2 -2
  161. package/dist/components/Toggle/index.js +2 -2
  162. package/dist/components/Tooltip/index.js +2 -2
  163. package/dist/components/VStack/index.js +4 -4
  164. package/dist/i18n/index.cjs +3 -1
  165. package/dist/i18n/index.cjs.map +1 -1
  166. package/dist/i18n/index.js +1 -1
  167. package/dist/index.cjs +453 -119
  168. package/dist/index.cjs.map +1 -1
  169. package/dist/index.d.cts +4 -0
  170. package/dist/index.d.ts +4 -0
  171. package/dist/index.js +47 -42
  172. package/dist/slot/index.d.cts +2 -2
  173. package/dist/slot/index.d.ts +2 -2
  174. package/package.json +1 -1
  175. package/dist/chunk-6PO2IWB3.js.map +0 -1
  176. package/dist/chunk-V2AWSDDZ.js.map +0 -1
@@ -0,0 +1,1374 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+ var reactDom = require('react-dom');
5
+ var reactNative = require('react-native');
6
+ var jsxRuntime = require('nativewind/jsx-runtime');
7
+
8
+ var __defProp = Object.defineProperty;
9
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
10
+
11
+ // ../tokens/build/theme.ts
12
+ var theme = {
13
+ color: {
14
+ danger: "#ef4444",
15
+ info: "#3b82f6",
16
+ neutral: {
17
+ "100": "#f4f4f5",
18
+ "200": "#e4e4e7",
19
+ "300": "#d4d4d8",
20
+ "400": "#a1a1aa",
21
+ "50": "#fafafa",
22
+ "500": "#71717a",
23
+ "600": "#52525b",
24
+ "700": "#3f3f46",
25
+ "800": "#27272a",
26
+ "900": "#18181b"
27
+ },
28
+ primary: {
29
+ "100": "#ccfbf1",
30
+ "200": "#99f6e4",
31
+ "300": "#5eead4",
32
+ "400": "#2dd4bf",
33
+ "50": "#f0fdfa",
34
+ "500": "#14b8a6",
35
+ "600": "#0d9488",
36
+ "700": "#0f766e",
37
+ "800": "#115e59",
38
+ "900": "#134e4a"
39
+ },
40
+ success: "#22c55e",
41
+ warning: "#f59e0b"
42
+ },
43
+ fontFamily: {
44
+ body: "system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
45
+ display: "ui-serif, Georgia, 'Times New Roman', serif",
46
+ mono: "ui-monospace, 'SF Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace"
47
+ },
48
+ fontSize: {
49
+ "2xl": "24px",
50
+ "3xl": "30px",
51
+ "4xl": "36px",
52
+ lg: "18px",
53
+ md: "16px",
54
+ sm: "14px",
55
+ xl: "20px",
56
+ xs: "12px"
57
+ },
58
+ fontWeight: {
59
+ bold: "700",
60
+ medium: "500",
61
+ regular: "400",
62
+ semibold: "600"
63
+ },
64
+ lineHeight: {
65
+ normal: "1.4",
66
+ relaxed: "1.6",
67
+ tight: "1.2"
68
+ },
69
+ radius: {
70
+ "2xl": "16px",
71
+ full: "9999px",
72
+ lg: "8px",
73
+ md: "6px",
74
+ none: "0px",
75
+ sm: "4px",
76
+ xl: "12px"
77
+ },
78
+ semantic: {
79
+ background: {
80
+ default: "#fafafa",
81
+ elevated: "#ffffff",
82
+ subtle: "#f4f4f5"
83
+ },
84
+ border: {
85
+ default: "#e4e4e7",
86
+ strong: "#d4d4d8"
87
+ },
88
+ interactive: {
89
+ destructive: "#ef4444",
90
+ primary: "#0d9488",
91
+ primaryHover: "#0f766e",
92
+ primaryPressed: "#115e59"
93
+ },
94
+ text: {
95
+ default: "#18181b",
96
+ inverted: "#fafafa",
97
+ muted: "#52525b"
98
+ }
99
+ },
100
+ shadow: {
101
+ lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
102
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
103
+ sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)"
104
+ },
105
+ spacing: {
106
+ "0": "0px",
107
+ "1": "4px",
108
+ "10": "40px",
109
+ "12": "48px",
110
+ "16": "64px",
111
+ "2": "8px",
112
+ "20": "80px",
113
+ "24": "96px",
114
+ "3": "12px",
115
+ "4": "16px",
116
+ "5": "20px",
117
+ "6": "24px",
118
+ "8": "32px"
119
+ }
120
+ };
121
+ var themeDark = {
122
+ color: {
123
+ danger: "#ef4444",
124
+ info: "#3b82f6",
125
+ neutral: {
126
+ "100": "#f4f4f5",
127
+ "200": "#e4e4e7",
128
+ "300": "#d4d4d8",
129
+ "400": "#a1a1aa",
130
+ "50": "#fafafa",
131
+ "500": "#71717a",
132
+ "600": "#52525b",
133
+ "700": "#3f3f46",
134
+ "800": "#27272a",
135
+ "900": "#18181b"
136
+ },
137
+ primary: {
138
+ "100": "#ccfbf1",
139
+ "200": "#99f6e4",
140
+ "300": "#5eead4",
141
+ "400": "#2dd4bf",
142
+ "50": "#f0fdfa",
143
+ "500": "#14b8a6",
144
+ "600": "#0d9488",
145
+ "700": "#0f766e",
146
+ "800": "#115e59",
147
+ "900": "#134e4a"
148
+ },
149
+ success: "#22c55e",
150
+ warning: "#f59e0b"
151
+ },
152
+ fontFamily: {
153
+ body: "system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif",
154
+ display: "ui-serif, Georgia, 'Times New Roman', serif",
155
+ mono: "ui-monospace, 'SF Mono', Menlo, Consolas, 'DejaVu Sans Mono', monospace"
156
+ },
157
+ fontSize: {
158
+ "2xl": "24px",
159
+ "3xl": "30px",
160
+ "4xl": "36px",
161
+ lg: "18px",
162
+ md: "16px",
163
+ sm: "14px",
164
+ xl: "20px",
165
+ xs: "12px"
166
+ },
167
+ fontWeight: {
168
+ bold: "700",
169
+ medium: "500",
170
+ regular: "400",
171
+ semibold: "600"
172
+ },
173
+ lineHeight: {
174
+ normal: "1.4",
175
+ relaxed: "1.6",
176
+ tight: "1.2"
177
+ },
178
+ radius: {
179
+ "2xl": "16px",
180
+ full: "9999px",
181
+ lg: "8px",
182
+ md: "6px",
183
+ none: "0px",
184
+ sm: "4px",
185
+ xl: "12px"
186
+ },
187
+ semantic: {
188
+ background: {
189
+ default: "#18181b",
190
+ elevated: "#3f3f46",
191
+ subtle: "#27272a"
192
+ },
193
+ border: {
194
+ default: "#3f3f46",
195
+ strong: "#52525b"
196
+ },
197
+ interactive: {
198
+ destructive: "#ef4444",
199
+ primary: "#2dd4bf",
200
+ primaryHover: "#5eead4",
201
+ primaryPressed: "#99f6e4"
202
+ },
203
+ text: {
204
+ default: "#fafafa",
205
+ inverted: "#18181b",
206
+ muted: "#a1a1aa"
207
+ }
208
+ },
209
+ shadow: {
210
+ lg: "0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)",
211
+ md: "0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)",
212
+ sm: "0 1px 2px 0 rgba(0, 0, 0, 0.05)"
213
+ },
214
+ spacing: {
215
+ "0": "0px",
216
+ "1": "4px",
217
+ "10": "40px",
218
+ "12": "48px",
219
+ "16": "64px",
220
+ "2": "8px",
221
+ "20": "80px",
222
+ "24": "96px",
223
+ "3": "12px",
224
+ "4": "16px",
225
+ "5": "20px",
226
+ "6": "24px",
227
+ "8": "32px"
228
+ }
229
+ };
230
+ var defaultTheme = {
231
+ light: theme,
232
+ dark: themeDark
233
+ };
234
+ var ThemeContext = react.createContext(defaultTheme);
235
+ ThemeContext.displayName = "ThemeContext";
236
+ var ColorSchemeOverrideContext = react.createContext(null);
237
+ ColorSchemeOverrideContext.displayName = "ColorSchemeOverrideContext";
238
+ var isWeb = reactNative.Platform.OS === "web";
239
+ function readWebScheme() {
240
+ if (typeof document === "undefined") {
241
+ return "light";
242
+ }
243
+ const root = document.documentElement;
244
+ if (root.classList.contains("dark")) {
245
+ return "dark";
246
+ }
247
+ if (root.getAttribute("data-theme") === "dark") {
248
+ return "dark";
249
+ }
250
+ return "light";
251
+ }
252
+ __name(readWebScheme, "readWebScheme");
253
+ function useColorScheme() {
254
+ const override = react.useContext(ColorSchemeOverrideContext);
255
+ const [scheme, setScheme] = react.useState(() => {
256
+ if (isWeb) {
257
+ return readWebScheme();
258
+ }
259
+ return reactNative.Appearance.getColorScheme() ?? "light";
260
+ });
261
+ react.useEffect(() => {
262
+ if (isWeb) {
263
+ const root = document.documentElement;
264
+ const update = /* @__PURE__ */ __name(() => setScheme(readWebScheme()), "update");
265
+ const observer = new MutationObserver(update);
266
+ observer.observe(root, { attributes: true, attributeFilter: ["class", "data-theme"] });
267
+ update();
268
+ return () => observer.disconnect();
269
+ }
270
+ const sub = reactNative.Appearance.addChangeListener(({ colorScheme }) => {
271
+ setScheme(colorScheme ?? "light");
272
+ });
273
+ return () => sub.remove();
274
+ }, []);
275
+ return override ?? scheme;
276
+ }
277
+ __name(useColorScheme, "useColorScheme");
278
+
279
+ // src/theme/use-theme-colors.ts
280
+ function useThemeColors() {
281
+ const scheme = useColorScheme();
282
+ const themePair = react.useContext(ThemeContext);
283
+ return scheme === "dark" ? themePair.dark : themePair.light;
284
+ }
285
+ __name(useThemeColors, "useThemeColors");
286
+ var isWeb2 = reactNative.Platform.OS === "web";
287
+ var make = /* @__PURE__ */ __name(({ path, glyph }) => /* @__PURE__ */ __name(function PlaceholderIcon({ size = 20, color = "currentColor" }) {
288
+ const colors = useThemeColors();
289
+ if (isWeb2) {
290
+ return /* @__PURE__ */ jsxRuntime.jsx(
291
+ "svg",
292
+ {
293
+ width: size,
294
+ height: size,
295
+ viewBox: "0 0 24 24",
296
+ fill: "none",
297
+ stroke: color,
298
+ strokeWidth: "2",
299
+ strokeLinecap: "round",
300
+ strokeLinejoin: "round",
301
+ "aria-hidden": "true",
302
+ children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: path })
303
+ }
304
+ );
305
+ }
306
+ const resolvedColor = color === "currentColor" ? colors.semantic.text.default : color;
307
+ return /* @__PURE__ */ jsxRuntime.jsx(
308
+ reactNative.Text,
309
+ {
310
+ accessibilityElementsHidden: true,
311
+ importantForAccessibility: "no-hide-descendants",
312
+ style: { fontSize: size, lineHeight: size, color: resolvedColor },
313
+ children: glyph
314
+ }
315
+ );
316
+ }, "PlaceholderIcon"), "make");
317
+ var defaultSemanticIcons = {
318
+ checkmark: make({ path: "M20 6 9 17l-5-5", glyph: "\u2713" }),
319
+ close: make({ path: "M18 6 6 18 M6 6l12 12", glyph: "\u2715" }),
320
+ eye: make({
321
+ path: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7S2 12 2 12z M12 9a3 3 0 1 0 0 6 3 3 0 0 0 0-6z",
322
+ glyph: "\u{1F441}"
323
+ }),
324
+ eyeOff: make({
325
+ path: "M17.94 17.94A10 10 0 0 1 2 12s3.5-7 10-7c2 0 3.8.6 5.4 1.5 M1 1l22 22",
326
+ glyph: "\u{1F648}"
327
+ }),
328
+ chevronDown: make({ path: "m6 9 6 6 6-6", glyph: "\u2304" }),
329
+ chevronUp: make({ path: "m18 15-6-6-6 6", glyph: "\u2303" }),
330
+ alertTriangle: make({
331
+ path: "M12 9v4 M12 17h.01 M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z",
332
+ glyph: "\u26A0"
333
+ }),
334
+ info: make({
335
+ path: "M12 8h.01 M11 12h1v4h1 M12 22C6.48 22 2 17.52 2 12 2 6.48 6.48 2 12 2c5.52 0 10 4.48 10 10 0 5.52-4.48 10-10 10z",
336
+ glyph: "\u24D8"
337
+ }),
338
+ check: make({ path: "M20 6 9 17l-5-5", glyph: "\u2713" }),
339
+ x: make({ path: "M18 6 6 18 M6 6l12 12", glyph: "\u2715" })
340
+ };
341
+
342
+ // src/theme/px.ts
343
+ function px(value) {
344
+ if (typeof value === "number") {
345
+ return value;
346
+ }
347
+ const n = Number.parseFloat(value);
348
+ return Number.isFinite(n) ? n : 0;
349
+ }
350
+ __name(px, "px");
351
+
352
+ // src/utils/cn.ts
353
+ function cn(...inputs) {
354
+ const out = [];
355
+ for (const input of inputs) {
356
+ append(out, input);
357
+ }
358
+ return out.join(" ");
359
+ }
360
+ __name(cn, "cn");
361
+ function append(out, input) {
362
+ if (!input) {
363
+ return;
364
+ }
365
+ if (typeof input === "string") {
366
+ if (input.length > 0) {
367
+ out.push(input);
368
+ }
369
+ return;
370
+ }
371
+ if (typeof input === "number") {
372
+ return;
373
+ }
374
+ if (Array.isArray(input)) {
375
+ for (const inner of input) {
376
+ append(out, inner);
377
+ }
378
+ return;
379
+ }
380
+ if (typeof input === "object") {
381
+ for (const key of Object.keys(input)) {
382
+ if (input[key]) {
383
+ out.push(key);
384
+ }
385
+ }
386
+ }
387
+ }
388
+ __name(append, "append");
389
+ var DEFAULT_PAGE_SIZE = 50;
390
+ var DEFAULT_ITEM_HEIGHT = 36;
391
+ var DEFAULT_MAX_MENU = 320;
392
+ var SEARCH_DEBOUNCE_MS = 150;
393
+ var VIRTUAL_OVERSCAN = 4;
394
+ var TYPE_AHEAD_RESET_MS = 500;
395
+ var defaultFilter = /* @__PURE__ */ __name((option, search) => {
396
+ if (!search) {
397
+ return true;
398
+ }
399
+ return option.label.toLowerCase().includes(search.toLowerCase());
400
+ }, "defaultFilter");
401
+ var Select = /* @__PURE__ */ __name((props) => {
402
+ const {
403
+ options: staticOptions,
404
+ loadOptions,
405
+ pageSize = DEFAULT_PAGE_SIZE,
406
+ searchable: searchableProp,
407
+ searchPlaceholder = "Search\u2026",
408
+ filterOption,
409
+ renderOption,
410
+ placeholder = "Select\u2026",
411
+ locale,
412
+ sortByLocale = true,
413
+ noOptionsMessage = "No options",
414
+ loadingMessage = "Loading\u2026",
415
+ disabled = false,
416
+ dir = "ltr",
417
+ virtualized: virtualizedProp,
418
+ itemHeight = DEFAULT_ITEM_HEIGHT,
419
+ maxMenuHeight = DEFAULT_MAX_MENU,
420
+ className,
421
+ testID,
422
+ id,
423
+ name
424
+ } = props;
425
+ const ariaLabel = props["aria-label"];
426
+ const ariaLabelledBy = props["aria-labelledby"];
427
+ const ariaDescribedBy = props["aria-describedby"];
428
+ const ariaInvalid = props["aria-invalid"];
429
+ const ariaRequired = props["aria-required"];
430
+ const multiple = props.multiple === true;
431
+ const maxSelected = multiple ? props.maxSelected : void 0;
432
+ const maxChips = multiple ? props.maxChips ?? 3 : void 0;
433
+ const baseId = react.useId();
434
+ const colors = useThemeColors();
435
+ const [open, setOpen] = react.useState(false);
436
+ const controlledValues = multiple ? props.value : props.value !== void 0 ? [props.value] : void 0;
437
+ const defaultValues = multiple ? props.defaultValue ?? [] : props.defaultValue !== void 0 ? [props.defaultValue] : [];
438
+ const [innerValues, setInnerValues] = react.useState(defaultValues);
439
+ const isControlled = controlledValues !== void 0;
440
+ const currentValues = isControlled ? controlledValues : innerValues;
441
+ const current = currentValues[0];
442
+ const [searchInput, setSearchInput] = react.useState("");
443
+ const [debouncedSearch, setDebouncedSearch] = react.useState("");
444
+ const [activeIndex, setActiveIndex] = react.useState(0);
445
+ react.useEffect(() => {
446
+ const t = setTimeout(() => setDebouncedSearch(searchInput), SEARCH_DEBOUNCE_MS);
447
+ return () => clearTimeout(t);
448
+ }, [searchInput]);
449
+ const [asyncItems, setAsyncItems] = react.useState([]);
450
+ const [asyncLoading, setAsyncLoading] = react.useState(false);
451
+ const [asyncTotal, setAsyncTotal] = react.useState(void 0);
452
+ const asyncRequestId = react.useRef(0);
453
+ const isAsync = loadOptions !== void 0;
454
+ react.useEffect(() => {
455
+ if (!isAsync || !loadOptions || !open) {
456
+ return;
457
+ }
458
+ const requestId = ++asyncRequestId.current;
459
+ setAsyncLoading(true);
460
+ setAsyncItems([]);
461
+ setAsyncTotal(void 0);
462
+ loadOptions({ search: debouncedSearch, offset: 0, limit: pageSize }).then((result) => {
463
+ if (requestId !== asyncRequestId.current) {
464
+ return;
465
+ }
466
+ setAsyncItems(result.items.slice());
467
+ setAsyncTotal(result.total);
468
+ }).catch(() => {
469
+ }).finally(() => {
470
+ if (requestId === asyncRequestId.current) {
471
+ setAsyncLoading(false);
472
+ }
473
+ });
474
+ }, [debouncedSearch, isAsync, loadOptions, pageSize, open]);
475
+ const loadMore = react.useCallback(() => {
476
+ if (!isAsync || !loadOptions || asyncLoading) {
477
+ return;
478
+ }
479
+ const haveAll = asyncTotal !== void 0 && asyncItems.length >= asyncTotal;
480
+ if (haveAll) {
481
+ return;
482
+ }
483
+ const requestId = ++asyncRequestId.current;
484
+ setAsyncLoading(true);
485
+ loadOptions({ search: debouncedSearch, offset: asyncItems.length, limit: pageSize }).then((result) => {
486
+ if (requestId !== asyncRequestId.current) {
487
+ return;
488
+ }
489
+ setAsyncItems((prev) => prev.concat(result.items));
490
+ if (result.total !== void 0) {
491
+ setAsyncTotal(result.total);
492
+ }
493
+ }).catch(() => void 0).finally(() => {
494
+ if (requestId === asyncRequestId.current) {
495
+ setAsyncLoading(false);
496
+ }
497
+ });
498
+ }, [asyncItems.length, asyncLoading, asyncTotal, debouncedSearch, isAsync, loadOptions, pageSize]);
499
+ const visibleOptions = react.useMemo(() => {
500
+ const source = isAsync ? asyncItems : staticOptions ?? [];
501
+ const filtered = isAsync ? source.slice() : source.filter((opt) => (filterOption ?? defaultFilter)(opt, debouncedSearch));
502
+ if (locale && sortByLocale) {
503
+ const collator = new Intl.Collator(locale, { sensitivity: "base", numeric: true });
504
+ return filtered.slice().sort((a, b) => {
505
+ const ga = a.group ?? "";
506
+ const gb = b.group ?? "";
507
+ const groupDelta = collator.compare(ga, gb);
508
+ if (groupDelta !== 0) {
509
+ return groupDelta;
510
+ }
511
+ return collator.compare(a.label, b.label);
512
+ });
513
+ }
514
+ return filtered;
515
+ }, [isAsync, asyncItems, staticOptions, filterOption, debouncedSearch, locale, sortByLocale]);
516
+ const selectedOption = react.useMemo(() => {
517
+ const all = isAsync ? asyncItems : staticOptions ?? [];
518
+ return all.find((o) => o.value === current);
519
+ }, [asyncItems, isAsync, staticOptions, current]);
520
+ const selectedOptions = react.useMemo(() => {
521
+ if (!multiple) {
522
+ return [];
523
+ }
524
+ const all = isAsync ? asyncItems : staticOptions ?? [];
525
+ const map = new Map(all.map((o) => [o.value, o]));
526
+ return currentValues.map((v) => map.get(v)).filter((o) => o !== void 0);
527
+ }, [multiple, currentValues, asyncItems, isAsync, staticOptions]);
528
+ const searchable = searchableProp ?? (isAsync || staticOptions !== void 0 && staticOptions.length >= 10);
529
+ const virtualized = virtualizedProp ?? visibleOptions.length > 100;
530
+ react.useEffect(() => {
531
+ setActiveIndex((idx) => Math.min(Math.max(0, idx), Math.max(0, visibleOptions.length - 1)));
532
+ }, [visibleOptions.length]);
533
+ const onSelect = react.useCallback(
534
+ (option) => {
535
+ if (option.disabled) {
536
+ return;
537
+ }
538
+ if (multiple) {
539
+ const has = currentValues.includes(option.value);
540
+ let nextValues;
541
+ if (has) {
542
+ nextValues = currentValues.filter((v) => v !== option.value);
543
+ } else {
544
+ if (maxSelected !== void 0 && currentValues.length >= maxSelected) {
545
+ return;
546
+ }
547
+ nextValues = [...currentValues, option.value];
548
+ }
549
+ if (!isControlled) {
550
+ setInnerValues(nextValues);
551
+ }
552
+ const allOpts = [
553
+ ...staticOptions ?? [],
554
+ ...asyncItems
555
+ ];
556
+ const optMap = new Map(allOpts.map((o) => [o.value, o]));
557
+ const selectedOpts = nextValues.map((v) => optMap.get(v)).filter((o) => o !== void 0);
558
+ props.onChange?.(nextValues, selectedOpts);
559
+ return;
560
+ }
561
+ if (!isControlled) {
562
+ setInnerValues([option.value]);
563
+ }
564
+ props.onChange?.(option.value, option);
565
+ setOpen(false);
566
+ setSearchInput("");
567
+ },
568
+ // biome-ignore lint/correctness/useExhaustiveDependencies: `props` is the discriminated union — destructuring it would defeat the narrowing; the asyncItems / staticOptions captures intentionally re-trigger the callback when the option pool changes
569
+ [multiple, isControlled, currentValues, maxSelected, staticOptions, asyncItems, props]
570
+ );
571
+ const clearAll = react.useCallback(() => {
572
+ if (!isControlled) {
573
+ setInnerValues([]);
574
+ }
575
+ props.onChange?.([], []);
576
+ }, [isControlled, props]);
577
+ const moveActive = react.useCallback(
578
+ (delta) => {
579
+ setActiveIndex((idx) => {
580
+ if (visibleOptions.length === 0) {
581
+ return 0;
582
+ }
583
+ let next = (idx + delta + visibleOptions.length) % visibleOptions.length;
584
+ for (let attempts = 0; attempts < visibleOptions.length; attempts += 1) {
585
+ if (!visibleOptions[next]?.disabled) {
586
+ return next;
587
+ }
588
+ next = (next + delta + visibleOptions.length) % visibleOptions.length;
589
+ }
590
+ return idx;
591
+ });
592
+ },
593
+ [visibleOptions]
594
+ );
595
+ const typeAheadRef = react.useRef({
596
+ buffer: "",
597
+ timer: null
598
+ });
599
+ react.useEffect(() => {
600
+ return () => {
601
+ if (typeAheadRef.current.timer) {
602
+ clearTimeout(typeAheadRef.current.timer);
603
+ typeAheadRef.current.timer = null;
604
+ }
605
+ };
606
+ }, []);
607
+ const handleTypeAhead = react.useCallback(
608
+ (char) => {
609
+ if (visibleOptions.length === 0) {
610
+ return;
611
+ }
612
+ if (typeAheadRef.current.timer) {
613
+ clearTimeout(typeAheadRef.current.timer);
614
+ }
615
+ const nextBuffer = typeAheadRef.current.buffer + char.toLowerCase();
616
+ typeAheadRef.current.buffer = nextBuffer;
617
+ typeAheadRef.current.timer = setTimeout(() => {
618
+ typeAheadRef.current.buffer = "";
619
+ typeAheadRef.current.timer = null;
620
+ }, TYPE_AHEAD_RESET_MS);
621
+ const allSame = nextBuffer.length > 1 && nextBuffer.split("").every((c) => c === nextBuffer[0]);
622
+ const cycleMode = nextBuffer.length === 1 || allSame;
623
+ const needle = cycleMode ? nextBuffer.charAt(0) : nextBuffer;
624
+ const len = visibleOptions.length;
625
+ const startFrom = cycleMode ? (activeIndex + 1) % len : 0;
626
+ for (let i = 0; i < len; i += 1) {
627
+ const idx = (startFrom + i) % len;
628
+ const opt = visibleOptions[idx];
629
+ if (!opt || opt.disabled) {
630
+ continue;
631
+ }
632
+ if (opt.label.toLowerCase().startsWith(needle)) {
633
+ setActiveIndex(idx);
634
+ return;
635
+ }
636
+ }
637
+ },
638
+ [visibleOptions, activeIndex]
639
+ );
640
+ const handleListKeyDown = react.useCallback(
641
+ (event) => {
642
+ switch (event.key) {
643
+ case "ArrowDown":
644
+ event.preventDefault();
645
+ moveActive(1);
646
+ return true;
647
+ case "ArrowUp":
648
+ event.preventDefault();
649
+ moveActive(-1);
650
+ return true;
651
+ case "Home": {
652
+ event.preventDefault();
653
+ const idx = visibleOptions.findIndex((o) => !o.disabled);
654
+ if (idx >= 0) {
655
+ setActiveIndex(idx);
656
+ }
657
+ return true;
658
+ }
659
+ case "End": {
660
+ event.preventDefault();
661
+ for (let i = visibleOptions.length - 1; i >= 0; i -= 1) {
662
+ if (!visibleOptions[i]?.disabled) {
663
+ setActiveIndex(i);
664
+ break;
665
+ }
666
+ }
667
+ return true;
668
+ }
669
+ case "Enter": {
670
+ const opt = visibleOptions[activeIndex];
671
+ if (opt) {
672
+ event.preventDefault();
673
+ onSelect(opt);
674
+ }
675
+ return true;
676
+ }
677
+ case "Escape":
678
+ event.preventDefault();
679
+ setOpen(false);
680
+ if (reactNative.Platform.OS === "web") {
681
+ const trigger = triggerRef.current;
682
+ trigger?.focus?.();
683
+ }
684
+ return true;
685
+ case "Tab":
686
+ setOpen(false);
687
+ return true;
688
+ }
689
+ return false;
690
+ },
691
+ [moveActive, activeIndex, visibleOptions, onSelect]
692
+ );
693
+ const handleSearchKeyDown = react.useCallback(
694
+ (event) => {
695
+ handleListKeyDown(event);
696
+ },
697
+ [handleListKeyDown]
698
+ );
699
+ const handlePopupKeyDown = react.useCallback(
700
+ (event) => {
701
+ if (handleListKeyDown(event)) {
702
+ return;
703
+ }
704
+ if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey && event.key !== " ") {
705
+ event.preventDefault();
706
+ handleTypeAhead(event.key);
707
+ }
708
+ },
709
+ [handleListKeyDown, handleTypeAhead]
710
+ );
711
+ const handleTriggerKeyDown = react.useCallback(
712
+ (event) => {
713
+ switch (event.key) {
714
+ case " ":
715
+ case "Enter":
716
+ case "ArrowDown":
717
+ case "ArrowUp":
718
+ event.preventDefault();
719
+ setOpen(true);
720
+ return;
721
+ }
722
+ if (!disabled && event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
723
+ event.preventDefault();
724
+ setOpen(true);
725
+ handleTypeAhead(event.key);
726
+ }
727
+ },
728
+ [disabled, handleTypeAhead]
729
+ );
730
+ const containerRef = react.useRef(null);
731
+ const triggerRef = react.useRef(null);
732
+ const popupRef = react.useRef(null);
733
+ react.useEffect(() => {
734
+ if (reactNative.Platform.OS !== "web" || typeof document === "undefined" || typeof document.addEventListener !== "function") {
735
+ return;
736
+ }
737
+ if (!open) {
738
+ return;
739
+ }
740
+ const onDocClick = /* @__PURE__ */ __name((event) => {
741
+ const node = containerRef.current;
742
+ const popup = popupRef.current;
743
+ const target = event.target;
744
+ if (node?.contains(target)) {
745
+ return;
746
+ }
747
+ if (popup?.contains(target)) {
748
+ return;
749
+ }
750
+ setOpen(false);
751
+ }, "onDocClick");
752
+ document.addEventListener("mousedown", onDocClick);
753
+ return () => document.removeEventListener("mousedown", onDocClick);
754
+ }, [open]);
755
+ const [triggerRect, setTriggerRect] = react.useState(
756
+ null
757
+ );
758
+ const measureTrigger = react.useCallback(() => {
759
+ const node = triggerRef.current;
760
+ if (!node) {
761
+ return;
762
+ }
763
+ if (reactNative.Platform.OS === "web" && typeof node.getBoundingClientRect === "function") {
764
+ const rect = node.getBoundingClientRect();
765
+ setTriggerRect({ top: rect.top, left: rect.left, width: rect.width, height: rect.height });
766
+ return;
767
+ }
768
+ if (typeof node.measure === "function") {
769
+ node.measure((_x, _y, w, h, pageX, pageY) => {
770
+ setTriggerRect({ top: pageY, left: pageX, width: w, height: h });
771
+ });
772
+ }
773
+ }, []);
774
+ react.useEffect(() => {
775
+ if (!open) {
776
+ return;
777
+ }
778
+ if (reactNative.Platform.OS !== "web" || typeof window === "undefined" || typeof window.addEventListener !== "function") {
779
+ return;
780
+ }
781
+ measureTrigger();
782
+ window.addEventListener("scroll", measureTrigger, true);
783
+ window.addEventListener("resize", measureTrigger);
784
+ return () => {
785
+ window.removeEventListener("scroll", measureTrigger, true);
786
+ window.removeEventListener("resize", measureTrigger);
787
+ };
788
+ }, [open, measureTrigger]);
789
+ react.useEffect(() => {
790
+ if (!open || searchable || reactNative.Platform.OS !== "web") {
791
+ return;
792
+ }
793
+ const id2 = requestAnimationFrame(() => {
794
+ const node = popupRef.current;
795
+ node?.focus?.();
796
+ });
797
+ return () => cancelAnimationFrame(id2);
798
+ }, [open, searchable]);
799
+ const onListScroll = react.useCallback(
800
+ (event) => {
801
+ if (!isAsync) {
802
+ return;
803
+ }
804
+ const { contentOffset, contentSize, layoutMeasurement } = event.nativeEvent;
805
+ const remaining = contentSize.height - contentOffset.y - layoutMeasurement.height;
806
+ if (remaining < itemHeight * 4) {
807
+ loadMore();
808
+ }
809
+ },
810
+ [isAsync, itemHeight, loadMore]
811
+ );
812
+ const triggerStyle = {
813
+ flexDirection: "row",
814
+ alignItems: "center",
815
+ justifyContent: "space-between",
816
+ gap: px(colors.spacing["2"]),
817
+ paddingHorizontal: px(colors.spacing["3"]),
818
+ paddingVertical: px(colors.spacing["2"]),
819
+ minHeight: 36,
820
+ // component-density literal — not from theme
821
+ borderWidth: 1,
822
+ borderColor: colors.semantic.border.default,
823
+ borderRadius: px(colors.radius.md),
824
+ backgroundColor: colors.semantic.background.elevated,
825
+ opacity: disabled ? 0.6 : 1
826
+ };
827
+ const winDims = reactNative.useWindowDimensions();
828
+ const popupStyle = triggerRect ? {
829
+ position: reactNative.Platform.OS === "web" ? "fixed" : "absolute",
830
+ top: triggerRect.top + triggerRect.height + px(colors.spacing["1"]),
831
+ left: dir === "rtl" ? void 0 : triggerRect.left,
832
+ right: dir === "rtl" ? reactNative.Platform.OS === "web" && typeof window !== "undefined" ? window.innerWidth - (triggerRect.left + triggerRect.width) : winDims.width - (triggerRect.left + triggerRect.width) : void 0,
833
+ minWidth: Math.max(200, triggerRect.width),
834
+ backgroundColor: colors.semantic.background.elevated,
835
+ borderRadius: px(colors.radius.lg),
836
+ borderWidth: 1,
837
+ borderColor: colors.semantic.border.default,
838
+ // 2147483646 (max int32 - 1) so we sit above any third-party
839
+ // chrome (toasts, modals, dev banners) without picking a fight
840
+ // for the very top slot. Combined with portaling to body below,
841
+ // this also dodges any ancestor stacking context that would
842
+ // otherwise trap our z-index inside a sibling preview frame.
843
+ zIndex: 2147483646,
844
+ ...{ boxShadow: "0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)" }
845
+ } : {
846
+ // Trigger not yet measured — render off-screen until the
847
+ // first measurement lands. Avoids a one-frame flash at (0,0).
848
+ position: reactNative.Platform.OS === "web" ? "fixed" : "absolute",
849
+ top: -9999,
850
+ left: -9999
851
+ };
852
+ const containerProps = {
853
+ ref: /* @__PURE__ */ __name((node) => {
854
+ containerRef.current = node;
855
+ }, "ref"),
856
+ ...testID !== void 0 ? { testID } : {},
857
+ dir
858
+ };
859
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { ...containerProps, className: cn("relative", className), style: { position: "relative" }, children: [
860
+ /* @__PURE__ */ jsxRuntime.jsxs(
861
+ reactNative.Pressable,
862
+ {
863
+ ref: (node) => {
864
+ triggerRef.current = node;
865
+ },
866
+ ...{
867
+ onKeyDown: handleTriggerKeyDown,
868
+ role: "combobox",
869
+ accessibilityRole: "combobox",
870
+ "aria-expanded": open,
871
+ "aria-controls": `${baseId}-listbox`,
872
+ "aria-haspopup": "listbox",
873
+ tabIndex: disabled ? -1 : 0,
874
+ ...id !== void 0 ? { id, nativeID: id } : {},
875
+ ...name !== void 0 ? { name } : {},
876
+ ...ariaLabel !== void 0 ? { "aria-label": ariaLabel, accessibilityLabel: ariaLabel } : {},
877
+ ...ariaLabelledBy !== void 0 ? { "aria-labelledby": ariaLabelledBy, accessibilityLabelledBy: ariaLabelledBy } : {},
878
+ ...ariaDescribedBy !== void 0 ? { "aria-describedby": ariaDescribedBy, accessibilityDescribedBy: ariaDescribedBy } : {},
879
+ ...ariaInvalid === true ? { "aria-invalid": true } : {},
880
+ ...ariaRequired === true ? { "aria-required": true } : {},
881
+ ...disabled ? { "aria-disabled": true, disabled: true } : {}
882
+ },
883
+ onPress: () => {
884
+ if (disabled) {
885
+ return;
886
+ }
887
+ measureTrigger();
888
+ setOpen((v) => !v);
889
+ },
890
+ style: triggerStyle,
891
+ children: [
892
+ multiple ? /* @__PURE__ */ jsxRuntime.jsx(MultiTriggerLabel, { options: selectedOptions, placeholder, maxChips: maxChips ?? 3 }) : /* @__PURE__ */ jsxRuntime.jsx(
893
+ reactNative.Text,
894
+ {
895
+ style: {
896
+ color: selectedOption ? colors.semantic.text.default : colors.semantic.text.muted,
897
+ fontFamily: colors.fontFamily.body,
898
+ fontSize: px(colors.fontSize.sm),
899
+ flex: 1
900
+ },
901
+ numberOfLines: 1,
902
+ children: selectedOption?.label ?? placeholder
903
+ }
904
+ ),
905
+ /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.chevronDown, { size: 16, color: colors.semantic.text.muted })
906
+ ]
907
+ }
908
+ ),
909
+ open ? renderPopup() : null
910
+ ] });
911
+ function renderPopup() {
912
+ const popup = /* @__PURE__ */ jsxRuntime.jsxs(
913
+ reactNative.View,
914
+ {
915
+ ref: (node) => {
916
+ popupRef.current = node;
917
+ },
918
+ ...{
919
+ role: "listbox",
920
+ id: `${baseId}-listbox`,
921
+ ...multiple ? { "aria-multiselectable": true } : {},
922
+ // Without a search field there's no input to capture
923
+ // keystrokes — make the popup itself focusable and own
924
+ // arrow / Enter / Escape / type-ahead. With a search
925
+ // field these belong to the input below.
926
+ ...searchable ? {} : { tabIndex: -1, onKeyDown: handlePopupKeyDown }
927
+ },
928
+ style: popupStyle,
929
+ children: [
930
+ searchable ? /* @__PURE__ */ jsxRuntime.jsx(
931
+ SearchInput,
932
+ {
933
+ value: searchInput,
934
+ onChange: setSearchInput,
935
+ onKeyDown: handleSearchKeyDown,
936
+ placeholder: searchPlaceholder,
937
+ dir
938
+ }
939
+ ) : null,
940
+ multiple && currentValues.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(MultiSelectionHeader, { count: currentValues.length, onClearAll: clearAll }) : null,
941
+ /* @__PURE__ */ jsxRuntime.jsx(
942
+ SelectList,
943
+ {
944
+ options: visibleOptions,
945
+ activeIndex,
946
+ currentValue: current,
947
+ selectedValues: currentValues,
948
+ multiple,
949
+ onSelect,
950
+ onActiveChange: setActiveIndex,
951
+ ...renderOption !== void 0 ? { renderOption } : {},
952
+ itemHeight,
953
+ maxHeight: maxMenuHeight,
954
+ virtualized,
955
+ loading: isAsync && asyncLoading,
956
+ loadingMessage,
957
+ noOptionsMessage,
958
+ listboxId: `${baseId}-listbox`,
959
+ onScroll: onListScroll
960
+ }
961
+ )
962
+ ]
963
+ }
964
+ );
965
+ if (reactNative.Platform.OS === "web" && typeof document !== "undefined") {
966
+ return reactDom.createPortal(popup, document.body);
967
+ }
968
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Modal, { transparent: true, visible: true, animationType: "fade", onRequestClose: () => setOpen(false), statusBarTranslucent: true, children: [
969
+ /* @__PURE__ */ jsxRuntime.jsx(
970
+ reactNative.Pressable,
971
+ {
972
+ onPress: () => setOpen(false),
973
+ style: {
974
+ position: "absolute",
975
+ top: 0,
976
+ left: 0,
977
+ right: 0,
978
+ bottom: 0
979
+ }
980
+ }
981
+ ),
982
+ popup
983
+ ] });
984
+ }
985
+ }, "Select");
986
+ var SearchInput = /* @__PURE__ */ __name(({ value, onChange, onKeyDown, placeholder, dir }) => {
987
+ const colors = useThemeColors();
988
+ const inputRef = react.useRef(null);
989
+ react.useEffect(() => {
990
+ inputRef.current?.focus?.();
991
+ }, []);
992
+ return /* @__PURE__ */ jsxRuntime.jsx(
993
+ reactNative.View,
994
+ {
995
+ style: {
996
+ paddingHorizontal: px(colors.spacing["2"]),
997
+ paddingVertical: px(colors.spacing["2"]),
998
+ borderBottomWidth: 1,
999
+ borderBottomColor: colors.semantic.border.default
1000
+ },
1001
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1002
+ "input",
1003
+ {
1004
+ ref: inputRef,
1005
+ type: "text",
1006
+ value,
1007
+ onChange: (event) => onChange(event.target.value),
1008
+ onKeyDown,
1009
+ placeholder,
1010
+ dir,
1011
+ "aria-label": "Search options",
1012
+ style: {
1013
+ width: "100%",
1014
+ // Inline `padding: '6px 8px'` shorthand intentionally kept as a
1015
+ // string for the native HTML <input> — it's not an RN style prop.
1016
+ padding: `${px(colors.spacing["2"]) - 2}px ${px(colors.spacing["2"])}px`,
1017
+ fontFamily: colors.fontFamily.body,
1018
+ fontSize: px(colors.fontSize.sm),
1019
+ color: colors.semantic.text.default,
1020
+ backgroundColor: colors.semantic.background.elevated,
1021
+ border: `1px solid ${colors.semantic.border.default}`,
1022
+ borderRadius: px(colors.radius.sm),
1023
+ outline: "none"
1024
+ }
1025
+ }
1026
+ )
1027
+ }
1028
+ );
1029
+ }, "SearchInput");
1030
+ var SelectList = /* @__PURE__ */ __name(({
1031
+ options,
1032
+ activeIndex,
1033
+ currentValue,
1034
+ selectedValues,
1035
+ multiple,
1036
+ onSelect,
1037
+ onActiveChange,
1038
+ renderOption,
1039
+ itemHeight,
1040
+ maxHeight,
1041
+ virtualized,
1042
+ loading,
1043
+ loadingMessage,
1044
+ noOptionsMessage,
1045
+ listboxId,
1046
+ onScroll
1047
+ }) => {
1048
+ const colors = useThemeColors();
1049
+ const [scrollTop, setScrollTop] = react.useState(0);
1050
+ const totalHeight = options.length * itemHeight;
1051
+ const visibleStart = virtualized ? Math.max(0, Math.floor(scrollTop / itemHeight) - VIRTUAL_OVERSCAN) : 0;
1052
+ const visibleEnd = virtualized ? Math.min(options.length, Math.ceil((scrollTop + maxHeight) / itemHeight) + VIRTUAL_OVERSCAN) : options.length;
1053
+ const handleScroll = /* @__PURE__ */ __name((event) => {
1054
+ if (virtualized) {
1055
+ setScrollTop(event.nativeEvent.contentOffset.y);
1056
+ }
1057
+ onScroll(event);
1058
+ }, "handleScroll");
1059
+ if (loading && options.length === 0) {
1060
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { padding: px(colors.spacing["4"]), alignItems: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1061
+ reactNative.Text,
1062
+ {
1063
+ style: {
1064
+ color: colors.semantic.text.muted,
1065
+ fontFamily: colors.fontFamily.body,
1066
+ fontSize: px(colors.fontSize.sm)
1067
+ },
1068
+ children: loadingMessage
1069
+ }
1070
+ ) });
1071
+ }
1072
+ if (options.length === 0) {
1073
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: { padding: px(colors.spacing["4"]), alignItems: "center" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1074
+ reactNative.Text,
1075
+ {
1076
+ style: {
1077
+ color: colors.semantic.text.muted,
1078
+ fontFamily: colors.fontFamily.body,
1079
+ fontSize: px(colors.fontSize.sm)
1080
+ },
1081
+ children: noOptionsMessage
1082
+ }
1083
+ ) });
1084
+ }
1085
+ const items = [];
1086
+ let lastGroup;
1087
+ for (let i = visibleStart; i < visibleEnd; i += 1) {
1088
+ const opt = options[i];
1089
+ if (!opt) {
1090
+ continue;
1091
+ }
1092
+ if (opt.group !== lastGroup && opt.group !== void 0) {
1093
+ items.push(
1094
+ /* @__PURE__ */ jsxRuntime.jsx(
1095
+ reactNative.View,
1096
+ {
1097
+ style: {
1098
+ paddingHorizontal: px(colors.spacing["3"]),
1099
+ paddingTop: px(colors.spacing["2"]),
1100
+ paddingBottom: px(colors.spacing["1"]),
1101
+ position: virtualized ? "absolute" : "relative",
1102
+ top: virtualized ? i * itemHeight - px(colors.spacing["4"]) : void 0,
1103
+ left: 0,
1104
+ right: 0
1105
+ },
1106
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1107
+ reactNative.Text,
1108
+ {
1109
+ style: {
1110
+ color: colors.semantic.text.muted,
1111
+ fontFamily: colors.fontFamily.body,
1112
+ fontSize: 11,
1113
+ // group header — component-density literal — not from theme (smaller than xs)
1114
+ fontWeight: colors.fontWeight.semibold,
1115
+ textTransform: "uppercase",
1116
+ letterSpacing: 0.5
1117
+ },
1118
+ children: opt.group
1119
+ }
1120
+ )
1121
+ },
1122
+ `grp-${i}-${opt.group}`
1123
+ )
1124
+ );
1125
+ lastGroup = opt.group;
1126
+ }
1127
+ const selected = multiple ? selectedValues.includes(opt.value) : opt.value === currentValue;
1128
+ const active = i === activeIndex;
1129
+ const itemNode = renderOption ? renderOption(opt, { selected, active }) : /* @__PURE__ */ jsxRuntime.jsx(DefaultOptionRow, { option: opt, selected, active, multiple });
1130
+ items.push(
1131
+ /* @__PURE__ */ jsxRuntime.jsx(
1132
+ reactNative.Pressable,
1133
+ {
1134
+ ...{
1135
+ role: "option",
1136
+ accessibilityRole: "none",
1137
+ "aria-selected": selected,
1138
+ onMouseEnter: /* @__PURE__ */ __name(() => onActiveChange(i), "onMouseEnter"),
1139
+ ...opt.disabled ? { "aria-disabled": true, disabled: true } : {}
1140
+ },
1141
+ onPress: () => onSelect(opt),
1142
+ style: {
1143
+ position: virtualized ? "absolute" : "relative",
1144
+ top: virtualized ? i * itemHeight : void 0,
1145
+ left: 0,
1146
+ right: 0,
1147
+ height: itemHeight,
1148
+ flexDirection: "row",
1149
+ alignItems: "center",
1150
+ paddingHorizontal: px(colors.spacing["3"]),
1151
+ backgroundColor: active ? colors.semantic.background.subtle : "transparent",
1152
+ opacity: opt.disabled ? 0.5 : 1
1153
+ },
1154
+ children: itemNode
1155
+ },
1156
+ `opt-${i}-${opt.value}`
1157
+ )
1158
+ );
1159
+ }
1160
+ return /* @__PURE__ */ jsxRuntime.jsx(
1161
+ reactNative.ScrollView,
1162
+ {
1163
+ nativeID: listboxId,
1164
+ onScroll: handleScroll,
1165
+ scrollEventThrottle: 16,
1166
+ style: { maxHeight },
1167
+ contentContainerStyle: virtualized ? { height: totalHeight, position: "relative" } : void 0,
1168
+ children: items
1169
+ }
1170
+ );
1171
+ }, "SelectList");
1172
+ var DefaultOptionRow = /* @__PURE__ */ __name(({
1173
+ option,
1174
+ selected,
1175
+ active,
1176
+ multiple = false
1177
+ }) => {
1178
+ const colors = useThemeColors();
1179
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: { flexDirection: "row", alignItems: "center", flex: 1, gap: px(colors.spacing["2"]) }, children: [
1180
+ multiple ? (
1181
+ // Inline checkbox-style indicator. We don't reuse <Checkbox>
1182
+ // here because the row is already a Pressable — nesting two
1183
+ // pressable surfaces breaks tap handling on native; this
1184
+ // is purely visual (the Pressable parent owns the toggle).
1185
+ /* @__PURE__ */ jsxRuntime.jsx(
1186
+ reactNative.View,
1187
+ {
1188
+ "aria-hidden": true,
1189
+ accessibilityElementsHidden: true,
1190
+ importantForAccessibility: "no-hide-descendants",
1191
+ style: {
1192
+ width: 18,
1193
+ height: 18,
1194
+ borderWidth: 1,
1195
+ borderRadius: px(colors.radius.sm),
1196
+ borderColor: selected ? colors.semantic.interactive.primary : colors.semantic.border.strong,
1197
+ backgroundColor: selected ? colors.semantic.interactive.primary : "transparent",
1198
+ alignItems: "center",
1199
+ justifyContent: "center"
1200
+ },
1201
+ children: selected ? /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.check, { size: 12, color: colors.semantic.text.inverted }) : null
1202
+ }
1203
+ )
1204
+ ) : null,
1205
+ /* @__PURE__ */ jsxRuntime.jsx(
1206
+ reactNative.Text,
1207
+ {
1208
+ style: {
1209
+ color: colors.semantic.text.default,
1210
+ fontFamily: colors.fontFamily.body,
1211
+ fontSize: px(colors.fontSize.sm),
1212
+ fontWeight: selected ? colors.fontWeight.semibold : colors.fontWeight.regular,
1213
+ flex: 1
1214
+ },
1215
+ numberOfLines: 1,
1216
+ children: option.label
1217
+ }
1218
+ ),
1219
+ selected && !multiple ? /* @__PURE__ */ jsxRuntime.jsx(defaultSemanticIcons.check, { size: 16, color: colors.semantic.interactive.primary }) : null,
1220
+ active ? null : null
1221
+ ] });
1222
+ }, "DefaultOptionRow");
1223
+ var MultiTriggerLabel = /* @__PURE__ */ __name(({
1224
+ options,
1225
+ placeholder,
1226
+ maxChips
1227
+ }) => {
1228
+ const colors = useThemeColors();
1229
+ if (options.length === 0) {
1230
+ return /* @__PURE__ */ jsxRuntime.jsx(
1231
+ reactNative.Text,
1232
+ {
1233
+ style: {
1234
+ color: colors.semantic.text.muted,
1235
+ fontFamily: colors.fontFamily.body,
1236
+ fontSize: px(colors.fontSize.sm),
1237
+ flex: 1
1238
+ },
1239
+ numberOfLines: 1,
1240
+ children: placeholder
1241
+ }
1242
+ );
1243
+ }
1244
+ if (options.length > maxChips) {
1245
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1246
+ reactNative.Text,
1247
+ {
1248
+ style: {
1249
+ color: colors.semantic.text.default,
1250
+ fontFamily: colors.fontFamily.body,
1251
+ fontSize: px(colors.fontSize.sm),
1252
+ fontWeight: colors.fontWeight.medium,
1253
+ fontVariant: ["tabular-nums"],
1254
+ flex: 1
1255
+ },
1256
+ numberOfLines: 1,
1257
+ children: [
1258
+ options.length,
1259
+ " selected"
1260
+ ]
1261
+ }
1262
+ );
1263
+ }
1264
+ return /* @__PURE__ */ jsxRuntime.jsx(
1265
+ reactNative.View,
1266
+ {
1267
+ style: {
1268
+ flexDirection: "row",
1269
+ alignItems: "center",
1270
+ flexWrap: "wrap",
1271
+ rowGap: px(colors.spacing["1"]),
1272
+ columnGap: px(colors.spacing["1"]),
1273
+ flex: 1
1274
+ },
1275
+ children: options.map((opt) => /* @__PURE__ */ jsxRuntime.jsx(
1276
+ reactNative.View,
1277
+ {
1278
+ style: {
1279
+ flexDirection: "row",
1280
+ alignItems: "center",
1281
+ paddingHorizontal: px(colors.spacing["2"]),
1282
+ paddingVertical: 2,
1283
+ borderRadius: px(colors.radius.sm),
1284
+ backgroundColor: colors.semantic.background.subtle,
1285
+ borderWidth: 1,
1286
+ borderColor: colors.semantic.border.default
1287
+ },
1288
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1289
+ reactNative.Text,
1290
+ {
1291
+ style: {
1292
+ color: colors.semantic.text.default,
1293
+ fontFamily: colors.fontFamily.body,
1294
+ fontSize: px(colors.fontSize.sm)
1295
+ },
1296
+ numberOfLines: 1,
1297
+ children: opt.label
1298
+ }
1299
+ )
1300
+ },
1301
+ `chip-${opt.value}`
1302
+ ))
1303
+ }
1304
+ );
1305
+ }, "MultiTriggerLabel");
1306
+ var MultiSelectionHeader = /* @__PURE__ */ __name(({ count, onClearAll }) => {
1307
+ const colors = useThemeColors();
1308
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1309
+ reactNative.View,
1310
+ {
1311
+ style: {
1312
+ flexDirection: "row",
1313
+ alignItems: "center",
1314
+ justifyContent: "space-between",
1315
+ paddingHorizontal: px(colors.spacing["3"]),
1316
+ paddingVertical: px(colors.spacing["2"]),
1317
+ borderBottomWidth: 1,
1318
+ borderBottomColor: colors.semantic.border.default
1319
+ },
1320
+ children: [
1321
+ /* @__PURE__ */ jsxRuntime.jsxs(
1322
+ reactNative.Text,
1323
+ {
1324
+ style: {
1325
+ color: colors.semantic.text.muted,
1326
+ fontFamily: colors.fontFamily.body,
1327
+ fontSize: px(colors.fontSize.sm),
1328
+ fontVariant: ["tabular-nums"]
1329
+ },
1330
+ children: [
1331
+ count,
1332
+ " selected"
1333
+ ]
1334
+ }
1335
+ ),
1336
+ /* @__PURE__ */ jsxRuntime.jsx(
1337
+ reactNative.Pressable,
1338
+ {
1339
+ role: "button",
1340
+ accessibilityRole: "button",
1341
+ "aria-label": "Clear all",
1342
+ accessibilityLabel: "Clear all",
1343
+ onPress: onClearAll,
1344
+ style: ({ pressed }) => ({
1345
+ paddingHorizontal: px(colors.spacing["2"]),
1346
+ paddingVertical: 2,
1347
+ borderRadius: px(colors.radius.sm),
1348
+ opacity: pressed ? 0.6 : 1
1349
+ }),
1350
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1351
+ reactNative.Text,
1352
+ {
1353
+ style: {
1354
+ color: colors.semantic.interactive.primary,
1355
+ fontFamily: colors.fontFamily.body,
1356
+ fontSize: px(colors.fontSize.sm),
1357
+ fontWeight: colors.fontWeight.medium
1358
+ },
1359
+ children: "Clear all"
1360
+ }
1361
+ )
1362
+ }
1363
+ )
1364
+ ]
1365
+ }
1366
+ );
1367
+ }, "MultiSelectionHeader");
1368
+ var Combobox = /* @__PURE__ */ __name((props) => {
1369
+ return /* @__PURE__ */ jsxRuntime.jsx(Select, { searchable: true, ...props });
1370
+ }, "Combobox");
1371
+
1372
+ exports.Combobox = Combobox;
1373
+ //# sourceMappingURL=index.cjs.map
1374
+ //# sourceMappingURL=index.cjs.map