@oxy.so/bloom 4.30.1 → 4.32.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 (96) hide show
  1. package/docs/adoption-matrix.mdx +4 -3
  2. package/docs/date-picker.mdx +37 -0
  3. package/docs/input-otp.mdx +22 -5
  4. package/lib/commonjs/date-picker/Calendar.js +2 -0
  5. package/lib/commonjs/date-picker/Calendar.js.map +1 -1
  6. package/lib/commonjs/date-picker/CalendarMonth.js +3 -2
  7. package/lib/commonjs/date-picker/CalendarMonth.js.map +1 -1
  8. package/lib/commonjs/date-picker/DatePicker.js +3 -0
  9. package/lib/commonjs/date-picker/DatePicker.js.map +1 -1
  10. package/lib/commonjs/date-picker/DateRangePicker.js +14 -6
  11. package/lib/commonjs/date-picker/DateRangePicker.js.map +1 -1
  12. package/lib/commonjs/date-picker/MeetingScheduler.js +1 -0
  13. package/lib/commonjs/date-picker/MeetingScheduler.js.map +1 -1
  14. package/lib/commonjs/date-picker/PickerShell.js +5 -3
  15. package/lib/commonjs/date-picker/PickerShell.js.map +1 -1
  16. package/lib/commonjs/date-picker/calendar-grid.js +9 -1
  17. package/lib/commonjs/date-picker/calendar-grid.js.map +1 -1
  18. package/lib/commonjs/input-otp/InputOtp.js +71 -18
  19. package/lib/commonjs/input-otp/InputOtp.js.map +1 -1
  20. package/lib/commonjs/input-otp/index.js +6 -0
  21. package/lib/commonjs/input-otp/index.js.map +1 -1
  22. package/lib/module/date-picker/Calendar.js +2 -0
  23. package/lib/module/date-picker/Calendar.js.map +1 -1
  24. package/lib/module/date-picker/CalendarMonth.js +3 -2
  25. package/lib/module/date-picker/CalendarMonth.js.map +1 -1
  26. package/lib/module/date-picker/DatePicker.js +3 -0
  27. package/lib/module/date-picker/DatePicker.js.map +1 -1
  28. package/lib/module/date-picker/DateRangePicker.js +14 -6
  29. package/lib/module/date-picker/DateRangePicker.js.map +1 -1
  30. package/lib/module/date-picker/MeetingScheduler.js +1 -0
  31. package/lib/module/date-picker/MeetingScheduler.js.map +1 -1
  32. package/lib/module/date-picker/PickerShell.js +4 -4
  33. package/lib/module/date-picker/PickerShell.js.map +1 -1
  34. package/lib/module/date-picker/calendar-grid.js +9 -1
  35. package/lib/module/date-picker/calendar-grid.js.map +1 -1
  36. package/lib/module/input-otp/InputOtp.js +70 -18
  37. package/lib/module/input-otp/InputOtp.js.map +1 -1
  38. package/lib/module/input-otp/index.js +1 -1
  39. package/lib/module/input-otp/index.js.map +1 -1
  40. package/lib/typescript/commonjs/date-picker/Calendar.d.ts.map +1 -1
  41. package/lib/typescript/commonjs/date-picker/CalendarMonth.d.ts +3 -2
  42. package/lib/typescript/commonjs/date-picker/CalendarMonth.d.ts.map +1 -1
  43. package/lib/typescript/commonjs/date-picker/DatePicker.d.ts +1 -1
  44. package/lib/typescript/commonjs/date-picker/DatePicker.d.ts.map +1 -1
  45. package/lib/typescript/commonjs/date-picker/DateRangePicker.d.ts +1 -1
  46. package/lib/typescript/commonjs/date-picker/DateRangePicker.d.ts.map +1 -1
  47. package/lib/typescript/commonjs/date-picker/MeetingScheduler.d.ts.map +1 -1
  48. package/lib/typescript/commonjs/date-picker/PickerShell.d.ts +3 -1
  49. package/lib/typescript/commonjs/date-picker/PickerShell.d.ts.map +1 -1
  50. package/lib/typescript/commonjs/date-picker/calendar-grid.d.ts +3 -2
  51. package/lib/typescript/commonjs/date-picker/calendar-grid.d.ts.map +1 -1
  52. package/lib/typescript/commonjs/date-picker/index.d.ts +1 -1
  53. package/lib/typescript/commonjs/date-picker/index.d.ts.map +1 -1
  54. package/lib/typescript/commonjs/date-picker/types.d.ts +39 -1
  55. package/lib/typescript/commonjs/date-picker/types.d.ts.map +1 -1
  56. package/lib/typescript/commonjs/input-otp/InputOtp.d.ts +4 -2
  57. package/lib/typescript/commonjs/input-otp/InputOtp.d.ts.map +1 -1
  58. package/lib/typescript/commonjs/input-otp/index.d.ts +2 -2
  59. package/lib/typescript/commonjs/input-otp/index.d.ts.map +1 -1
  60. package/lib/typescript/commonjs/input-otp/types.d.ts +14 -2
  61. package/lib/typescript/commonjs/input-otp/types.d.ts.map +1 -1
  62. package/lib/typescript/module/date-picker/Calendar.d.ts.map +1 -1
  63. package/lib/typescript/module/date-picker/CalendarMonth.d.ts +3 -2
  64. package/lib/typescript/module/date-picker/CalendarMonth.d.ts.map +1 -1
  65. package/lib/typescript/module/date-picker/DatePicker.d.ts +1 -1
  66. package/lib/typescript/module/date-picker/DatePicker.d.ts.map +1 -1
  67. package/lib/typescript/module/date-picker/DateRangePicker.d.ts +1 -1
  68. package/lib/typescript/module/date-picker/DateRangePicker.d.ts.map +1 -1
  69. package/lib/typescript/module/date-picker/MeetingScheduler.d.ts.map +1 -1
  70. package/lib/typescript/module/date-picker/PickerShell.d.ts +3 -1
  71. package/lib/typescript/module/date-picker/PickerShell.d.ts.map +1 -1
  72. package/lib/typescript/module/date-picker/calendar-grid.d.ts +3 -2
  73. package/lib/typescript/module/date-picker/calendar-grid.d.ts.map +1 -1
  74. package/lib/typescript/module/date-picker/index.d.ts +1 -1
  75. package/lib/typescript/module/date-picker/index.d.ts.map +1 -1
  76. package/lib/typescript/module/date-picker/types.d.ts +39 -1
  77. package/lib/typescript/module/date-picker/types.d.ts.map +1 -1
  78. package/lib/typescript/module/input-otp/InputOtp.d.ts +4 -2
  79. package/lib/typescript/module/input-otp/InputOtp.d.ts.map +1 -1
  80. package/lib/typescript/module/input-otp/index.d.ts +2 -2
  81. package/lib/typescript/module/input-otp/index.d.ts.map +1 -1
  82. package/lib/typescript/module/input-otp/types.d.ts +14 -2
  83. package/lib/typescript/module/input-otp/types.d.ts.map +1 -1
  84. package/package.json +1 -1
  85. package/src/date-picker/Calendar.tsx +10 -1
  86. package/src/date-picker/CalendarMonth.tsx +5 -3
  87. package/src/date-picker/DatePicker.tsx +3 -0
  88. package/src/date-picker/DateRangePicker.tsx +13 -5
  89. package/src/date-picker/MeetingScheduler.tsx +1 -0
  90. package/src/date-picker/PickerShell.tsx +5 -2
  91. package/src/date-picker/calendar-grid.ts +13 -11
  92. package/src/date-picker/index.ts +4 -0
  93. package/src/date-picker/types.ts +51 -1
  94. package/src/input-otp/InputOtp.tsx +66 -19
  95. package/src/input-otp/index.ts +2 -2
  96. package/src/input-otp/types.ts +15 -2
@@ -10,7 +10,7 @@
10
10
  * internal state. The time of day on an input is ignored.
11
11
  */
12
12
 
13
- import type { DateRange, WeekStart } from './types';
13
+ import type { DateRange, DateRangePreset, WeekStart } from './types';
14
14
 
15
15
  const MS_PER_DAY = 86_400_000;
16
16
 
@@ -334,20 +334,22 @@ export function clampDate(date: Date, { minDate, maxDate }: DateConstraints): Da
334
334
  return startOfDay(date);
335
335
  }
336
336
 
337
- /** Quick-select presets, relative to `now`. */
338
- export function quickSelectPresets(now: Date = today()): { label: string; range: DateRange }[] {
337
+ /** Quick-select presets, relative to `now`. `label` is the English default. */
338
+ export function quickSelectPresets(
339
+ now: Date = today(),
340
+ ): { key: DateRangePreset; label: string; range: DateRange }[] {
339
341
  const lastMonth = addMonths(now, -1);
340
342
  const lastYear = new Date(now.getFullYear() - 1, now.getMonth(), 1);
341
343
  const yesterday = addDays(now, -1);
342
344
  return [
343
- { label: 'Today', range: { start: now, end: now } },
344
- { label: 'Yesterday', range: { start: yesterday, end: yesterday } },
345
- { label: 'Last week', range: { start: addDays(now, -7), end: yesterday } },
346
- { label: 'This month', range: { start: startOfMonth(now), end: endOfMonth(now) } },
347
- { label: 'Last month', range: { start: startOfMonth(lastMonth), end: endOfMonth(lastMonth) } },
348
- { label: 'This year', range: { start: startOfYear(now), end: endOfYear(now) } },
349
- { label: 'Last year', range: { start: startOfYear(lastYear), end: endOfYear(lastYear) } },
350
- { label: 'All time', range: { start: addMonths(now, -120), end: now } },
345
+ { key: 'today', label: 'Today', range: { start: now, end: now } },
346
+ { key: 'yesterday', label: 'Yesterday', range: { start: yesterday, end: yesterday } },
347
+ { key: 'lastWeek', label: 'Last week', range: { start: addDays(now, -7), end: yesterday } },
348
+ { key: 'thisMonth', label: 'This month', range: { start: startOfMonth(now), end: endOfMonth(now) } },
349
+ { key: 'lastMonth', label: 'Last month', range: { start: startOfMonth(lastMonth), end: endOfMonth(lastMonth) } },
350
+ { key: 'thisYear', label: 'This year', range: { start: startOfYear(now), end: endOfYear(now) } },
351
+ { key: 'lastYear', label: 'Last year', range: { start: startOfYear(lastYear), end: endOfYear(lastYear) } },
352
+ { key: 'allTime', label: 'All time', range: { start: addMonths(now, -120), end: now } },
351
353
  ];
352
354
  }
353
355
 
@@ -8,10 +8,14 @@ export { TimeField } from './TimeField';
8
8
 
9
9
  export type {
10
10
  CalendarConstraintProps,
11
+ CalendarLabels,
11
12
  CalendarProps,
13
+ DatePickerLabels,
12
14
  DatePickerProps,
13
15
  DateRange,
16
+ DateRangePickerLabels,
14
17
  DateRangePickerProps,
18
+ DateRangePreset,
15
19
  HourFormat,
16
20
  MeetingSchedulerDetails,
17
21
  MeetingSchedulerHost,
@@ -23,11 +23,23 @@ export interface CalendarConstraintProps {
23
23
  locale?: string;
24
24
  }
25
25
 
26
+ /**
27
+ * Fixed strings of the month panels, overridable for localisation. Month and
28
+ * weekday names already follow `locale`; these are the rest.
29
+ */
30
+ export interface CalendarLabels {
31
+ /** Names the previous-month chevron. Default `'Previous month'`. */
32
+ previousMonth?: string;
33
+ /** Names the next-month chevron. Default `'Next month'`. */
34
+ nextMonth?: string;
35
+ }
36
+
26
37
  interface CalendarBaseProps extends CalendarConstraintProps {
27
38
  /** Month shown first. Defaults to the selected day's month, else today's. */
28
39
  defaultMonth?: Date;
29
40
  /** Names the calendar grid. Defaults to the month title. */
30
41
  accessibilityLabel?: string;
42
+ labels?: CalendarLabels;
31
43
  style?: StyleProp<ViewStyle>;
32
44
  testID?: string;
33
45
  }
@@ -68,6 +80,40 @@ interface PickerBaseProps extends CalendarConstraintProps {
68
80
  testID?: string;
69
81
  }
70
82
 
83
+ /** `DatePicker`'s fixed strings, overridable for localisation. */
84
+ export interface DatePickerLabels extends CalendarLabels {
85
+ /** The footer's dismiss button. Default `'Cancel'`. */
86
+ cancel?: string;
87
+ /** The footer's commit button. Default `'Apply'`. */
88
+ apply?: string;
89
+ }
90
+
91
+ /** The quick-select column's rows, in the order they are drawn. */
92
+ export type DateRangePreset =
93
+ | 'today'
94
+ | 'yesterday'
95
+ | 'lastWeek'
96
+ | 'thisMonth'
97
+ | 'lastMonth'
98
+ | 'thisYear'
99
+ | 'lastYear'
100
+ | 'allTime';
101
+
102
+ /** `DateRangePicker`'s fixed strings, overridable for localisation. */
103
+ export interface DateRangePickerLabels extends DatePickerLabels {
104
+ /**
105
+ * The footer pill. Receives the count so the app pluralises with its own
106
+ * i18n rules. Default `(n) => \`${n} day${n === 1 ? '' : 's'} selected\``.
107
+ */
108
+ daysSelected?: (days: number) => string;
109
+ /** Names the start-date chip. Default `'Start date'`. */
110
+ startDate?: string;
111
+ /** Names the end-date chip. Default `'End date'`. */
112
+ endDate?: string;
113
+ /** Quick-select rows; any left out keep their English text (`'Today'`, `'Last week'`, …). */
114
+ presets?: Partial<Record<DateRangePreset, string>>;
115
+ }
116
+
71
117
  export interface DatePickerProps extends PickerBaseProps {
72
118
  /** Committed day (controlled). `null` for none. */
73
119
  value?: Date | null;
@@ -79,6 +125,8 @@ export interface DatePickerProps extends PickerBaseProps {
79
125
  placeholder?: string;
80
126
  /** Names the popup and its calendar. Defaults to `'Date'`. */
81
127
  accessibilityLabel?: string;
128
+ /** Footer buttons and month chevrons. */
129
+ labels?: DatePickerLabels;
82
130
  }
83
131
 
84
132
  export interface DateRangePickerProps extends PickerBaseProps {
@@ -94,6 +142,8 @@ export interface DateRangePickerProps extends PickerBaseProps {
94
142
  accessibilityLabel?: string;
95
143
  /** Show the quick-select column (Today, Last week, …). Defaults to `true`. */
96
144
  quickSelect?: boolean;
145
+ /** Footer buttons and pill, date chips, quick-select rows and month chevrons. */
146
+ labels?: DateRangePickerLabels;
97
147
  }
98
148
 
99
149
  /** The person the meeting is booked with. */
@@ -136,7 +186,7 @@ export type HourFormat = '12h' | '24h';
136
186
  export type MeetingSchedulerHourFormat = HourFormat;
137
187
 
138
188
  /** Fixed strings, overridable for localisation. */
139
- export interface MeetingSchedulerLabels {
189
+ export interface MeetingSchedulerLabels extends CalendarLabels {
140
190
  /** Default `'Send meeting'`. */
141
191
  send?: string;
142
192
  /** Chip text before a time is picked. Default `'Select a time'`. */
@@ -19,13 +19,14 @@ import {
19
19
  TEXT_FIELD_TRANSITION_MS,
20
20
  } from '../text-field/shared';
21
21
  import { TYPE_SCALE } from '../typography/scale';
22
- import type { InputOtpProps } from './types';
22
+ import type { InputOtpProps, InputOtpType } from './types';
23
23
  import { useFieldMembership } from '../field/membership';
24
24
 
25
25
  /**
26
26
  * `InputOtp`: one box per digit, side by side, behaving as ONE value.
27
27
  *
28
- * box 48 × 48, radius 10, 1px border, shadow-xs
28
+ * box 48 × 48, radius 10, 1px border, shadow-xs; narrower (never
29
+ * wider) when the row does not fit its container
29
30
  * digit mono, title-3-medium 18/26 500, centred, tabular numerals
30
31
  * gap 8 between boxes, +12 before each `groupEvery` group
31
32
  * focus accent-500 border + 2px accent-500 ring (outside the border)
@@ -46,12 +47,19 @@ import { useFieldMembership } from '../field/membership';
46
47
  * Digits are monospace so the boxes stay optically even — in a proportional
47
48
  * face a `1` is visibly narrower than an `8`.
48
49
  *
50
+ * `type="alphanumeric"` is the same field for codes that carry letters: every
51
+ * character is upper-cased, anything outside `A`–`Z`/`0`–`9` is dropped (so a
52
+ * code printed as `ABCDE-12345` pastes whole), and the keyboard is a letters
53
+ * one with auto-capitalisation instead of the number pad.
54
+ *
49
55
  * Focus paints on EVERY focus, not only keyboard focus: a text input matches
50
56
  * `:focus-visible` on a pointer focus too, so the ring shows on click, and
51
57
  * state (not CSS) carries it here so native paints the same ring.
52
58
  */
53
59
 
54
- const DIGITS_ONLY = /\D/g;
60
+ const NOT_DIGIT = /\D/g;
61
+ /** Filtered BEFORE upper-casing: `'ß'.toUpperCase()` is `SS`, `'ı'` becomes `I`. */
62
+ const NOT_ALPHANUMERIC = /[^A-Za-z0-9]/g;
55
63
  const BOX_SIZE = 48;
56
64
  const BOX_GAP = 8;
57
65
  const GROUP_GAP = 12;
@@ -141,7 +149,34 @@ export function resolveInputOtpBoxPaint(
141
149
  return { backgroundColor, borderColor, color, boxShadow };
142
150
  }
143
151
 
144
- const clean = (raw: string, length: number) => raw.replace(DIGITS_ONLY, '').slice(0, length);
152
+ /** The characters `type` accepts, in order; everything else is dropped. Pure. */
153
+ export function cleanInputOtpValue(raw: string, type: InputOtpType = 'numeric'): string {
154
+ return type === 'alphanumeric' ? raw.replace(NOT_ALPHANUMERIC, '').toUpperCase() : raw.replace(NOT_DIGIT, '');
155
+ }
156
+
157
+ const clean = (raw: string, length: number, type: InputOtpType) => cleanInputOtpValue(raw, type).slice(0, length);
158
+
159
+ /**
160
+ * Keyboard and input hints per `type`. The one-time-code autofill hint is
161
+ * shared (below); only what the keyboard offers differs. Android has no
162
+ * `ascii-capable`, and its `visible-password` is the letters keyboard without
163
+ * suggestions or autocorrect — both of which would rewrite a code.
164
+ *
165
+ * Alphanumeric sets `inputMode` on web ONLY: React Native gives `inputMode`
166
+ * precedence over `keyboardType`, so `inputMode: 'text'` on native would open
167
+ * the ordinary keyboard instead of `ascii-capable` / `visible-password`.
168
+ */
169
+ const KEYBOARD_PROPS: Record<InputOtpType, Record<string, unknown>> = {
170
+ numeric: { inputMode: 'numeric', keyboardType: 'number-pad' },
171
+ alphanumeric: {
172
+ ...(IS_WEB
173
+ ? { inputMode: 'text' }
174
+ : { keyboardType: Platform.OS === 'android' ? 'visible-password' : 'ascii-capable' }),
175
+ autoCapitalize: 'characters',
176
+ autoCorrect: false,
177
+ spellCheck: false,
178
+ },
179
+ };
145
180
 
146
181
  const WEB_BOX_STYLE: TextStyle | undefined = IS_WEB
147
182
  ? ({
@@ -155,6 +190,7 @@ const WEB_BOX_STYLE: TextStyle | undefined = IS_WEB
155
190
 
156
191
  export function InputOtp({
157
192
  length = 6,
193
+ type = 'numeric',
158
194
  value,
159
195
  defaultValue = '',
160
196
  onChange,
@@ -186,21 +222,24 @@ export function InputOtp({
186
222
  const groupName = membership.accessibilityLabel ?? 'One-time code';
187
223
 
188
224
  const inputsRef = useRef<Array<TextInput | null>>([]);
189
- const [internal, setInternal] = useState(() => clean(defaultValue, length));
225
+ const [internal, setInternal] = useState(() => clean(defaultValue, length, type));
190
226
  const [focusedIndex, setFocusedIndex] = useState<number | null>(null);
191
227
  const [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
192
228
 
193
229
  const controlled = value !== undefined;
194
- const code = clean(controlled ? value : internal, length);
230
+ const code = clean(controlled ? value : internal, length, type);
231
+ const unit = type === 'alphanumeric' ? 'Character' : 'Digit';
195
232
 
196
233
  const commit = useCallback(
197
234
  (next: string) => {
198
- const cleaned = clean(next, length);
235
+ // `next` is already cleaned per character (a cleared box is a space
236
+ // placeholder, which `clean` drops along with anything else).
237
+ const cleaned = clean(next, length, type);
199
238
  if (!controlled) setInternal(cleaned);
200
239
  onChange?.(cleaned);
201
240
  if (cleaned.length === length) onComplete?.(cleaned);
202
241
  },
203
- [controlled, length, onChange, onComplete],
242
+ [controlled, length, type, onChange, onComplete],
204
243
  );
205
244
 
206
245
  const focusBox = useCallback(
@@ -210,9 +249,9 @@ export function InputOtp({
210
249
  [length],
211
250
  );
212
251
 
213
- /** Writes `digits` starting at `index`, which covers typing, paste and autofill. */
214
- const writeFrom = (index: number, digits: string) => {
215
- const incoming = digits.replace(DIGITS_ONLY, '');
252
+ /** Writes `text` starting at `index`, which covers typing, paste and autofill. */
253
+ const writeFrom = (index: number, text: string) => {
254
+ const incoming = cleanInputOtpValue(text, type);
216
255
  if (incoming === '') return;
217
256
  const chars = code.padEnd(length, ' ').split('');
218
257
  for (let offset = 0; offset < incoming.length && index + offset < length; offset += 1) {
@@ -281,16 +320,18 @@ export function InputOtp({
281
320
  } as Record<string, unknown>)
282
321
  : {})}
283
322
  testID={testID ? `${testID}-${index}` : undefined}
284
- // `text` with a numeric keyboard rather than a number input: a number
285
- // input brings spinners, accepts `e` and `-`, and reports an empty
286
- // value for anything it considers malformed.
287
- inputMode="numeric"
288
- keyboardType="number-pad"
323
+ // Numeric is `text` with a numeric keyboard rather than a number
324
+ // input: a number input brings spinners, accepts `e` and `-`, and
325
+ // reports an empty value for anything it considers malformed.
326
+ {...KEYBOARD_PROPS[type]}
289
327
  autoComplete={Platform.OS === 'android' ? 'sms-otp' : 'one-time-code'}
290
328
  textContentType="oneTimeCode"
291
329
  autoFocus={autoFocus && index === 0}
292
- // Long enough to accept a full autofilled code in one box.
293
- maxLength={length}
330
+ // Long enough to accept a full autofilled or pasted code in one box,
331
+ // separators included: a browser truncates a paste to `maxLength`
332
+ // BEFORE the change handler sees it, so `length` alone lost the
333
+ // last character of `ABCDE-12345`.
334
+ maxLength={length * 2}
294
335
  // Typing into a filled box must REPLACE its digit, so the digit is
295
336
  // selected on focus. Web's `selectTextOnFocus` does that. Android's
296
337
  // does not: it selects on the input's next layout, and focusing a box
@@ -300,7 +341,7 @@ export function InputOtp({
300
341
  selectTextOnFocus={IS_WEB}
301
342
  caretHidden={false}
302
343
  editable={!disabled}
303
- accessibilityLabel={`Digit ${index + 1} of ${length}`}
344
+ accessibilityLabel={`${unit} ${index + 1} of ${length}`}
304
345
  aria-invalid={invalid || undefined}
305
346
  aria-disabled={disabled || undefined}
306
347
  value={digit === ' ' ? '' : digit}
@@ -315,6 +356,12 @@ export function InputOtp({
315
356
  style={[
316
357
  {
317
358
  width: BOX_SIZE,
359
+ // A box shrinks (never grows) when the row is narrower than
360
+ // its natural width, so ten boxes still fit a phone. `minWidth`
361
+ // 0 is what lets it: a flex item's automatic minimum is its
362
+ // specified width, and an `<input>` would otherwise overflow.
363
+ flexShrink: 1,
364
+ minWidth: 0,
318
365
  height: BOX_SIZE,
319
366
  marginLeft: gapBefore ? GROUP_GAP : 0,
320
367
  padding: 0,
@@ -1,2 +1,2 @@
1
- export { InputOtp } from './InputOtp';
2
- export type { InputOtpProps } from './types';
1
+ export { InputOtp, cleanInputOtpValue } from './InputOtp';
2
+ export type { InputOtpProps, InputOtpType } from './types';
@@ -1,9 +1,22 @@
1
1
  import type { ViewStyleProp } from '../styles';
2
2
 
3
+ /**
4
+ * What a box accepts. `numeric` (the default) keeps digits only;
5
+ * `alphanumeric` upper-cases and keeps `A`–`Z` and `0`–`9`.
6
+ */
7
+ export type InputOtpType = 'numeric' | 'alphanumeric';
8
+
3
9
  export interface InputOtpProps extends ViewStyleProp {
4
- /** Number of digit boxes, default `6`. */
10
+ /** Number of boxes, default `6`. */
5
11
  length?: number;
6
- /** Controlled value. Non-digits are dropped and longer strings truncated to `length`. */
12
+ /**
13
+ * `numeric` (default): digits only, number pad. `alphanumeric`: letters and
14
+ * digits, upper-cased, on a letters keyboard with auto-capitalisation.
15
+ * Anything else — a dash, a space — is dropped either way, so a pasted
16
+ * `ABCDE-12345` fills ten boxes.
17
+ */
18
+ type?: InputOtpType;
19
+ /** Controlled value. Characters the `type` does not accept are dropped and longer strings truncated to `length`. */
7
20
  value?: string;
8
21
  /** Initial value when uncontrolled. */
9
22
  defaultValue?: string;