@retray-dev/ui-kit 10.1.0 → 10.2.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 (112) hide show
  1. package/COMPONENTS.md +136 -5
  2. package/README.md +4 -4
  3. package/dist/Accordion.js +1 -1
  4. package/dist/Accordion.mjs +2 -2
  5. package/dist/AlertBanner.js +1 -1
  6. package/dist/AlertBanner.mjs +2 -2
  7. package/dist/AppHeader.js +1 -1
  8. package/dist/AppHeader.mjs +3 -3
  9. package/dist/Badge.js +1 -1
  10. package/dist/Badge.mjs +2 -2
  11. package/dist/Button.js +1 -1
  12. package/dist/Button.mjs +2 -2
  13. package/dist/CategoryStrip.js +1 -1
  14. package/dist/CategoryStrip.mjs +2 -2
  15. package/dist/Chip.js +1 -1
  16. package/dist/Chip.mjs +2 -2
  17. package/dist/ConfirmDialog.js +1 -1
  18. package/dist/ConfirmDialog.mjs +3 -3
  19. package/dist/CurrencyInput.js +1 -1
  20. package/dist/CurrencyInput.mjs +3 -3
  21. package/dist/DetailRow.d.mts +1 -1
  22. package/dist/DetailRow.d.ts +1 -1
  23. package/dist/DetailRow.js +1 -1
  24. package/dist/DetailRow.mjs +2 -2
  25. package/dist/EmptyState.js +1 -1
  26. package/dist/EmptyState.mjs +3 -3
  27. package/dist/ErrorBoundary.js +1 -1
  28. package/dist/ErrorBoundary.mjs +2 -2
  29. package/dist/IconButton.js +1 -1
  30. package/dist/IconButton.mjs +2 -2
  31. package/dist/IconPicker.d.mts +17 -0
  32. package/dist/IconPicker.d.ts +17 -0
  33. package/dist/IconPicker.js +997 -0
  34. package/dist/IconPicker.mjs +7 -0
  35. package/dist/ImageUpload.d.mts +3 -1
  36. package/dist/ImageUpload.d.ts +3 -1
  37. package/dist/ImageUpload.js +28 -10
  38. package/dist/ImageUpload.mjs +1 -1
  39. package/dist/ImageViewer.js +1 -1
  40. package/dist/ImageViewer.mjs +4 -4
  41. package/dist/Input.js +1 -1
  42. package/dist/Input.mjs +2 -2
  43. package/dist/LabelValue.js +1 -1
  44. package/dist/LabelValue.mjs +2 -2
  45. package/dist/ListItem.js +1 -1
  46. package/dist/ListItem.mjs +2 -2
  47. package/dist/MediaCard.js +1 -1
  48. package/dist/MediaCard.mjs +2 -2
  49. package/dist/MenuItem.js +1 -1
  50. package/dist/MenuItem.mjs +2 -2
  51. package/dist/NumberStepper.d.mts +19 -0
  52. package/dist/NumberStepper.d.ts +19 -0
  53. package/dist/NumberStepper.js +410 -0
  54. package/dist/NumberStepper.mjs +9 -0
  55. package/dist/PagerDots.js +1 -1
  56. package/dist/PagerDots.mjs +2 -2
  57. package/dist/PricingCard.js +1 -1
  58. package/dist/PricingCard.mjs +4 -4
  59. package/dist/SelectableGrid.js +1 -1
  60. package/dist/SelectableGrid.mjs +2 -2
  61. package/dist/SheetSelect.js +1 -1
  62. package/dist/SheetSelect.mjs +2 -2
  63. package/dist/TabBar.js +1 -1
  64. package/dist/TabBar.mjs +2 -2
  65. package/dist/Textarea.js +1 -1
  66. package/dist/Textarea.mjs +2 -2
  67. package/dist/Toggle.js +1 -1
  68. package/dist/Toggle.mjs +2 -2
  69. package/dist/chunk-53Z3NYGE.mjs +742 -0
  70. package/dist/{chunk-VQ57HWPL.mjs → chunk-6L4G6PBT.mjs} +1 -1
  71. package/dist/{chunk-6OAZJ577.mjs → chunk-6SECQ2ZF.mjs} +2 -2
  72. package/dist/{chunk-KIHCWCWL.mjs → chunk-7LWRKMF5.mjs} +1 -1
  73. package/dist/{chunk-4I7D47FH.mjs → chunk-AJRVDP2H.mjs} +3 -3
  74. package/dist/{chunk-6MKGPAR2.mjs → chunk-BEMIQXXU.mjs} +1 -1
  75. package/dist/chunk-BUMAMSTZ.mjs +126 -0
  76. package/dist/{chunk-UREA2GYY.mjs → chunk-DYT7BG5I.mjs} +1 -1
  77. package/dist/{chunk-WOEYDUJZ.mjs → chunk-ELXBDILQ.mjs} +2 -2
  78. package/dist/{chunk-A4MDAP7G.mjs → chunk-FCSSQK3L.mjs} +1 -1
  79. package/dist/{chunk-2TFTAWVJ.mjs → chunk-HTHGSXFG.mjs} +1 -1
  80. package/dist/{chunk-VGTDN7SW.mjs → chunk-IX3NYLYQ.mjs} +1 -1
  81. package/dist/{chunk-T7XZ7H7Y.mjs → chunk-KA7LTET3.mjs} +17 -3
  82. package/dist/{chunk-URI2WBIV.mjs → chunk-KOO4WITD.mjs} +1 -1
  83. package/dist/{chunk-JUXSWN54.mjs → chunk-NMU5FMQJ.mjs} +1 -1
  84. package/dist/{chunk-LXJIIOYQ.mjs → chunk-RYZC432S.mjs} +1 -1
  85. package/dist/{chunk-JB67UOB5.mjs → chunk-S2R7UVOE.mjs} +1 -1
  86. package/dist/{chunk-ZUR7AU5R.mjs → chunk-SXLKNTA4.mjs} +1 -1
  87. package/dist/{chunk-3U4SSNWP.mjs → chunk-T2KCAHOS.mjs} +1 -1
  88. package/dist/{chunk-ZJKGQMYH.mjs → chunk-TB6SD2FT.mjs} +1 -1
  89. package/dist/{chunk-AZJF2BLK.mjs → chunk-TBNZHU6C.mjs} +1 -1
  90. package/dist/{chunk-Y4GL2MHX.mjs → chunk-TZDGAP5N.mjs} +28 -10
  91. package/dist/{chunk-CZCQZHG6.mjs → chunk-U2XJFYED.mjs} +1 -1
  92. package/dist/{chunk-TERDKCLE.mjs → chunk-VF2ATYN3.mjs} +1 -1
  93. package/dist/{chunk-OHBNABL5.mjs → chunk-VKID2D2I.mjs} +1 -1
  94. package/dist/{chunk-KZL5VTYK.mjs → chunk-WYEUNUTP.mjs} +1 -1
  95. package/dist/{chunk-DJ7RN37L.mjs → chunk-YJ7I257J.mjs} +1 -1
  96. package/dist/{chunk-NA7PARID.mjs → chunk-Z4VHZ7B5.mjs} +1 -1
  97. package/dist/{chunk-MLF3EZFW.mjs → chunk-Z6SFHN6T.mjs} +1 -1
  98. package/dist/{chunk-4K625MVM.mjs → chunk-ZZ2R6KZ3.mjs} +1 -1
  99. package/dist/index.d.mts +4 -1
  100. package/dist/index.d.ts +4 -1
  101. package/dist/index.js +892 -12
  102. package/dist/index.mjs +33 -31
  103. package/package.json +1 -1
  104. package/src/components/DetailRow/DetailRow.tsx +1 -1
  105. package/src/components/IconPicker/IconPicker.tsx +383 -0
  106. package/src/components/IconPicker/index.ts +1 -0
  107. package/src/components/ImageUpload/ImageUpload.tsx +34 -12
  108. package/src/components/NumberStepper/NumberStepper.tsx +147 -0
  109. package/src/components/NumberStepper/index.ts +1 -0
  110. package/src/index.ts +3 -1
  111. package/src/utils/curatedIcons.ts +286 -0
  112. package/src/utils/icons.ts +20 -2
@@ -0,0 +1,997 @@
1
+ 'use strict';
2
+
3
+ var React3 = require('react');
4
+ var reactNative = require('react-native');
5
+ var reactNativeGestureHandler = require('react-native-gesture-handler');
6
+ var bottomSheet = require('@gorhom/bottom-sheet');
7
+ var reactNativeSafeAreaContext = require('react-native-safe-area-context');
8
+ var AntDesign = require('@expo/vector-icons/AntDesign');
9
+ var Entypo = require('@expo/vector-icons/Entypo');
10
+ var Feather = require('@expo/vector-icons/Feather');
11
+ var FontAwesome5 = require('@expo/vector-icons/FontAwesome5');
12
+ var MaterialIcons = require('@expo/vector-icons/MaterialIcons');
13
+ var Ionicons = require('@expo/vector-icons/Ionicons');
14
+ var reactNativeSizeMatters = require('react-native-size-matters');
15
+
16
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
17
+
18
+ var React3__default = /*#__PURE__*/_interopDefault(React3);
19
+ var AntDesign__default = /*#__PURE__*/_interopDefault(AntDesign);
20
+ var Entypo__default = /*#__PURE__*/_interopDefault(Entypo);
21
+ var Feather__default = /*#__PURE__*/_interopDefault(Feather);
22
+ var FontAwesome5__default = /*#__PURE__*/_interopDefault(FontAwesome5);
23
+ var MaterialIcons__default = /*#__PURE__*/_interopDefault(MaterialIcons);
24
+ var Ionicons__default = /*#__PURE__*/_interopDefault(Ionicons);
25
+
26
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
27
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
28
+ }) : x)(function(x) {
29
+ if (typeof require !== "undefined") return require.apply(this, arguments);
30
+ throw Error('Dynamic require of "' + x + '" is not supported');
31
+ });
32
+
33
+ // src/theme/colorUtils.ts
34
+ function hexToRgb(hex) {
35
+ const clean = hex.replace("#", "");
36
+ const full = clean.length === 3 ? clean.split("").map((c) => c + c).join("") : clean;
37
+ if (full.length !== 6) return null;
38
+ return {
39
+ r: parseInt(full.slice(0, 2), 16),
40
+ g: parseInt(full.slice(2, 4), 16),
41
+ b: parseInt(full.slice(4, 6), 16)
42
+ };
43
+ }
44
+ function componentToHex(c) {
45
+ return Math.round(Math.max(0, Math.min(255, c))).toString(16).padStart(2, "0");
46
+ }
47
+ function rgbToHex(r, g, b) {
48
+ return `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`;
49
+ }
50
+ function withAlphaOnWhite(hex, alpha) {
51
+ const rgb = hexToRgb(hex);
52
+ if (!rgb) return hex;
53
+ const r = rgb.r * alpha + 255 * (1 - alpha);
54
+ const g = rgb.g * alpha + 255 * (1 - alpha);
55
+ const b = rgb.b * alpha + 255 * (1 - alpha);
56
+ return rgbToHex(r, g, b);
57
+ }
58
+ function withAlphaOnDark(hex, alpha, bgHex = "#0f0f0f") {
59
+ const rgb = hexToRgb(hex);
60
+ const bg = hexToRgb(bgHex);
61
+ if (!rgb || !bg) return hex;
62
+ const r = rgb.r * alpha + bg.r * (1 - alpha);
63
+ const g = rgb.g * alpha + bg.g * (1 - alpha);
64
+ const b = rgb.b * alpha + bg.b * (1 - alpha);
65
+ return rgbToHex(r, g, b);
66
+ }
67
+ function mixWithBackground(fgHex, bgHex, opacity) {
68
+ const fg = hexToRgb(fgHex);
69
+ const bg = hexToRgb(bgHex);
70
+ if (!fg || !bg) return fgHex;
71
+ const r = fg.r * opacity + bg.r * (1 - opacity);
72
+ const g = fg.g * opacity + bg.g * (1 - opacity);
73
+ const b = fg.b * opacity + bg.b * (1 - opacity);
74
+ return rgbToHex(r, g, b);
75
+ }
76
+ function lighten(hex, amount) {
77
+ return withAlphaOnWhite(hex, 1 - amount);
78
+ }
79
+ function darken(hex, amount) {
80
+ const rgb = hexToRgb(hex);
81
+ if (!rgb) return hex;
82
+ return rgbToHex(rgb.r * (1 - amount), rgb.g * (1 - amount), rgb.b * (1 - amount));
83
+ }
84
+
85
+ // src/theme/colors.ts
86
+ var defaultLight = {
87
+ background: "#ffffff",
88
+ foreground: "#1a1a1a",
89
+ card: "#ffffff",
90
+ primary: "#1a1a1a",
91
+ primaryForeground: "#ffffff",
92
+ // AUDIT FIX: brand accent — was undefined; falls back to primary when omitted
93
+ accent: "#d4561d",
94
+ accentForeground: "#ffffff",
95
+ border: "#dddddd",
96
+ // AUDIT FIX: was #e53935 (4.22:1 on white — fails AA); #c72828 = 5.59:1 ✓
97
+ destructive: "#c72828",
98
+ destructiveForeground: "#ffffff",
99
+ success: "#1a7a45",
100
+ successForeground: "#ffffff",
101
+ // AUDIT FIX: was #e67e00 (2.86:1 — severe fail); #9a5200 = 5.86:1 ✓ AAA-near
102
+ warning: "#9a5200",
103
+ warningForeground: "#ffffff"
104
+ };
105
+ function deriveColors(t, scheme) {
106
+ const dark = scheme === "dark";
107
+ const bg = t.background;
108
+ const foregroundSubtle = mixWithBackground(t.foreground, bg, 0.7);
109
+ const foregroundMuted = mixWithBackground(t.foreground, bg, 0.62);
110
+ const surface = dark ? lighten(bg, -0.06) : darken(bg, 0.04);
111
+ const surfaceStrong = dark ? lighten(bg, -0.12) : darken(bg, 0.08);
112
+ const destructiveTint = dark ? withAlphaOnDark(t.destructive, 0.15, bg) : withAlphaOnWhite(t.destructive, 0.08);
113
+ const destructiveBorder = dark ? withAlphaOnDark(t.destructive, 0.45, bg) : withAlphaOnWhite(t.destructive, 0.3);
114
+ const successTint = dark ? withAlphaOnDark(t.success, 0.15, bg) : withAlphaOnWhite(t.success, 0.08);
115
+ const successBorder = dark ? withAlphaOnDark(t.success, 0.45, bg) : withAlphaOnWhite(t.success, 0.3);
116
+ const warningTint = dark ? withAlphaOnDark(t.warning, 0.15, bg) : withAlphaOnWhite(t.warning, 0.08);
117
+ const warningBorder = dark ? withAlphaOnDark(t.warning, 0.45, bg) : withAlphaOnWhite(t.warning, 0.3);
118
+ return {
119
+ ...t,
120
+ foregroundSubtle,
121
+ foregroundMuted,
122
+ surface,
123
+ surfaceStrong,
124
+ destructiveTint,
125
+ destructiveBorder,
126
+ successTint,
127
+ successBorder,
128
+ warningTint,
129
+ warningBorder,
130
+ overlay: t.overlay ?? "rgba(0,0,0,0.45)",
131
+ accentResolved: t.accent ?? t.primary,
132
+ accentForegroundResolved: t.accentForeground ?? t.primaryForeground,
133
+ ring: t.accent ?? t.primary,
134
+ input: t.border,
135
+ separator: dark ? lighten(t.border, 0.22) : darken(t.border, 0.16)
136
+ };
137
+ }
138
+
139
+ // src/theme/ThemeProvider.tsx
140
+ var ThemeContext = React3.createContext({
141
+ colors: deriveColors(defaultLight, "light"),
142
+ colorScheme: "light"
143
+ });
144
+ function useTheme() {
145
+ const context = React3.useContext(ThemeContext);
146
+ if (!context) {
147
+ throw new Error("useTheme must be used within a ThemeProvider");
148
+ }
149
+ return context;
150
+ }
151
+ var glyphMapOf = (mod) => mod.glyphMap ?? {};
152
+ var ALL_FAMILIES = [
153
+ { name: "Ionicons", component: Ionicons__default.default, getGlyphMap: () => glyphMapOf(Ionicons__default.default) },
154
+ { name: "MaterialIcons", component: MaterialIcons__default.default, getGlyphMap: () => glyphMapOf(MaterialIcons__default.default) },
155
+ { name: "FontAwesome5", component: FontAwesome5__default.default, getGlyphMap: () => glyphMapOf(FontAwesome5__default.default) },
156
+ { name: "Entypo", component: Entypo__default.default, getGlyphMap: () => glyphMapOf(Entypo__default.default) },
157
+ { name: "AntDesign", component: AntDesign__default.default, getGlyphMap: () => glyphMapOf(AntDesign__default.default) },
158
+ { name: "Feather", component: Feather__default.default, getGlyphMap: () => glyphMapOf(Feather__default.default) }
159
+ ];
160
+ var activeFamilies = ALL_FAMILIES;
161
+ var resolvedCache = null;
162
+ function buildCache(families) {
163
+ const cache = /* @__PURE__ */ new Map();
164
+ for (const family of activeFamilies) {
165
+ const glyphMap = family.getGlyphMap();
166
+ for (const iconName of Object.keys(glyphMap)) {
167
+ cache.set(iconName, family);
168
+ }
169
+ }
170
+ return cache;
171
+ }
172
+ function resolveFamily(name) {
173
+ if (!resolvedCache) {
174
+ resolvedCache = buildCache();
175
+ }
176
+ return resolvedCache.get(name) ?? null;
177
+ }
178
+ function Icon({ name, size, color, family }) {
179
+ let resolved = null;
180
+ if (family) {
181
+ resolved = ALL_FAMILIES.find((f) => f.name === family) ?? null;
182
+ } else {
183
+ resolved = resolveFamily(name);
184
+ }
185
+ if (!resolved) return null;
186
+ const Component = resolved.component;
187
+ return React3__default.default.createElement(Component, { name, size, color });
188
+ }
189
+ function renderIcon(name, size, color) {
190
+ return React3__default.default.createElement(Icon, { name, size, color });
191
+ }
192
+
193
+ // src/utils/curatedIcons.ts
194
+ var CURATED_ICONS = [
195
+ {
196
+ name: "food",
197
+ label: "Food",
198
+ labelEs: "Comida",
199
+ categoryIcon: "coffee",
200
+ icons: [
201
+ // Bebidas
202
+ "coffee",
203
+ "wine-glass",
204
+ "beer",
205
+ "cocktail",
206
+ "mug-hot",
207
+ "glass-cheers",
208
+ "wine",
209
+ // Comidas
210
+ "restaurant",
211
+ "hamburger",
212
+ "pizza-slice",
213
+ "ice-cream",
214
+ "cake",
215
+ "egg",
216
+ "fish",
217
+ "bread-slice",
218
+ "cookie",
219
+ "cheese",
220
+ "carrot",
221
+ "hotdog",
222
+ // Cocina / utilidades
223
+ "utensils",
224
+ // Delivery / pedidos
225
+ "shopping-bag",
226
+ "clock",
227
+ "star",
228
+ "heart",
229
+ "map-pin",
230
+ "phone"
231
+ ]
232
+ },
233
+ {
234
+ name: "sports",
235
+ label: "Sports",
236
+ labelEs: "Deportes",
237
+ categoryIcon: "activity",
238
+ icons: [
239
+ // Deportes específicos
240
+ "futbol",
241
+ "dumbbell",
242
+ "running",
243
+ "bicycle",
244
+ "heartbeat",
245
+ "fitness-center",
246
+ // Competencia / logros
247
+ "target",
248
+ "award",
249
+ "flag",
250
+ "star",
251
+ "zap",
252
+ // Bienestar
253
+ "heart",
254
+ "clock",
255
+ "activity",
256
+ "sun",
257
+ "user",
258
+ "users"
259
+ ]
260
+ },
261
+ {
262
+ name: "business",
263
+ label: "Business",
264
+ labelEs: "Negocios",
265
+ categoryIcon: "briefcase",
266
+ icons: [
267
+ "shopping-cart",
268
+ "shopping-bag",
269
+ "credit-card",
270
+ "dollar-sign",
271
+ "percent",
272
+ "briefcase",
273
+ "truck",
274
+ "package",
275
+ "gift",
276
+ "bar-chart",
277
+ "bar-chart-2",
278
+ "pie-chart",
279
+ "trending-up",
280
+ "trending-down",
281
+ "activity",
282
+ "tag",
283
+ "bookmark",
284
+ "pocket"
285
+ ]
286
+ },
287
+ {
288
+ name: "objects",
289
+ label: "Objects",
290
+ labelEs: "Objetos",
291
+ categoryIcon: "folder",
292
+ icons: [
293
+ "file",
294
+ "file-text",
295
+ "file-plus",
296
+ "file-minus",
297
+ "folder",
298
+ "folder-plus",
299
+ "folder-minus",
300
+ "lock",
301
+ "unlock",
302
+ "key",
303
+ "shield",
304
+ "shield-off",
305
+ "settings",
306
+ "sliders",
307
+ "toggle-left",
308
+ "toggle-right",
309
+ "tool",
310
+ "printer",
311
+ "database",
312
+ "server",
313
+ "hard-drive",
314
+ "cpu",
315
+ "paperclip",
316
+ "aperture",
317
+ "box",
318
+ "radio"
319
+ ]
320
+ },
321
+ {
322
+ name: "status",
323
+ label: "Status",
324
+ labelEs: "Estado",
325
+ categoryIcon: "alert-circle",
326
+ icons: [
327
+ "alert-circle",
328
+ "alert-triangle",
329
+ "alert-octagon",
330
+ "info",
331
+ "help-circle",
332
+ "bell",
333
+ "bell-off",
334
+ "eye",
335
+ "eye-off",
336
+ "flag",
337
+ "zap",
338
+ "zap-off",
339
+ "loader",
340
+ "clock",
341
+ "watch"
342
+ ]
343
+ },
344
+ {
345
+ name: "actions",
346
+ label: "Actions",
347
+ labelEs: "Acciones",
348
+ categoryIcon: "edit-3",
349
+ icons: [
350
+ "plus",
351
+ "plus-circle",
352
+ "plus-square",
353
+ "minus",
354
+ "minus-circle",
355
+ "minus-square",
356
+ "x",
357
+ "x-circle",
358
+ "x-square",
359
+ "x-octagon",
360
+ "check",
361
+ "check-circle",
362
+ "check-square",
363
+ "edit",
364
+ "edit-2",
365
+ "edit-3",
366
+ "trash",
367
+ "trash-2",
368
+ "copy",
369
+ "clipboard",
370
+ "scissors",
371
+ "download",
372
+ "download-cloud",
373
+ "upload",
374
+ "upload-cloud",
375
+ "share",
376
+ "share-2",
377
+ "link",
378
+ "link-2",
379
+ "search",
380
+ "zoom-in",
381
+ "zoom-out",
382
+ "save",
383
+ "archive",
384
+ "log-in",
385
+ "log-out",
386
+ "power",
387
+ "refresh-cw",
388
+ "rotate-cw",
389
+ "slash"
390
+ ]
391
+ },
392
+ {
393
+ name: "communication",
394
+ label: "Communication",
395
+ labelEs: "Comunicaci\xF3n",
396
+ categoryIcon: "message-circle",
397
+ icons: [
398
+ "mail",
399
+ "message-circle",
400
+ "message-square",
401
+ "send",
402
+ "phone",
403
+ "phone-call",
404
+ "phone-incoming",
405
+ "phone-outgoing",
406
+ "phone-missed",
407
+ "phone-off",
408
+ "phone-forwarded",
409
+ "at-sign",
410
+ "inbox",
411
+ "user",
412
+ "user-plus",
413
+ "user-minus",
414
+ "user-check",
415
+ "user-x",
416
+ "users",
417
+ "smile",
418
+ "frown",
419
+ "meh",
420
+ "heart",
421
+ "thumbs-up",
422
+ "thumbs-down",
423
+ "star",
424
+ "award"
425
+ ]
426
+ },
427
+ {
428
+ name: "navigation",
429
+ label: "Navigation",
430
+ labelEs: "Navegaci\xF3n",
431
+ categoryIcon: "compass",
432
+ icons: [
433
+ "arrow-up",
434
+ "arrow-down",
435
+ "arrow-left",
436
+ "arrow-right",
437
+ "arrow-up-left",
438
+ "arrow-up-right",
439
+ "arrow-down-left",
440
+ "arrow-down-right",
441
+ "chevron-up",
442
+ "chevron-down",
443
+ "chevron-left",
444
+ "chevron-right",
445
+ "chevrons-up",
446
+ "chevrons-down",
447
+ "chevrons-left",
448
+ "chevrons-right",
449
+ "corner-up-left",
450
+ "corner-up-right",
451
+ "corner-down-left",
452
+ "corner-down-right",
453
+ "corner-left-up",
454
+ "corner-left-down",
455
+ "corner-right-up",
456
+ "corner-right-down",
457
+ "refresh-cw",
458
+ "refresh-ccw",
459
+ "rotate-cw",
460
+ "rotate-ccw",
461
+ "navigation",
462
+ "navigation-2",
463
+ "compass",
464
+ "map",
465
+ "map-pin",
466
+ "target",
467
+ "crosshair",
468
+ "home",
469
+ "maximize",
470
+ "maximize-2",
471
+ "minimize",
472
+ "minimize-2",
473
+ "external-link",
474
+ "move",
475
+ "anchor"
476
+ ]
477
+ },
478
+ {
479
+ name: "media",
480
+ label: "Media",
481
+ labelEs: "Medios",
482
+ categoryIcon: "image",
483
+ icons: [
484
+ "image",
485
+ "film",
486
+ "video",
487
+ "video-off",
488
+ "play",
489
+ "play-circle",
490
+ "pause",
491
+ "pause-circle",
492
+ "square",
493
+ "stop-circle",
494
+ "music",
495
+ "headphones",
496
+ "speaker",
497
+ "camera",
498
+ "camera-off",
499
+ "mic",
500
+ "mic-off",
501
+ "volume",
502
+ "volume-1",
503
+ "volume-2",
504
+ "volume-x",
505
+ "fast-forward",
506
+ "rewind",
507
+ "skip-forward",
508
+ "skip-back",
509
+ "repeat",
510
+ "shuffle",
511
+ "disc"
512
+ ]
513
+ },
514
+ {
515
+ name: "layout",
516
+ label: "Layout",
517
+ labelEs: "Dise\xF1o",
518
+ categoryIcon: "grid",
519
+ icons: [
520
+ "menu",
521
+ "more-horizontal",
522
+ "more-vertical",
523
+ "grid",
524
+ "columns",
525
+ "sidebar",
526
+ "layout",
527
+ "list",
528
+ "align-left",
529
+ "align-center",
530
+ "align-right",
531
+ "align-justify",
532
+ "bold",
533
+ "italic",
534
+ "underline",
535
+ "type",
536
+ "filter",
537
+ "crop",
538
+ "layers",
539
+ "hash",
540
+ "table",
541
+ "trello",
542
+ "circle",
543
+ "square",
544
+ "triangle",
545
+ "hexagon",
546
+ "octagon",
547
+ "feather",
548
+ "pen-tool"
549
+ ]
550
+ },
551
+ {
552
+ name: "nature",
553
+ label: "Nature",
554
+ labelEs: "Naturaleza",
555
+ categoryIcon: "sun",
556
+ icons: [
557
+ "sun",
558
+ "sunrise",
559
+ "sunset",
560
+ "moon",
561
+ "cloud",
562
+ "cloud-drizzle",
563
+ "cloud-lightning",
564
+ "cloud-off",
565
+ "cloud-rain",
566
+ "cloud-snow",
567
+ "wind",
568
+ "umbrella",
569
+ "thermometer",
570
+ "droplet",
571
+ "life-buoy"
572
+ ]
573
+ },
574
+ {
575
+ name: "brands",
576
+ label: "Brands",
577
+ labelEs: "Marcas",
578
+ categoryIcon: "globe",
579
+ icons: [
580
+ "github",
581
+ "gitlab",
582
+ "twitter",
583
+ "facebook",
584
+ "instagram",
585
+ "linkedin",
586
+ "youtube",
587
+ "dribbble",
588
+ "twitch",
589
+ "slack",
590
+ "figma",
591
+ "framer",
592
+ "chrome",
593
+ "codepen",
594
+ "codesandbox",
595
+ "globe",
596
+ "rss",
597
+ "airplay",
598
+ "cast",
599
+ "bluetooth",
600
+ "wifi",
601
+ "wifi-off",
602
+ "battery",
603
+ "battery-charging",
604
+ "monitor",
605
+ "tablet",
606
+ "smartphone",
607
+ "tv"
608
+ ]
609
+ }
610
+ ];
611
+ var ALL_CURATED_ICONS = [
612
+ ...new Set(CURATED_ICONS.flatMap((c) => c.icons))
613
+ ];
614
+ var _haptics = null;
615
+ var _hapticsLoaded = false;
616
+ async function getHaptics() {
617
+ if (reactNative.Platform.OS === "web") return null;
618
+ if (!_hapticsLoaded) {
619
+ _hapticsLoaded = true;
620
+ try {
621
+ _haptics = await import('expo-haptics');
622
+ } catch {
623
+ _haptics = null;
624
+ }
625
+ }
626
+ return _haptics;
627
+ }
628
+ var _pulsar = null;
629
+ var _pulsarChecked = false;
630
+ var _pulsarAvailable = false;
631
+ function isPulsarNativeRegistered() {
632
+ try {
633
+ const g = globalThis;
634
+ if (typeof g.__turboModuleProxy === "function") {
635
+ return g.__turboModuleProxy("RNPulsar") != null;
636
+ }
637
+ return reactNative.NativeModules?.RNPulsar != null;
638
+ } catch {
639
+ return false;
640
+ }
641
+ }
642
+ function getPulsar() {
643
+ if (reactNative.Platform.OS === "web") return null;
644
+ if (!_pulsarChecked) {
645
+ _pulsarChecked = true;
646
+ try {
647
+ if (isPulsarNativeRegistered()) {
648
+ _pulsar = __require("react-native-pulsar");
649
+ _pulsarAvailable = true;
650
+ }
651
+ } catch {
652
+ _pulsar = null;
653
+ _pulsarAvailable = false;
654
+ }
655
+ }
656
+ return _pulsarAvailable ? _pulsar : null;
657
+ }
658
+ function selectionAsync() {
659
+ if (reactNative.Platform.OS === "web") return;
660
+ getHaptics().then((h) => {
661
+ if (h) {
662
+ h.selectionAsync();
663
+ } else {
664
+ getPulsar()?.Presets.System.selection();
665
+ }
666
+ });
667
+ }
668
+ function impactMedium() {
669
+ if (reactNative.Platform.OS === "web") return;
670
+ getHaptics().then((h) => {
671
+ if (h) {
672
+ h.impactAsync(h.ImpactFeedbackStyle.Medium);
673
+ } else {
674
+ getPulsar()?.Presets.System.impactMedium();
675
+ }
676
+ });
677
+ }
678
+ var isWeb = reactNative.Platform.OS === "web";
679
+ var s = isWeb ? (n) => n : reactNativeSizeMatters.scale;
680
+ var vs = isWeb ? (n) => n : reactNativeSizeMatters.verticalScale;
681
+ var ms = isWeb ? (n, _factor) => n : reactNativeSizeMatters.moderateScale;
682
+
683
+ // src/tokens.ts
684
+ var RADIUS = {
685
+ md: 14,
686
+ full: 9999
687
+ };
688
+
689
+ // src/components/IconPicker/IconPicker.tsx
690
+ var NUM_COLUMNS = 6;
691
+ var GAP = 6;
692
+ var TRIGGER_SIZE = s(56);
693
+ var SCREEN_HEIGHT = reactNative.Dimensions.get("window").height;
694
+ function IconCell({ name, selected, size, onPress }) {
695
+ const { colors } = useTheme();
696
+ const handlePress = () => {
697
+ selectionAsync();
698
+ onPress();
699
+ };
700
+ const iconColor = selected ? colors.primaryForeground : colors.foreground;
701
+ const bg = selected ? colors.primary : "transparent";
702
+ return /* @__PURE__ */ React3__default.default.createElement(
703
+ reactNative.TouchableOpacity,
704
+ {
705
+ onPress: handlePress,
706
+ activeOpacity: 0.6,
707
+ touchSoundDisabled: true,
708
+ accessibilityRole: "button",
709
+ accessibilityState: { selected },
710
+ accessibilityLabel: name,
711
+ style: [styles.cell, { width: size, height: size, backgroundColor: bg }]
712
+ },
713
+ renderIcon(name, ms(20), iconColor)
714
+ );
715
+ }
716
+ var IconCellMemo = React3__default.default.memo(IconCell);
717
+ function IconPicker({
718
+ value,
719
+ onChange,
720
+ label,
721
+ error,
722
+ hint,
723
+ disabled = false,
724
+ numColumns = NUM_COLUMNS,
725
+ gap = GAP,
726
+ style
727
+ }) {
728
+ const { colors } = useTheme();
729
+ const insets = reactNativeSafeAreaContext.useSafeAreaInsets();
730
+ const sheetRef = React3.useRef(null);
731
+ const catScrollRef = React3.useRef(null);
732
+ const [open, setOpen] = React3.useState(false);
733
+ const [activeCategory, setActiveCategory] = React3.useState(null);
734
+ const [containerWidth, setContainerWidth] = React3.useState(() => reactNative.Dimensions.get("window").width - s(16) * 2);
735
+ const sheetName = React3.useId();
736
+ const activeIcons = React3.useMemo(() => {
737
+ if (activeCategory) {
738
+ return CURATED_ICONS.find((c) => c.name === activeCategory)?.icons ?? ALL_CURATED_ICONS;
739
+ }
740
+ return ALL_CURATED_ICONS;
741
+ }, [activeCategory]);
742
+ const gapPx = s(gap);
743
+ const cellSize = containerWidth > 0 ? Math.floor((containerWidth - gapPx * (numColumns - 1)) / numColumns) : 0;
744
+ const rows = React3.useMemo(() => {
745
+ const result = [];
746
+ for (let i = 0; i < activeIcons.length; i += numColumns) {
747
+ result.push(activeIcons.slice(i, i + numColumns));
748
+ }
749
+ return result;
750
+ }, [activeIcons, numColumns]);
751
+ React3.useEffect(() => {
752
+ if (open) {
753
+ impactMedium();
754
+ sheetRef.current?.present();
755
+ } else {
756
+ sheetRef.current?.dismiss();
757
+ }
758
+ }, [open]);
759
+ const handleSelect = React3.useCallback(
760
+ (iconName) => {
761
+ onChange(iconName);
762
+ setOpen(false);
763
+ setActiveCategory(null);
764
+ },
765
+ [onChange]
766
+ );
767
+ const handleOpen = React3.useCallback(() => {
768
+ if (disabled) return;
769
+ setActiveCategory(null);
770
+ setOpen(true);
771
+ }, [disabled]);
772
+ const handleClose = React3.useCallback(() => {
773
+ setOpen(false);
774
+ setActiveCategory(null);
775
+ }, []);
776
+ const renderBackdrop = React3.useCallback(
777
+ (props) => /* @__PURE__ */ React3__default.default.createElement(bottomSheet.BottomSheetBackdrop, { ...props, disappearsOnIndex: -1, appearsOnIndex: 0, pressBehavior: "close" }),
778
+ []
779
+ );
780
+ const selectedIcon = value ? renderIcon(value, ms(28), colors.foreground) : null;
781
+ return /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: [styles.triggerContainer, style] }, label ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.triggerLabel, { color: colors.foreground }], allowFontScaling: true }, label) : null, /* @__PURE__ */ React3__default.default.createElement(
782
+ reactNative.TouchableOpacity,
783
+ {
784
+ onPress: handleOpen,
785
+ disabled,
786
+ activeOpacity: 0.7,
787
+ touchSoundDisabled: true,
788
+ accessibilityRole: "button",
789
+ accessibilityLabel: label ?? "Seleccionar icono",
790
+ accessibilityState: { disabled },
791
+ style: [
792
+ styles.trigger,
793
+ {
794
+ backgroundColor: disabled ? colors.surface : colors.background,
795
+ width: TRIGGER_SIZE,
796
+ height: TRIGGER_SIZE,
797
+ borderColor: error ? colors.destructive : value ? colors.primary : colors.border
798
+ },
799
+ disabled && styles.triggerDisabled
800
+ ]
801
+ },
802
+ selectedIcon ?? renderIcon("plus", ms(24), colors.foregroundMuted)
803
+ ), error ? /* @__PURE__ */ React3__default.default.createElement(
804
+ reactNative.Text,
805
+ {
806
+ style: [styles.helperText, { color: colors.destructive }],
807
+ allowFontScaling: true,
808
+ accessibilityLiveRegion: "polite"
809
+ },
810
+ error
811
+ ) : null, !error && hint ? /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.helperText, { color: colors.foregroundMuted }], allowFontScaling: true }, hint) : null, /* @__PURE__ */ React3__default.default.createElement(
812
+ bottomSheet.BottomSheetModal,
813
+ {
814
+ ref: sheetRef,
815
+ name: sheetName,
816
+ onDismiss: handleClose,
817
+ enableDynamicSizing: true,
818
+ maxDynamicContentSize: SCREEN_HEIGHT * 0.7,
819
+ backdropComponent: renderBackdrop,
820
+ backgroundStyle: [styles.sheetBackground, { backgroundColor: colors.card }],
821
+ handleIndicatorStyle: [styles.handle, { backgroundColor: colors.border }],
822
+ enablePanDownToClose: true,
823
+ topInset: insets.top,
824
+ android_keyboardInputMode: "adjustPan"
825
+ },
826
+ /* @__PURE__ */ React3__default.default.createElement(
827
+ bottomSheet.BottomSheetScrollView,
828
+ {
829
+ contentContainerStyle: styles.sheetContent,
830
+ showsVerticalScrollIndicator: true
831
+ },
832
+ /* @__PURE__ */ React3__default.default.createElement(reactNative.Text, { style: [styles.sectionLabel, { color: colors.foregroundSubtle }], allowFontScaling: true }, "Categor\xEDas"),
833
+ /* @__PURE__ */ React3__default.default.createElement(
834
+ reactNativeGestureHandler.ScrollView,
835
+ {
836
+ ref: catScrollRef,
837
+ horizontal: true,
838
+ showsHorizontalScrollIndicator: false,
839
+ contentContainerStyle: styles.categoryStrip,
840
+ style: styles.categoryScroll
841
+ },
842
+ /* @__PURE__ */ React3__default.default.createElement(
843
+ reactNative.TouchableOpacity,
844
+ {
845
+ onPress: () => setActiveCategory(null),
846
+ activeOpacity: 0.7,
847
+ touchSoundDisabled: true,
848
+ accessibilityRole: "button",
849
+ accessibilityLabel: "Todos",
850
+ accessibilityState: { selected: activeCategory === null },
851
+ style: [
852
+ styles.categoryChip,
853
+ {
854
+ backgroundColor: activeCategory === null ? colors.primary : colors.surface,
855
+ borderColor: activeCategory === null ? colors.primary : colors.border
856
+ }
857
+ ]
858
+ },
859
+ /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.categoryChipInner }, renderIcon("grid", ms(14), activeCategory === null ? colors.primaryForeground : colors.foregroundSubtle), /* @__PURE__ */ React3__default.default.createElement(
860
+ reactNative.Text,
861
+ {
862
+ style: [
863
+ styles.categoryChipText,
864
+ { color: activeCategory === null ? colors.primaryForeground : colors.foreground }
865
+ ],
866
+ allowFontScaling: true,
867
+ numberOfLines: 1
868
+ },
869
+ "Todos"
870
+ ))
871
+ ),
872
+ CURATED_ICONS.map((cat) => /* @__PURE__ */ React3__default.default.createElement(
873
+ reactNative.TouchableOpacity,
874
+ {
875
+ key: cat.name,
876
+ onPress: () => setActiveCategory(cat.name),
877
+ activeOpacity: 0.7,
878
+ touchSoundDisabled: true,
879
+ accessibilityRole: "button",
880
+ accessibilityLabel: cat.labelEs,
881
+ accessibilityState: { selected: activeCategory === cat.name },
882
+ style: [
883
+ styles.categoryChip,
884
+ {
885
+ backgroundColor: activeCategory === cat.name ? colors.primary : colors.surface,
886
+ borderColor: activeCategory === cat.name ? colors.primary : colors.border
887
+ }
888
+ ]
889
+ },
890
+ /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.categoryChipInner }, renderIcon(cat.categoryIcon, ms(14), activeCategory === cat.name ? colors.primaryForeground : colors.foregroundSubtle), /* @__PURE__ */ React3__default.default.createElement(
891
+ reactNative.Text,
892
+ {
893
+ style: [
894
+ styles.categoryChipText,
895
+ { color: activeCategory === cat.name ? colors.primaryForeground : colors.foreground }
896
+ ],
897
+ allowFontScaling: true,
898
+ numberOfLines: 1
899
+ },
900
+ cat.labelEs
901
+ ))
902
+ ))
903
+ ),
904
+ /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: [styles.separator, { backgroundColor: colors.border }] }),
905
+ /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { style: styles.gridContainer, onLayout: (e) => setContainerWidth(e.nativeEvent.layout.width) }, cellSize > 0 ? rows.map((row, i) => /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { key: row[0] ?? `row-${i}`, style: [styles.row, { marginBottom: gapPx }] }, row.map((name) => /* @__PURE__ */ React3__default.default.createElement(
906
+ IconCellMemo,
907
+ {
908
+ key: name,
909
+ name,
910
+ selected: value === name,
911
+ size: cellSize,
912
+ onPress: () => handleSelect(name)
913
+ }
914
+ )), Array.from({ length: numColumns - row.length }).map((_, j) => /* @__PURE__ */ React3__default.default.createElement(reactNative.View, { key: `spacer-${j}`, style: { width: cellSize, height: cellSize } })))) : null)
915
+ )
916
+ ));
917
+ }
918
+ var styles = reactNative.StyleSheet.create({
919
+ triggerContainer: {
920
+ gap: vs(8)
921
+ },
922
+ triggerLabel: {
923
+ fontFamily: "Sohne-Medium",
924
+ fontSize: ms(14)
925
+ },
926
+ trigger: {
927
+ borderRadius: RADIUS.md,
928
+ borderWidth: 1,
929
+ alignItems: "center",
930
+ justifyContent: "center"
931
+ },
932
+ triggerDisabled: {
933
+ opacity: 0.6
934
+ },
935
+ helperText: {
936
+ fontFamily: "Sohne-Regular",
937
+ fontSize: ms(13)
938
+ },
939
+ sheetBackground: {
940
+ borderTopLeftRadius: ms(16),
941
+ borderTopRightRadius: ms(16)
942
+ },
943
+ handle: {
944
+ width: s(36),
945
+ height: vs(4),
946
+ borderRadius: ms(2)
947
+ },
948
+ sheetContent: {
949
+ paddingHorizontal: s(16),
950
+ paddingBottom: vs(24)
951
+ },
952
+ sectionLabel: {
953
+ fontFamily: "Sohne-Medium",
954
+ fontSize: ms(12),
955
+ marginBottom: vs(8),
956
+ textTransform: "uppercase",
957
+ letterSpacing: 0.5
958
+ },
959
+ categoryScroll: {
960
+ flexGrow: 0,
961
+ flexShrink: 0
962
+ },
963
+ categoryStrip: {
964
+ gap: s(8)
965
+ },
966
+ categoryChip: {
967
+ borderRadius: RADIUS.full,
968
+ borderWidth: 1,
969
+ paddingVertical: vs(6),
970
+ paddingHorizontal: s(12)
971
+ },
972
+ categoryChipInner: {
973
+ flexDirection: "row",
974
+ alignItems: "center",
975
+ gap: s(6)
976
+ },
977
+ categoryChipText: {
978
+ fontFamily: "Sohne-Medium",
979
+ fontSize: ms(12)
980
+ },
981
+ separator: {
982
+ height: reactNative.StyleSheet.hairlineWidth,
983
+ marginVertical: vs(12)
984
+ },
985
+ gridContainer: {},
986
+ row: {
987
+ flexDirection: "row",
988
+ gap: GAP
989
+ },
990
+ cell: {
991
+ borderRadius: RADIUS.md,
992
+ alignItems: "center",
993
+ justifyContent: "center"
994
+ }
995
+ });
996
+
997
+ exports.IconPicker = IconPicker;