@xaui/native 0.9.1-alpha.23 → 0.9.1-alpha.25

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 (59) hide show
  1. package/dist/{chunk-E3LXUXE7.js → chunk-2OY76YNB.js} +47 -13
  2. package/dist/{chunk-KM2TI5IC.js → chunk-4HELPMAK.js} +76 -82
  3. package/dist/{chunk-AHL33YAO.js → chunk-4J26FA6O.js} +9 -7
  4. package/dist/{chunk-BNWS26PX.cjs → chunk-6FBGCF5T.cjs} +9 -7
  5. package/dist/{chunk-ZQ3JSWRO.js → chunk-A4RGJBP2.js} +4 -2
  6. package/dist/{chunk-I6PE5UUH.cjs → chunk-AV5LMFS3.cjs} +13 -11
  7. package/dist/{chunk-OGC4RKE3.js → chunk-AXSJPWSJ.js} +5 -5
  8. package/dist/chunk-BULNTP5N.cjs +620 -0
  9. package/dist/chunk-EGLLDKN6.js +9 -0
  10. package/dist/chunk-EJQCQPET.cjs +9 -0
  11. package/dist/{chunk-VDRRD6GM.cjs → chunk-EWBBDVTM.cjs} +22 -21
  12. package/dist/chunk-GSEK6OCY.cjs +72 -0
  13. package/dist/chunk-I6UCYAO2.js +731 -0
  14. package/dist/{chunk-BH5DSJVX.cjs → chunk-IG4Q3WQO.cjs} +61 -68
  15. package/dist/{chunk-6WW4CSPY.cjs → chunk-J2JJLKLG.cjs} +6 -4
  16. package/dist/{chunk-4MHJOWM4.cjs → chunk-J4JFIC4W.cjs} +7 -7
  17. package/dist/{chunk-FNQF4KQV.js → chunk-MRYLLKML.js} +18 -17
  18. package/dist/{chunk-GBPWTFTU.cjs → chunk-OHEHPQLC.cjs} +10 -1
  19. package/dist/{chunk-GG2WWCBK.js → chunk-TZG3DERP.js} +10 -1
  20. package/dist/{chunk-TIP3T7JJ.cjs → chunk-YEW5LPWL.cjs} +47 -13
  21. package/dist/chunk-ZDCGPK5Z.js +72 -0
  22. package/dist/{chunk-FTCTTBLG.js → chunk-ZTA47PO5.js} +7 -5
  23. package/dist/components/alert/index.cjs +7 -6
  24. package/dist/components/alert/index.js +6 -5
  25. package/dist/components/button/index.cjs +6 -5
  26. package/dist/components/button/index.js +5 -4
  27. package/dist/components/card/index.cjs +5 -4
  28. package/dist/components/card/index.js +4 -3
  29. package/dist/components/chip/index.cjs +7 -6
  30. package/dist/components/chip/index.js +6 -5
  31. package/dist/components/input/index.cjs +13 -3
  32. package/dist/components/input/index.d.cts +109 -117
  33. package/dist/components/input/index.d.ts +109 -117
  34. package/dist/components/input/index.js +12 -2
  35. package/dist/components/input-otp/index.cjs +27 -0
  36. package/dist/components/input-otp/index.d.cts +325 -0
  37. package/dist/components/input-otp/index.d.ts +325 -0
  38. package/dist/components/input-otp/index.js +27 -0
  39. package/dist/components/text-area/index.cjs +13 -0
  40. package/dist/components/text-area/index.d.cts +73 -0
  41. package/dist/components/text-area/index.d.ts +73 -0
  42. package/dist/components/text-area/index.js +13 -0
  43. package/dist/components/typography/index.cjs +3 -3
  44. package/dist/components/typography/index.js +2 -2
  45. package/dist/index.cjs +53 -51
  46. package/dist/index.d.cts +4 -1
  47. package/dist/index.d.ts +4 -1
  48. package/dist/index.js +69 -67
  49. package/dist/input.type-BpJeUIe8.d.cts +151 -0
  50. package/dist/input.type-DjyZ6P2C.d.ts +151 -0
  51. package/dist/system/index.cjs +6 -5
  52. package/dist/system/index.js +5 -4
  53. package/dist/theme/index.cjs +2 -2
  54. package/dist/theme/index.js +1 -1
  55. package/package.json +21 -1
  56. package/dist/{chunk-DXGQ43IV.cjs → chunk-B4W2XNBP.cjs} +2 -2
  57. package/dist/{chunk-2U6JR7BF.js → chunk-G52TQJBI.js} +3 -3
  58. package/dist/{chunk-FVP5FUVS.js → chunk-ICR42HHG.js} +3 -3
  59. package/dist/{chunk-RAWOJ3N3.cjs → chunk-Y7U6ACMB.cjs} +2 -2
@@ -0,0 +1,731 @@
1
+ import { warnDev } from "./chunk-EGLLDKN6.js";
2
+ import { createRecipe, radiusAxis } from "./chunk-3JATAB7S.js";
3
+ import { createSlotContext, useStyleProps } from "./chunk-PMO62QK4.js";
4
+ import { useXAUITheme } from "./chunk-A3EGFI6T.js";
5
+
6
+ // src/components/input-otp/input-otp-box.tsx
7
+ import { forwardRef as forwardRef3, useMemo } from "react";
8
+ import { View as View2 } from "react-native";
9
+
10
+ // src/components/input-otp/input-otp.context.ts
11
+ var [InputOTPProvider, useInputOTP] = createSlotContext("InputOTP");
12
+ var [InputOTPBoxProvider, useInputOTPBox] = createSlotContext("InputOTP.Box");
13
+
14
+ // src/components/input-otp/input-otp-caret.tsx
15
+ import { useEffect } from "react";
16
+ import { View } from "react-native";
17
+ import Animated, { Easing, cancelAnimation, useAnimatedStyle, useSharedValue, withRepeat, withTiming } from "react-native-reanimated";
18
+ import { jsx } from "react/jsx-runtime";
19
+ var BLINK_DURATION = 530;
20
+ function InputOTPCaret({
21
+ style,
22
+ animation = true,
23
+ ...props
24
+ }) {
25
+ const {
26
+ caretStyle
27
+ } = useInputOTP();
28
+ const {
29
+ slot
30
+ } = useInputOTPBox();
31
+ const [styleProps] = useStyleProps(props);
32
+ const barStyle = [caretStyle, styleProps, style];
33
+ if (!slot?.isCaretVisible) return null;
34
+ if (!animation) return /* @__PURE__ */jsx(View, {
35
+ style: barStyle
36
+ });
37
+ return /* @__PURE__ */jsx(BlinkingCaret, {
38
+ style: barStyle
39
+ });
40
+ }
41
+ InputOTPCaret.displayName = "XAUI.InputOTP.Caret";
42
+ const _worklet_4103709998384_init_data = {
43
+ code: "function chunkI6UCYAO2Js1(){const{opacity}=this.__closure;return{opacity:opacity.value};}",
44
+ location: "/home/runner/work/xaui/xaui/packages/native/dist/chunk-I6UCYAO2.js",
45
+ sourceMap: "{\"version\":3,\"names\":[\"chunkI6UCYAO2Js1\",\"opacity\",\"__closure\",\"value\"],\"sources\":[\"/home/runner/work/xaui/xaui/packages/native/dist/chunk-I6UCYAO2.js\"],\"mappings\":\"AA4DyC,SAAAA,iBAAA,QAAAC,OAAA,OAAAC,SAAA,OAAO,CAAED,OAAO,CAAEA,OAAO,CAACE,KAAM,CAAC\",\"ignoreList\":[]}"
46
+ };
47
+ function BlinkingCaret({
48
+ style
49
+ }) {
50
+ const opacity = useSharedValue(1);
51
+ useEffect(() => {
52
+ opacity.value = withRepeat(withTiming(0, {
53
+ duration: BLINK_DURATION,
54
+ easing: Easing.ease
55
+ }), -1, true);
56
+ return () => cancelAnimation(opacity);
57
+ }, [opacity]);
58
+ const animatedStyle = useAnimatedStyle(function chunkI6UCYAO2Js1Factory({
59
+ _worklet_4103709998384_init_data,
60
+ opacity
61
+ }) {
62
+ const _e = [new global.Error(), -2, -27];
63
+ const chunkI6UCYAO2Js1 = () => ({
64
+ opacity: opacity.value
65
+ });
66
+ chunkI6UCYAO2Js1.__closure = {
67
+ opacity
68
+ };
69
+ chunkI6UCYAO2Js1.__workletHash = 4103709998384;
70
+ chunkI6UCYAO2Js1.__pluginVersion = "0.7.4";
71
+ chunkI6UCYAO2Js1.__initData = _worklet_4103709998384_init_data;
72
+ chunkI6UCYAO2Js1.__stackDetails = _e;
73
+ return chunkI6UCYAO2Js1;
74
+ }({
75
+ _worklet_4103709998384_init_data,
76
+ opacity
77
+ }));
78
+ return /* @__PURE__ */jsx(Animated.View, {
79
+ style: [style, animatedStyle]
80
+ });
81
+ }
82
+
83
+ // src/components/input-otp/input-otp-placeholder.tsx
84
+ import { forwardRef } from "react";
85
+ import { Text } from "react-native";
86
+ import { jsx as jsx2 } from "react/jsx-runtime";
87
+ var InputOTPPlaceholder = forwardRef(function InputOTPPlaceholder2({
88
+ children,
89
+ style,
90
+ maxFontSizeMultiplier = 1.6,
91
+ ...props
92
+ }, ref) {
93
+ const {
94
+ placeholderStyle
95
+ } = useInputOTP();
96
+ const {
97
+ slot
98
+ } = useInputOTPBox();
99
+ const [styleProps, rest] = useStyleProps(props);
100
+ const char = children ?? slot?.placeholderChar;
101
+ if (!char) return null;
102
+ return /* @__PURE__ */jsx2(Text, {
103
+ ref,
104
+ maxFontSizeMultiplier,
105
+ style: [placeholderStyle, styleProps, style],
106
+ ...rest,
107
+ children: char
108
+ });
109
+ });
110
+ InputOTPPlaceholder.displayName = "XAUI.InputOTP.Placeholder";
111
+
112
+ // src/components/input-otp/input-otp-value.tsx
113
+ import { forwardRef as forwardRef2 } from "react";
114
+ import { Text as Text2 } from "react-native";
115
+ import { jsx as jsx3 } from "react/jsx-runtime";
116
+ var InputOTPValue = forwardRef2(function InputOTPValue2({
117
+ children,
118
+ style,
119
+ maxFontSizeMultiplier = 1.6,
120
+ ...props
121
+ }, ref) {
122
+ const {
123
+ valueStyle
124
+ } = useInputOTP();
125
+ const {
126
+ slot
127
+ } = useInputOTPBox();
128
+ const [styleProps, rest] = useStyleProps(props);
129
+ const char = children ?? slot?.char;
130
+ if (!char) return null;
131
+ return /* @__PURE__ */jsx3(Text2, {
132
+ ref,
133
+ maxFontSizeMultiplier,
134
+ style: [valueStyle, styleProps, style],
135
+ ...rest,
136
+ children: char
137
+ });
138
+ });
139
+ InputOTPValue.displayName = "XAUI.InputOTP.Value";
140
+
141
+ // src/components/input-otp/input-otp-box.tsx
142
+ import { Fragment, jsx as jsx4, jsxs } from "react/jsx-runtime";
143
+ var InputOTPBox = forwardRef3(function InputOTPBox2({
144
+ index,
145
+ children,
146
+ style,
147
+ ...props
148
+ }, ref) {
149
+ const {
150
+ boxStyle,
151
+ boxActiveStyle,
152
+ slots
153
+ } = useInputOTP();
154
+ const [styleProps, rest] = useStyleProps(props);
155
+ const slot = slots[index];
156
+ const context = useMemo(() => ({
157
+ slot
158
+ }), [slot]);
159
+ return /* @__PURE__ */jsx4(InputOTPBoxProvider, {
160
+ value: context,
161
+ children: /* @__PURE__ */jsx4(View2, {
162
+ ref,
163
+ style: [slot?.isActive ? boxActiveStyle : boxStyle, styleProps, style],
164
+ ...rest,
165
+ children: children ?? /* @__PURE__ */jsxs(Fragment, {
166
+ children: [/* @__PURE__ */jsx4(InputOTPPlaceholder, {}), /* @__PURE__ */jsx4(InputOTPValue, {}), /* @__PURE__ */jsx4(InputOTPCaret, {})]
167
+ })
168
+ })
169
+ });
170
+ });
171
+ InputOTPBox.displayName = "XAUI.InputOTP.Box";
172
+
173
+ // src/components/input-otp/input-otp-group.tsx
174
+ import { forwardRef as forwardRef4 } from "react";
175
+ import { View as View3 } from "react-native";
176
+ import { jsx as jsx5 } from "react/jsx-runtime";
177
+ var InputOTPGroup = forwardRef4(function InputOTPGroup2({
178
+ children,
179
+ style,
180
+ ...props
181
+ }, ref) {
182
+ const {
183
+ groupStyle,
184
+ slots,
185
+ value,
186
+ maxLength,
187
+ isFocused,
188
+ isDisabled,
189
+ isInvalid
190
+ } = useInputOTP();
191
+ const [styleProps, rest] = useStyleProps(props);
192
+ const content = typeof children === "function" ? children({
193
+ slots,
194
+ value,
195
+ maxLength,
196
+ isFocused,
197
+ isDisabled,
198
+ isInvalid
199
+ }) : children;
200
+ return /* @__PURE__ */jsx5(View3, {
201
+ ref,
202
+ style: [groupStyle, styleProps, style],
203
+ ...rest,
204
+ children: content
205
+ });
206
+ });
207
+ InputOTPGroup.displayName = "XAUI.InputOTP.Group";
208
+
209
+ // src/components/input-otp/input-otp-separator.tsx
210
+ import { forwardRef as forwardRef5 } from "react";
211
+ import { View as View4 } from "react-native";
212
+ import { jsx as jsx6 } from "react/jsx-runtime";
213
+ var InputOTPSeparator = forwardRef5(function InputOTPSeparator2({
214
+ children,
215
+ style,
216
+ ...props
217
+ }, ref) {
218
+ const {
219
+ separatorStyle
220
+ } = useInputOTP();
221
+ const [styleProps, rest] = useStyleProps(props);
222
+ return /* @__PURE__ */jsx6(View4, {
223
+ ref,
224
+ accessibilityElementsHidden: true,
225
+ importantForAccessibility: "no-hide-descendants",
226
+ style: [separatorStyle, styleProps, style],
227
+ ...rest,
228
+ children
229
+ });
230
+ });
231
+ InputOTPSeparator.displayName = "XAUI.InputOTP.Separator";
232
+
233
+ // src/components/input-otp/input-otp.tsx
234
+ import { forwardRef as forwardRef6, useImperativeHandle, useMemo as useMemo3 } from "react";
235
+ import { TextInput, View as View5 } from "react-native";
236
+
237
+ // src/components/input-otp/input-otp.hook.ts
238
+ import { useCallback as useCallback2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
239
+
240
+ // src/hooks/use-controllable-state.ts
241
+ import { useCallback, useRef, useState } from "react";
242
+ function useControllableState({
243
+ value,
244
+ defaultValue,
245
+ onChange
246
+ }) {
247
+ const [uncontrolled, setUncontrolled] = useState(defaultValue);
248
+ const isControlled = value !== void 0;
249
+ const current = isControlled ? value : uncontrolled;
250
+ useControlWarning(isControlled);
251
+ const latest = useRef(current);
252
+ latest.current = current;
253
+ const onChangeRef = useRef(onChange);
254
+ onChangeRef.current = onChange;
255
+ const controlled = useRef(isControlled);
256
+ controlled.current = isControlled;
257
+ const set = useCallback(next => {
258
+ const resolved = typeof next === "function" ? next(latest.current) : next;
259
+ if (resolved === latest.current) return;
260
+ if (!controlled.current) setUncontrolled(resolved);
261
+ onChangeRef.current?.(resolved);
262
+ }, []);
263
+ return [current, set];
264
+ }
265
+ function useControlWarning(isControlled) {
266
+ const wasControlled = useRef(isControlled);
267
+ if (wasControlled.current !== isControlled) {
268
+ warnDev(`a component switched from ${wasControlled.current ? "controlled" : "uncontrolled"} to ${isControlled ? "controlled" : "uncontrolled"}. Decide for the life of the component: pass \`value\` always, or never. Passing \`undefined\` for a value you do control reads as "uncontrolled" here.`);
269
+ wasControlled.current = isControlled;
270
+ }
271
+ }
272
+
273
+ // src/components/input-otp/input-otp.utils.ts
274
+ function buildSlots({
275
+ value,
276
+ maxLength,
277
+ isFocused,
278
+ placeholder
279
+ }) {
280
+ return Array.from({
281
+ length: maxLength
282
+ }, (_, index) => {
283
+ const char = value[index] ?? null;
284
+ const isActive = isFocused && index === value.length;
285
+ return {
286
+ index,
287
+ char,
288
+ // A box shows its placeholder only when it has neither a character nor the caret.
289
+ placeholderChar: char === null && !isActive ? placeholderFor(placeholder, index) : null,
290
+ isActive,
291
+ isCaretVisible: isActive && char === null
292
+ };
293
+ });
294
+ }
295
+ function placeholderFor(placeholder, index) {
296
+ if (!placeholder) return null;
297
+ return placeholder.length === 1 ? placeholder : placeholder[index] ?? null;
298
+ }
299
+ function extractPastedCode(pasted, maxLength) {
300
+ const match = pasted.match(new RegExp(`(?<!\\d)(\\d{${maxLength}})(?!\\d)`));
301
+ return match?.[1] ?? "";
302
+ }
303
+ function isPaste(text, previous) {
304
+ return text.length > previous.length + 1;
305
+ }
306
+ var OTP_DIGITS = "^\\d+$";
307
+ var OTP_LETTERS = "^[a-zA-Z]+$";
308
+ var OTP_ALPHANUMERIC = "^[a-zA-Z0-9]+$";
309
+
310
+ // src/components/input-otp/input-otp.hook.ts
311
+ function useInputOTPState({
312
+ maxLength,
313
+ value: valueProp,
314
+ defaultValue = "",
315
+ onChangeText: onChangeTextProp,
316
+ onComplete,
317
+ pattern,
318
+ placeholder
319
+ }) {
320
+ const [value, setValue] = useControllableState({
321
+ value: valueProp,
322
+ defaultValue,
323
+ onChange: onChangeTextProp
324
+ });
325
+ const [isFocused, setIsFocused] = useState2(false);
326
+ const inputRef = useRef2(null);
327
+ const regexp = useMemo2(() => {
328
+ if (!pattern) return null;
329
+ return typeof pattern === "string" ? new RegExp(pattern) : pattern;
330
+ }, [pattern]);
331
+ const slots = useMemo2(() => buildSlots({
332
+ value,
333
+ maxLength,
334
+ isFocused,
335
+ placeholder
336
+ }), [value, maxLength, isFocused, placeholder]);
337
+ const latest = useRef2({
338
+ value,
339
+ maxLength,
340
+ regexp,
341
+ onComplete,
342
+ setValue
343
+ });
344
+ latest.current = {
345
+ value,
346
+ maxLength,
347
+ regexp,
348
+ onComplete,
349
+ setValue
350
+ };
351
+ const onChangeText = useCallback2(text => {
352
+ const current = latest.current;
353
+ const candidate = isPaste(text, current.value) ? extractPastedCode(text, current.maxLength) : text;
354
+ const next = candidate.slice(0, current.maxLength);
355
+ if (next.length > 0 && current.regexp && !current.regexp.test(next)) return;
356
+ current.setValue(next);
357
+ if (next.length === current.maxLength) current.onComplete?.(next);
358
+ }, []);
359
+ const onFocus = useCallback2(() => setIsFocused(true), []);
360
+ const onBlur = useCallback2(() => setIsFocused(false), []);
361
+ const handle = useMemo2(() => ({
362
+ focus: () => inputRef.current?.focus(),
363
+ blur: () => inputRef.current?.blur(),
364
+ // Both halves: the native buffer and our value. Clearing one and not the other is
365
+ // how a cleared field comes back on the next keystroke.
366
+ clear: () => {
367
+ inputRef.current?.clear();
368
+ latest.current.setValue("");
369
+ }
370
+ }), []);
371
+ return {
372
+ value,
373
+ slots,
374
+ isFocused,
375
+ inputRef,
376
+ handle,
377
+ onChangeText,
378
+ onFocus,
379
+ onBlur
380
+ };
381
+ }
382
+
383
+ // src/components/input-otp/input-otp.recipe.ts
384
+ var SLOTS = ["root", "group", "box", "value", "placeholder", "caret", "separator"];
385
+ var VARIANT_TOKENS = {
386
+ primary: {
387
+ bg: "fieldBackground",
388
+ border: "fieldBorder",
389
+ borderFocus: "accent",
390
+ fg: "fieldForeground"
391
+ },
392
+ secondary: {
393
+ bg: "default",
394
+ border: "fieldBorder",
395
+ borderFocus: "accent",
396
+ fg: "fieldForeground"
397
+ },
398
+ tertiary: {
399
+ border: "fieldBorder",
400
+ borderFocus: "accent",
401
+ fg: "fieldForeground"
402
+ }
403
+ };
404
+ var PLACEHOLDER_OPACITY = 0.5;
405
+ var ACTIVE_BORDER_WIDTH = 2;
406
+ function sizeAxis(step) {
407
+ const {
408
+ control,
409
+ gap,
410
+ glyph
411
+ } = step;
412
+ return theme => {
413
+ const height = theme.controlHeights[control];
414
+ const type = {
415
+ fontSize: theme.fontSizes[glyph],
416
+ lineHeight: theme.lineHeights[glyph]
417
+ };
418
+ return {
419
+ root: {
420
+ gap: theme.spacing(gap)
421
+ },
422
+ group: {
423
+ gap: theme.spacing(gap)
424
+ },
425
+ box: {
426
+ height,
427
+ width: height - theme.spacing(1)
428
+ },
429
+ value: type,
430
+ placeholder: type,
431
+ // As tall as the character it stands in for, so the box does not change shape
432
+ // between an empty state and a typed one.
433
+ caret: {
434
+ height: theme.lineHeights[glyph],
435
+ width: theme.spacing(CARET_WIDTH)
436
+ },
437
+ separator: {
438
+ height: theme.spacing(CARET_WIDTH),
439
+ width: theme.spacing(SEPARATOR_WIDTH)
440
+ }
441
+ };
442
+ };
443
+ }
444
+ var CARET_WIDTH = 0.5;
445
+ var SEPARATOR_WIDTH = 2;
446
+ var SIZES = {
447
+ sm: {
448
+ control: "sm",
449
+ gap: 2,
450
+ glyph: "md"
451
+ },
452
+ md: {
453
+ control: "md",
454
+ gap: 2,
455
+ glyph: "lg"
456
+ },
457
+ lg: {
458
+ control: "lg",
459
+ gap: 2.5,
460
+ glyph: "xl"
461
+ }
462
+ };
463
+ var inputOTPRecipe = createRecipe({
464
+ slots: SLOTS,
465
+ base: theme => ({
466
+ root: {
467
+ flexDirection: "row",
468
+ alignItems: "center"
469
+ },
470
+ group: {
471
+ flexDirection: "row",
472
+ alignItems: "center"
473
+ },
474
+ box: {
475
+ alignItems: "center",
476
+ justifyContent: "center",
477
+ // `lg` and not `field`, though the two are the same twelve points at the default
478
+ // base. The keys are kept apart on purpose: `field` is the corner a theme moves when
479
+ // it wants rounder *fields*, and a field is wide — a code box is very nearly square,
480
+ // 44 by 48 at `md`, where the geometric maximum is 22 and anything near it is a pill
481
+ // in all but name. Following `field` here would hand this component a shape that was
482
+ // never decided for it.
483
+ borderRadius: theme.radius.lg,
484
+ borderCurve: "continuous",
485
+ // The one root in the library that clips: the box has no shadow to lose and a
486
+ // character wider than it would otherwise spill onto its neighbour.
487
+ overflow: "hidden"
488
+ },
489
+ // `semibold`, where a field's own text is `regular`. A code is read at a glance and
490
+ // then compared character by character, which is the one thing weight helps with.
491
+ value: {
492
+ fontFamily: theme.fontFamilies.body,
493
+ fontWeight: theme.fontWeights.semibold
494
+ },
495
+ placeholder: {
496
+ fontFamily: theme.fontFamilies.body,
497
+ fontWeight: theme.fontWeights.semibold,
498
+ color: theme.colors.fieldPlaceholder,
499
+ opacity: PLACEHOLDER_OPACITY
500
+ },
501
+ caret: {
502
+ position: "absolute",
503
+ borderRadius: theme.radius.full,
504
+ backgroundColor: theme.colors.fieldPlaceholder
505
+ },
506
+ // The theme's second separator level rather than the first at half opacity: it is
507
+ // already the lighter of the two, and it composites the same way in both modes.
508
+ separator: {
509
+ borderRadius: theme.radius.full,
510
+ backgroundColor: theme.colors.separatorSecondary
511
+ }
512
+ }),
513
+ variantTokens: VARIANT_TOKENS,
514
+ /**
515
+ * Where the variant's colours land. The border width follows the *presence* of the
516
+ * border role, so a variant that names none needs no rule of its own to say so.
517
+ *
518
+ * The active box takes the ring whichever variant it is: the `focused` state sets the
519
+ * width as well as the colour. The box has a fixed width and height and centres what it
520
+ * holds, so an edge appearing moves nothing.
521
+ */
522
+ paint: (theme, colors) => ({
523
+ box: {
524
+ backgroundColor: colors.bg,
525
+ borderColor: colors.border,
526
+ borderWidth: colors.border ? theme.borderWidth.field : 0
527
+ },
528
+ value: {
529
+ color: colors.fg
530
+ }
531
+ }),
532
+ variants: {
533
+ size: {
534
+ sm: sizeAxis(SIZES.sm),
535
+ md: sizeAxis(SIZES.md),
536
+ lg: sizeAxis(SIZES.lg)
537
+ },
538
+ radius: radiusAxis("box"),
539
+ /**
540
+ * Declared after `size` and before the states, so a code that is wrong stays wrong
541
+ * under the finger: the ring below reads `borderFocus`, and the root hands it the
542
+ * danger colour by suppressing the active state and painting every box instead.
543
+ */
544
+ isInvalid: {
545
+ true: theme => ({
546
+ box: {
547
+ borderColor: theme.colors.danger,
548
+ borderWidth: ACTIVE_BORDER_WIDTH
549
+ }
550
+ })
551
+ }
552
+ },
553
+ compoundVariants: [{
554
+ when: {
555
+ variant: "primary"
556
+ },
557
+ style: theme => ({
558
+ box: theme.shadows.field
559
+ })
560
+ }],
561
+ /**
562
+ * `focused` here means **this box is the active one**, not that the component has the
563
+ * keyboard: the root resolves the recipe twice, once each way, and hands both to the
564
+ * boxes so none of them resolves anything itself (R5).
565
+ */
566
+ states: {
567
+ focused: (_theme, colors) => ({
568
+ box: {
569
+ borderColor: colors.borderFocus,
570
+ borderWidth: ACTIVE_BORDER_WIDTH
571
+ }
572
+ }),
573
+ disabled: theme => ({
574
+ root: {
575
+ opacity: theme.opacity.disabled
576
+ }
577
+ })
578
+ },
579
+ defaultVariants: {
580
+ variant: "secondary",
581
+ size: "md"
582
+ }
583
+ });
584
+
585
+ // src/components/input-otp/input-otp.style.ts
586
+ import { Platform, StyleSheet } from "react-native";
587
+ var inputOTPSheet = StyleSheet.create({
588
+ hiddenInput: {
589
+ ...StyleSheet.absoluteFillObject,
590
+ color: "transparent",
591
+ // A caret of our own is drawn in the active box; the platform's would sit wherever
592
+ // the invisible text happens to end.
593
+ ...Platform.select({
594
+ ios: {
595
+ opacity: 0.02
596
+ },
597
+ default: {
598
+ opacity: 0
599
+ }
600
+ })
601
+ }
602
+ });
603
+
604
+ // src/components/input-otp/input-otp.tsx
605
+ import { jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
606
+ var InputOTPRoot = forwardRef6(function InputOTP({
607
+ children,
608
+ maxLength,
609
+ variant,
610
+ size,
611
+ radius,
612
+ color,
613
+ value: valueProp,
614
+ defaultValue,
615
+ onChangeText,
616
+ onComplete,
617
+ pattern,
618
+ placeholder,
619
+ isInvalid = false,
620
+ isDisabled = false,
621
+ inputMode = "numeric",
622
+ textInputProps,
623
+ style,
624
+ ...props
625
+ }, ref) {
626
+ const theme = useXAUITheme();
627
+ const [styleProps, rest] = useStyleProps(props);
628
+ const state = useInputOTPState({
629
+ maxLength,
630
+ value: valueProp,
631
+ defaultValue,
632
+ onChangeText,
633
+ onComplete,
634
+ pattern,
635
+ placeholder
636
+ });
637
+ useImperativeHandle(ref, () => state.handle, [state.handle]);
638
+ const selection = {
639
+ variant,
640
+ size,
641
+ radius,
642
+ isInvalid: isInvalid ? "true" : void 0
643
+ };
644
+ const states = {
645
+ disabled: isDisabled
646
+ };
647
+ const styles = inputOTPRecipe.resolve({
648
+ theme,
649
+ selection,
650
+ states
651
+ });
652
+ const activeStyles = isInvalid ? styles : inputOTPRecipe.resolve({
653
+ theme,
654
+ selection,
655
+ states: {
656
+ ...states,
657
+ focused: true
658
+ }
659
+ });
660
+ const tint = color ? inputOTPRecipe.tint({
661
+ theme,
662
+ color,
663
+ selection,
664
+ states
665
+ }) : void 0;
666
+ const activeTint = color && !isInvalid ? inputOTPRecipe.tint({
667
+ theme,
668
+ color,
669
+ selection,
670
+ states: {
671
+ ...states,
672
+ focused: true
673
+ }
674
+ }) : tint;
675
+ const context = useMemo3(() => ({
676
+ groupStyle: styles.group,
677
+ boxStyle: tint ? [styles.box, tint.box] : styles.box,
678
+ boxActiveStyle: activeTint ? [activeStyles.box, activeTint.box] : activeStyles.box,
679
+ valueStyle: tint ? [styles.value, tint.value] : styles.value,
680
+ placeholderStyle: styles.placeholder,
681
+ caretStyle: styles.caret,
682
+ separatorStyle: styles.separator,
683
+ slots: state.slots,
684
+ value: state.value,
685
+ maxLength,
686
+ isFocused: state.isFocused,
687
+ isDisabled,
688
+ isInvalid,
689
+ inputRef: state.inputRef
690
+ }), [styles, activeStyles, tint, activeTint, state.slots, state.value, state.isFocused, state.inputRef, maxLength, isDisabled, isInvalid]);
691
+ return /* @__PURE__ */jsx7(InputOTPProvider, {
692
+ value: context,
693
+ children: /* @__PURE__ */jsxs2(View5, {
694
+ style: [styles.root, tint?.root, styleProps, style],
695
+ ...rest,
696
+ children: [children, /* @__PURE__ */jsx7(TextInput, {
697
+ ref: state.inputRef,
698
+ style: inputOTPSheet.hiddenInput,
699
+ value: state.value,
700
+ onChangeText: state.onChangeText,
701
+ onFocus: state.onFocus,
702
+ onBlur: state.onBlur,
703
+ editable: !isDisabled,
704
+ inputMode,
705
+ caretHidden: true,
706
+ autoComplete: "one-time-code",
707
+ textContentType: "oneTimeCode",
708
+ accessibilityLabel: `${maxLength}-character code`,
709
+ accessibilityState: {
710
+ disabled: isDisabled
711
+ },
712
+ accessibilityValue: {
713
+ text: `${state.value.length} of ${maxLength} entered`
714
+ },
715
+ ...textInputProps
716
+ })]
717
+ })
718
+ });
719
+ });
720
+ InputOTPRoot.displayName = "XAUI.InputOTP.Root";
721
+
722
+ // src/components/input-otp/index.ts
723
+ var InputOTP2 = Object.assign(InputOTPRoot, {
724
+ Group: InputOTPGroup,
725
+ Box: InputOTPBox,
726
+ Value: InputOTPValue,
727
+ Placeholder: InputOTPPlaceholder,
728
+ Caret: InputOTPCaret,
729
+ Separator: InputOTPSeparator
730
+ });
731
+ export { useInputOTP, useInputOTPBox, useControllableState, buildSlots, extractPastedCode, OTP_DIGITS, OTP_LETTERS, OTP_ALPHANUMERIC, inputOTPRecipe, InputOTP2 as InputOTP };