@hjmds/react-native 0.8.2

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 (94) hide show
  1. package/README.md +310 -0
  2. package/dist/actions.d.ts +128 -0
  3. package/dist/actions.d.ts.map +1 -0
  4. package/dist/actions.js +157 -0
  5. package/dist/actions.js.map +1 -0
  6. package/dist/data-display.d.ts +285 -0
  7. package/dist/data-display.d.ts.map +1 -0
  8. package/dist/data-display.js +775 -0
  9. package/dist/data-display.js.map +1 -0
  10. package/dist/date-picker.d.ts +25 -0
  11. package/dist/date-picker.d.ts.map +1 -0
  12. package/dist/date-picker.js +39 -0
  13. package/dist/date-picker.js.map +1 -0
  14. package/dist/evidence.d.ts +954 -0
  15. package/dist/evidence.d.ts.map +1 -0
  16. package/dist/evidence.js +98 -0
  17. package/dist/evidence.js.map +1 -0
  18. package/dist/feedback.d.ts +148 -0
  19. package/dist/feedback.d.ts.map +1 -0
  20. package/dist/feedback.js +559 -0
  21. package/dist/feedback.js.map +1 -0
  22. package/dist/file-picker.d.ts +20 -0
  23. package/dist/file-picker.d.ts.map +1 -0
  24. package/dist/file-picker.js +37 -0
  25. package/dist/file-picker.js.map +1 -0
  26. package/dist/forms.d.ts +170 -0
  27. package/dist/forms.d.ts.map +1 -0
  28. package/dist/forms.js +595 -0
  29. package/dist/forms.js.map +1 -0
  30. package/dist/index.d.ts +16 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +16 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/inputs-public.d.ts +6 -0
  35. package/dist/inputs-public.d.ts.map +1 -0
  36. package/dist/inputs-public.js +6 -0
  37. package/dist/inputs-public.js.map +1 -0
  38. package/dist/inputs.d.ts +258 -0
  39. package/dist/inputs.d.ts.map +1 -0
  40. package/dist/inputs.js +681 -0
  41. package/dist/inputs.js.map +1 -0
  42. package/dist/internal/modal-lifecycle.d.ts +15 -0
  43. package/dist/internal/modal-lifecycle.d.ts.map +1 -0
  44. package/dist/internal/modal-lifecycle.js +17 -0
  45. package/dist/internal/modal-lifecycle.js.map +1 -0
  46. package/dist/internal/state.d.ts +8 -0
  47. package/dist/internal/state.d.ts.map +1 -0
  48. package/dist/internal/state.js +18 -0
  49. package/dist/internal/state.js.map +1 -0
  50. package/dist/internal/styles.d.ts +29 -0
  51. package/dist/internal/styles.d.ts.map +1 -0
  52. package/dist/internal/styles.js +51 -0
  53. package/dist/internal/styles.js.map +1 -0
  54. package/dist/navigation.d.ts +271 -0
  55. package/dist/navigation.d.ts.map +1 -0
  56. package/dist/navigation.js +978 -0
  57. package/dist/navigation.js.map +1 -0
  58. package/dist/number-field.d.ts +58 -0
  59. package/dist/number-field.d.ts.map +1 -0
  60. package/dist/number-field.js +172 -0
  61. package/dist/number-field.js.map +1 -0
  62. package/dist/otp-field.d.ts +2 -0
  63. package/dist/otp-field.d.ts.map +1 -0
  64. package/dist/otp-field.js +2 -0
  65. package/dist/otp-field.js.map +1 -0
  66. package/dist/overlays.d.ts +68 -0
  67. package/dist/overlays.d.ts.map +1 -0
  68. package/dist/overlays.js +757 -0
  69. package/dist/overlays.js.map +1 -0
  70. package/dist/password-field.d.ts +2 -0
  71. package/dist/password-field.d.ts.map +1 -0
  72. package/dist/password-field.js +2 -0
  73. package/dist/password-field.js.map +1 -0
  74. package/dist/primitives.d.ts +132 -0
  75. package/dist/primitives.d.ts.map +1 -0
  76. package/dist/primitives.js +238 -0
  77. package/dist/primitives.js.map +1 -0
  78. package/dist/provider.d.ts +41 -0
  79. package/dist/provider.d.ts.map +1 -0
  80. package/dist/provider.js +78 -0
  81. package/dist/provider.js.map +1 -0
  82. package/dist/slider.d.ts +45 -0
  83. package/dist/slider.d.ts.map +1 -0
  84. package/dist/slider.js +200 -0
  85. package/dist/slider.js.map +1 -0
  86. package/dist/steps.d.ts +13 -0
  87. package/dist/steps.d.ts.map +1 -0
  88. package/dist/steps.js +13 -0
  89. package/dist/steps.js.map +1 -0
  90. package/dist/upload-item.d.ts +13 -0
  91. package/dist/upload-item.d.ts.map +1 -0
  92. package/dist/upload-item.js +25 -0
  93. package/dist/upload-item.js.map +1 -0
  94. package/package.json +166 -0
package/dist/inputs.js ADDED
@@ -0,0 +1,681 @@
1
+ import { createElement as _createElement } from "react";
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { resolveColorReference } from "@hjmds/design-contracts/color-references";
4
+ import { glyph, radius, spacing, typography } from "@hjmds/design-contracts/foundations";
5
+ import { fieldRecipe, } from "@hjmds/design-contracts/recipes/base";
6
+ import { chipRecipe, searchFieldRecipe, segmentedControlRecipe, selectionControlRecipe, selectionGroupRecipe, switchRecipe, } from "@hjmds/design-contracts/recipes";
7
+ import { passwordFieldRecipe, resolvePasswordFieldDescriptor, } from "@hjmds/design-contracts/components/password-field";
8
+ import { getOtpFieldSlotValues, otpFieldRecipe, resolveOtpFieldValue, } from "@hjmds/design-contracts/components/otp-field";
9
+ import { getCheckboxNextState, reconcileCheckboxSelection, resolveControlAccessibleName, resolveInitialRadioValue, resolveInitialTabValue, reconcileRadioSelection, selectionGroupBehaviorDefaults, toggleCheckboxSelection, validateCheckboxSelection, validateRadioSelection, validateSelectionItems, } from "@hjmds/design-contracts/behaviors";
10
+ import { forwardRef, useEffect, useId, useImperativeHandle, useRef, useState, } from "react";
11
+ import { ActivityIndicator, Pressable, Switch as NativeSwitch, TextInput, View, } from "react-native";
12
+ import { useControllableState } from "./internal/state.js";
13
+ import { logicalTextAlign, minimumTargetStyle, resolveNativeTextScaleProps, } from "./internal/styles.js";
14
+ import { Text } from "./primitives.js";
15
+ import { useHjmNativeTheme } from "./provider.js";
16
+ function resolveFieldAccessibleName(label, accessibilityLabel) {
17
+ const visibleLabel = label?.trim();
18
+ const explicitAccessibleName = accessibilityLabel?.trim();
19
+ const accessibleName = explicitAccessibleName || visibleLabel;
20
+ if (!accessibleName) {
21
+ throw new TypeError("Field requires a non-empty label or accessibilityLabel");
22
+ }
23
+ return {
24
+ accessibleName,
25
+ ...(visibleLabel ? { visibleLabel } : {}),
26
+ };
27
+ }
28
+ function FieldMessage({ error, supportText }) {
29
+ if (!error && !supportText)
30
+ return null;
31
+ return (_jsx(Text, { accessibilityLiveRegion: error ? "assertive" : "none", tone: error ? "danger" : "muted", variant: fieldRecipe.support.textVariant, children: error ?? supportText }));
32
+ }
33
+ const FieldRenderer = forwardRef(function FieldRenderer({ label, value, defaultValue = "", onValueChange, supportText, error, required = false, disabled = false, busy = false, variant = fieldRecipe.defaults.variant, shape, accessibilityLabel, inputStyle, containerStyle, allowFontScaling, multiline, search, searchSize = searchFieldRecipe.defaults.size, leading, trailing, onBlur, onFocus, ...props }, ref) {
34
+ const theme = useHjmNativeTheme();
35
+ const { colors, environment, textScaling } = theme;
36
+ const [focused, setFocused] = useState(false);
37
+ const [currentValue, setCurrentValue] = useControllableState({
38
+ ...(value === undefined ? {} : { value }),
39
+ defaultValue,
40
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
41
+ });
42
+ const hint = error ?? supportText;
43
+ const { accessibleName, visibleLabel } = resolveFieldAccessibleName(label, accessibilityLabel);
44
+ const resolvedShape = shape ?? (search ? searchFieldRecipe.defaults.shape : fieldRecipe.defaults.shape);
45
+ const searchSizing = searchFieldRecipe.sizes[searchSize];
46
+ const minHeight = multiline
47
+ ? fieldRecipe.multilineMinHeight
48
+ : search
49
+ ? searchSizing.minHeight
50
+ : fieldRecipe.minHeight;
51
+ const borderWidth = search ? searchFieldRecipe.borderWidth : fieldRecipe.borderWidth;
52
+ const borderColor = search
53
+ ? resolveColorReference(error
54
+ ? searchFieldRecipe.colors.invalid
55
+ : focused
56
+ ? searchFieldRecipe.colors.focus
57
+ : searchFieldRecipe.colors.border, theme.palette)
58
+ : colors[error
59
+ ? fieldRecipe.states.invalid.border
60
+ : focused
61
+ ? fieldRecipe.states.focused.border
62
+ : fieldRecipe.states.idle.border];
63
+ const backgroundColor = search && variant === fieldRecipe.defaults.variant
64
+ ? resolveColorReference(searchFieldRecipe.colors.background, theme.palette)
65
+ : colors[fieldRecipe.variants[variant].background];
66
+ const placeholderColor = search
67
+ ? resolveColorReference(searchFieldRecipe.colors.placeholder, theme.palette)
68
+ : colors[fieldRecipe.placeholder.color];
69
+ const textStyle = typography[search ? searchSizing.textVariant : fieldRecipe.textVariant];
70
+ const controlRadius = radius[search ? searchFieldRecipe.shapes[resolvedShape] : fieldRecipe.shapes[resolvedShape]];
71
+ const inputTextScaleProps = resolveNativeTextScaleProps(textScaling, [
72
+ {
73
+ color: search
74
+ ? resolveColorReference(searchFieldRecipe.colors.content, theme.palette)
75
+ : colors.text,
76
+ flex: 1,
77
+ fontSize: textStyle.fontSize,
78
+ fontWeight: textStyle.fontWeight,
79
+ lineHeight: textStyle.lineHeight,
80
+ minHeight: minHeight - (borderWidth * 2),
81
+ paddingHorizontal: 0,
82
+ paddingVertical: fieldRecipe.paddingVertical,
83
+ textAlign: logicalTextAlign(environment.direction),
84
+ textAlignVertical: multiline ? "top" : "center",
85
+ },
86
+ inputStyle,
87
+ ], allowFontScaling);
88
+ return (_jsxs(View, { style: [
89
+ {
90
+ gap: fieldRecipe.label.gap,
91
+ opacity: disabled
92
+ ? search
93
+ ? searchFieldRecipe.states.disabledOpacity
94
+ : fieldRecipe.disabledOpacity
95
+ : 1,
96
+ },
97
+ containerStyle,
98
+ ], children: [visibleLabel ? (_jsxs(Text, { style: {
99
+ color: colors[fieldRecipe.label.color],
100
+ fontWeight: fieldRecipe.label.fontWeight,
101
+ }, tone: "body", variant: fieldRecipe.label.textVariant, children: [visibleLabel, required ? " *" : ""] })) : null, _jsxs(View, { style: { gap: fieldRecipe.support.gap }, children: [_jsxs(View, { style: {
102
+ alignItems: multiline ? "stretch" : "center",
103
+ backgroundColor,
104
+ borderColor,
105
+ borderRadius: controlRadius,
106
+ borderWidth,
107
+ direction: environment.direction,
108
+ flexDirection: "row",
109
+ gap: search ? searchSizing.gap : 0,
110
+ minHeight,
111
+ paddingHorizontal: search
112
+ ? searchSizing.paddingHorizontal
113
+ : fieldRecipe.paddingHorizontal,
114
+ }, children: [leading ? (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", children: leading })) : null, _jsx(TextInput, { ...props, ...inputTextScaleProps, ref: ref, accessibilityHint: hint, accessibilityLabel: accessibleName, accessibilityRole: search ? "search" : undefined, accessibilityState: { busy, disabled }, editable: !disabled && !busy, multiline: multiline, onBlur: (event) => {
115
+ setFocused(false);
116
+ onBlur?.(event);
117
+ }, onChangeText: setCurrentValue, onFocus: (event) => {
118
+ setFocused(true);
119
+ onFocus?.(event);
120
+ }, placeholderTextColor: placeholderColor, value: currentValue }), trailing] }), _jsx(FieldMessage, { ...(error === undefined ? {} : { error }), ...(supportText === undefined ? {} : { supportText }) })] })] }));
121
+ });
122
+ export const TextField = forwardRef(function TextField(props, ref) {
123
+ return _jsx(FieldRenderer, { ...props, ref: ref, multiline: false, search: false });
124
+ });
125
+ export const TextArea = forwardRef(function TextArea(props, ref) {
126
+ return _jsx(FieldRenderer, { ...props, ref: ref, multiline: true, search: false });
127
+ });
128
+ export const SearchField = forwardRef(function SearchField({ clearLabel, busyLabel, onClear, leading: leadingNode, trailing: trailingNode, renderLeading, renderClearIcon, renderBusyIndicator, value, defaultValue, onValueChange, size = searchFieldRecipe.defaults.size, busy = false, disabled = false, ...props }, ref) {
129
+ const theme = useHjmNativeTheme();
130
+ const searchSizing = searchFieldRecipe.sizes[size];
131
+ const iconProps = {
132
+ color: resolveColorReference(searchFieldRecipe.colors.leading, theme.palette),
133
+ size: glyph[searchSizing.glyph],
134
+ disabled,
135
+ };
136
+ const [searchValue, setSearchValue] = useControllableState({
137
+ ...(value === undefined ? {} : { value }),
138
+ defaultValue: defaultValue ?? "",
139
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
140
+ });
141
+ const leading = leadingNode ?? renderLeading?.(iconProps);
142
+ const trailing = busy ? (_jsx(View, { accessibilityLabel: busyLabel, accessibilityRole: "progressbar", accessibilityState: { busy: true }, style: {
143
+ alignItems: "center",
144
+ height: searchSizing.clearDiameter,
145
+ justifyContent: "center",
146
+ width: searchSizing.clearDiameter,
147
+ }, children: renderBusyIndicator?.(iconProps) ?? (_jsx(ActivityIndicator, { color: iconProps.color, size: iconProps.size })) })) : searchValue.length > 0 ? (_jsx(Pressable, { accessibilityLabel: clearLabel, accessibilityRole: "button", disabled: disabled, hitSlop: searchSizing.clearHitSlop, onPress: () => {
148
+ setSearchValue("");
149
+ onClear?.();
150
+ }, style: {
151
+ alignItems: "center",
152
+ height: searchSizing.clearDiameter,
153
+ justifyContent: "center",
154
+ width: searchSizing.clearDiameter,
155
+ }, children: renderClearIcon?.(iconProps) ?? (_jsx(Text, { align: "center", style: { fontSize: iconProps.size, lineHeight: iconProps.size }, tone: "muted", children: "\u00D7" })) })) : trailingNode;
156
+ return (_jsx(FieldRenderer, { ...props, ref: ref, busy: busy, disabled: disabled, leading: leading, multiline: false, onValueChange: (next) => {
157
+ if (!busy && !disabled)
158
+ setSearchValue(next);
159
+ }, search: true, searchSize: size, trailing: trailing, value: searchValue }));
160
+ });
161
+ function DefaultPasswordToggleIcon({ color, revealed, size, }) {
162
+ const eyeWidth = size * 1.08;
163
+ const eyeHeight = size * 0.68;
164
+ const strokeWidth = Math.max(1.5, size * 0.1);
165
+ return (_jsxs(View, { accessible: false, style: {
166
+ alignItems: "center",
167
+ height: size,
168
+ justifyContent: "center",
169
+ width: eyeWidth,
170
+ }, children: [_jsx(View, { style: {
171
+ alignItems: "center",
172
+ borderColor: color,
173
+ borderRadius: eyeHeight / 2,
174
+ borderWidth: strokeWidth,
175
+ height: eyeHeight,
176
+ justifyContent: "center",
177
+ width: eyeWidth,
178
+ }, children: _jsx(View, { style: {
179
+ backgroundColor: color,
180
+ borderRadius: size * 0.15,
181
+ height: size * 0.3,
182
+ width: size * 0.3,
183
+ } }) }), revealed ? (_jsx(View, { style: {
184
+ backgroundColor: color,
185
+ borderRadius: strokeWidth,
186
+ height: strokeWidth,
187
+ position: "absolute",
188
+ transform: [{ rotate: "-42deg" }],
189
+ width: eyeWidth * 1.18,
190
+ } })) : null] }));
191
+ }
192
+ /** Password input with independent reveal state and native autofill translation. */
193
+ export const PasswordField = forwardRef(function PasswordField({ revealed: revealedProp, defaultRevealed = false, onRevealedChange, autofillHint, revealLabel, concealLabel, size = passwordFieldRecipe.defaults.size, renderToggleIcon, disabled = false, onSelectionChange, ...props }, forwardedRef) {
194
+ const theme = useHjmNativeTheme();
195
+ const inputRef = useRef(null);
196
+ useImperativeHandle(forwardedRef, () => inputRef.current);
197
+ const selectionRef = useRef({ start: 0, end: 0 });
198
+ const [revealed, setRevealed] = useControllableState({
199
+ ...(revealedProp === undefined ? {} : { value: revealedProp }),
200
+ defaultValue: defaultRevealed,
201
+ ...(onRevealedChange === undefined ? {} : { onChange: onRevealedChange }),
202
+ });
203
+ const resolved = resolvePasswordFieldDescriptor({ revealed, autofillHint }, {
204
+ composeToggleAccessibleName: ({ willReveal }) => willReveal ? revealLabel : concealLabel,
205
+ });
206
+ const metrics = passwordFieldRecipe.sizes[size];
207
+ const toggleColor = resolveColorReference(passwordFieldRecipe.toggle.color, theme.palette);
208
+ const appearance = {
209
+ name: revealed
210
+ ? passwordFieldRecipe.toggle.icons.revealed
211
+ : passwordFieldRecipe.toggle.icons.concealed,
212
+ color: toggleColor,
213
+ size: glyph.sm,
214
+ revealed,
215
+ disabled,
216
+ };
217
+ useEffect(() => {
218
+ const timeout = setTimeout(() => {
219
+ inputRef.current?.setNativeProps({ selection: selectionRef.current });
220
+ }, 0);
221
+ return () => clearTimeout(timeout);
222
+ }, [revealed]);
223
+ return (_jsx(FieldRenderer, { ...props, ref: inputRef, autoComplete: autofillHint === "current" ? "current-password" : "new-password", disabled: disabled, inputStyle: [
224
+ size === "large"
225
+ ? {
226
+ fontSize: typography.bodyLarge.fontSize,
227
+ lineHeight: typography.bodyLarge.lineHeight,
228
+ minHeight: metrics.minHeight - (passwordFieldRecipe.frame.borderWidth * 2),
229
+ }
230
+ : undefined,
231
+ props.inputStyle,
232
+ ], multiline: false, onSelectionChange: (event) => {
233
+ selectionRef.current = event.nativeEvent.selection;
234
+ onSelectionChange?.(event);
235
+ }, search: false, secureTextEntry: resolved.nativeSecureTextEntry, textContentType: autofillHint === "current" ? "password" : "newPassword", trailing: (_jsx(Pressable, { accessibilityLabel: resolved.toggleAccessibleName, accessibilityRole: "button", accessibilityState: { disabled, selected: revealed }, disabled: disabled, onPress: () => setRevealed(!revealed), style: ({ pressed }) => ({
236
+ alignItems: "center",
237
+ height: metrics.toggleDiameter,
238
+ justifyContent: "center",
239
+ opacity: pressed ? 0.72 : 1,
240
+ width: metrics.toggleDiameter,
241
+ }), children: renderToggleIcon?.(appearance) ?? _jsx(DefaultPasswordToggleIcon, { ...appearance }) })) }));
242
+ });
243
+ /** One accessible numeric TextInput rendered through decorative OTP slots. */
244
+ export const OtpField = forwardRef(function OtpField({ label, accessibilityLabel, supportText, error, required = false, disabled = false, busy = false, readOnly = false, length, value: valueProp, defaultValue = "", onValueChange, onComplete, size = otpFieldRecipe.defaults.size, slotStyle, slotTextStyle, containerStyle, allowFontScaling, onBlur, onFocus, ...props }, ref) {
245
+ const theme = useHjmNativeTheme();
246
+ const { accessibleName, visibleLabel } = resolveFieldAccessibleName(label, accessibilityLabel);
247
+ const [focused, setFocused] = useState(false);
248
+ const [value, setValue] = useControllableState({
249
+ ...(valueProp === undefined ? {} : { value: valueProp }),
250
+ defaultValue: resolveOtpFieldValue(length, defaultValue),
251
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
252
+ });
253
+ const slots = getOtpFieldSlotValues({ length, value });
254
+ const complete = value.length === length;
255
+ const wasCompleteRef = useRef(complete);
256
+ useEffect(() => {
257
+ if (complete && !wasCompleteRef.current)
258
+ onComplete?.(value);
259
+ wasCompleteRef.current = complete;
260
+ }, [complete, onComplete, value]);
261
+ const metrics = otpFieldRecipe.sizes[size];
262
+ const activeIndex = Math.min(value.length, length - 1);
263
+ const slotHeight = Math.max(metrics.slotSize, typography[metrics.textVariant].lineHeight * theme.environment.textScale + spacing.xs * 2);
264
+ const baseBorder = resolveColorReference(otpFieldRecipe.slot.border, theme.palette);
265
+ const focusBorder = resolveColorReference(otpFieldRecipe.slot.focusBorder, theme.palette);
266
+ const invalidBorder = resolveColorReference(otpFieldRecipe.slot.invalidBorder, theme.palette);
267
+ const filledBorder = resolveColorReference(otpFieldRecipe.slot.filledBorder, theme.palette);
268
+ const contentColor = resolveColorReference(otpFieldRecipe.slot.content, theme.palette);
269
+ return (_jsxs(View, { style: [
270
+ {
271
+ gap: fieldRecipe.label.gap,
272
+ opacity: disabled || busy ? otpFieldRecipe.states.disabledOpacity : 1,
273
+ },
274
+ containerStyle,
275
+ ], children: [visibleLabel ? (_jsxs(Text, { style: {
276
+ color: theme.colors[fieldRecipe.label.color],
277
+ fontWeight: fieldRecipe.label.fontWeight,
278
+ }, tone: "body", variant: fieldRecipe.label.textVariant, children: [visibleLabel, required ? " *" : ""] })) : null, _jsxs(View, { style: { gap: otpFieldRecipe.support.gap }, children: [_jsxs(View, { style: {
279
+ direction: "ltr",
280
+ flexDirection: "row",
281
+ gap: metrics.gap,
282
+ maxWidth: metrics.slotSize * length + metrics.gap * (length - 1),
283
+ position: "relative",
284
+ width: "100%",
285
+ }, children: [_jsx(TextInput, { ...props, ref: ref, accessibilityHint: error ?? supportText, accessibilityLabel: accessibleName, accessibilityState: { busy, disabled: disabled || readOnly }, allowFontScaling: allowFontScaling, autoComplete: "one-time-code", caretHidden: true, editable: !disabled && !busy && !readOnly, keyboardType: "number-pad", maxLength: length, onBlur: (event) => {
286
+ setFocused(false);
287
+ onBlur?.(event);
288
+ }, onChangeText: (rawText) => setValue(resolveOtpFieldValue(length, rawText)), onFocus: (event) => {
289
+ setFocused(true);
290
+ onFocus?.(event);
291
+ }, selectionColor: "transparent", style: {
292
+ bottom: 0,
293
+ color: "transparent",
294
+ left: 0,
295
+ opacity: 0.01,
296
+ padding: 0,
297
+ position: "absolute",
298
+ right: 0,
299
+ top: 0,
300
+ zIndex: 1,
301
+ }, textContentType: "oneTimeCode", value: value }), slots.map((digit, index) => {
302
+ const borderColor = error
303
+ ? invalidBorder
304
+ : focused && index === activeIndex
305
+ ? focusBorder
306
+ : digit
307
+ ? filledBorder
308
+ : baseBorder;
309
+ return (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", style: [
310
+ {
311
+ alignItems: "center",
312
+ backgroundColor: theme.colors.surface,
313
+ borderColor,
314
+ borderRadius: radius[otpFieldRecipe.slot.radius],
315
+ borderWidth: otpFieldRecipe.slot.borderWidth,
316
+ flex: 1,
317
+ height: slotHeight,
318
+ justifyContent: "center",
319
+ maxWidth: metrics.slotSize,
320
+ minWidth: 0,
321
+ },
322
+ slotStyle,
323
+ ], children: _jsx(Text, { accessible: false, align: "center", allowFontScaling: allowFontScaling, style: [{ color: contentColor }, slotTextStyle], variant: metrics.textVariant, children: digit }) }, index));
324
+ })] }), _jsx(FieldMessage, { ...(error === undefined ? {} : { error }), ...(supportText === undefined ? {} : { supportText }) })] })] }));
325
+ });
326
+ function ChoiceRow({ kind, label, description, checked, disabled, readOnly, required, invalid, readOnlyLabel, requiredLabel, invalidLabel, accessibilityHint, presentation = selectionControlRecipe.defaults.presentation, size = selectionControlRecipe.defaults.size, indicator = "default", leading, renderLeading, renderIndicator, onActivate, style, controlStyle, indicatorStyle, leadingStyle, contentStyle, labelStyle, descriptionStyle, }) {
327
+ const theme = useHjmNativeTheme();
328
+ const metrics = selectionControlRecipe.sizes[size];
329
+ const plate = selectionControlRecipe.presentations[presentation];
330
+ const selected = checked === true || checked === "mixed";
331
+ const indicatorColor = resolveColorReference(selectionControlRecipe.states.indicator, theme.palette);
332
+ const appearance = {
333
+ checked,
334
+ selected,
335
+ disabled,
336
+ readOnly,
337
+ color: indicatorColor,
338
+ size: metrics.control,
339
+ };
340
+ const resolvedLeading = leading ?? renderLeading?.(appearance);
341
+ const plateBackground = selected
342
+ ? selectionControlRecipe.states.selectedBackground
343
+ : plate.background ?? selectionControlRecipe.states.idleBackground;
344
+ const plateBorder = invalid
345
+ ? selectionControlRecipe.states.invalidBorder
346
+ : selected
347
+ ? selectionControlRecipe.states.selectedBorder
348
+ : plate.border;
349
+ const controlBorder = invalid
350
+ ? selectionControlRecipe.states.invalidBorder
351
+ : selected
352
+ ? selectionControlRecipe.states.checkedBorder
353
+ : selectionControlRecipe.states.idleBorder;
354
+ const resolvedHint = [
355
+ accessibilityHint ?? description,
356
+ required ? requiredLabel : undefined,
357
+ readOnly ? readOnlyLabel : undefined,
358
+ invalid ? invalidLabel : undefined,
359
+ ].filter(Boolean).join(". ") || undefined;
360
+ const defaultIndicator = kind === "radio" ? (checked === true ? (_jsx(View, { style: {
361
+ backgroundColor: indicatorColor,
362
+ borderRadius: radius.full,
363
+ height: metrics.control * selectionControlRecipe.radioDotRatio,
364
+ width: metrics.control * selectionControlRecipe.radioDotRatio,
365
+ } })) : null) : checked === "mixed" ? (_jsx(Text, { accessible: false, align: "center", style: { color: indicatorColor }, variant: "label", children: "\u2212" })) : checked ? (_jsx(Text, { accessible: false, align: "center", style: { color: indicatorColor }, variant: "label", children: "\u2713" })) : null;
366
+ return (_jsxs(Pressable, { accessibilityHint: resolvedHint, accessibilityLabel: label, accessibilityRole: kind, accessibilityState: { checked, disabled: disabled || readOnly }, disabled: disabled || readOnly, hitSlop: plate.useSizePadding ? 0 : metrics.hitSlop, onPress: () => {
367
+ if (!readOnly)
368
+ onActivate();
369
+ }, style: ({ pressed }) => [
370
+ {
371
+ alignItems: "center",
372
+ alignSelf: "stretch",
373
+ backgroundColor: resolveColorReference(plateBackground, theme.palette),
374
+ borderColor: plateBorder
375
+ ? resolveColorReference(plateBorder, theme.palette)
376
+ : "transparent",
377
+ borderRadius: radius[plate.radius],
378
+ borderWidth: plate.borderWidth,
379
+ direction: theme.environment.direction,
380
+ flexDirection: "row",
381
+ gap: metrics.gap,
382
+ minHeight: metrics.rowMinHeight,
383
+ opacity: disabled
384
+ ? selectionControlRecipe.states.disabledOpacity
385
+ : pressed && !readOnly
386
+ ? 0.86
387
+ : 1,
388
+ paddingHorizontal: plate.useSizePadding ? metrics.paddingHorizontal : 0,
389
+ paddingVertical: plate.useSizePadding ? metrics.paddingVertical : 0,
390
+ },
391
+ style,
392
+ ], children: [indicator === "default" ? (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", style: [
393
+ {
394
+ alignItems: "center",
395
+ backgroundColor: resolveColorReference(selected
396
+ ? selectionControlRecipe.states.checkedBackground
397
+ : selectionControlRecipe.states.idleBackground, theme.palette),
398
+ borderColor: resolveColorReference(controlBorder, theme.palette),
399
+ borderRadius: radius[selectionControlRecipe.shapes[kind]],
400
+ borderWidth: 1,
401
+ height: metrics.control,
402
+ justifyContent: "center",
403
+ width: metrics.control,
404
+ },
405
+ controlStyle,
406
+ ], children: _jsx(View, { style: indicatorStyle, children: renderIndicator?.(appearance) ?? defaultIndicator }) })) : null, resolvedLeading ? (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", style: leadingStyle, children: resolvedLeading })) : null, _jsxs(View, { style: [{ flex: 1, gap: spacing.xxs, minWidth: 0 }, contentStyle], children: [_jsx(Text, { style: [
407
+ {
408
+ color: resolveColorReference(selectionControlRecipe.label.color, theme.palette),
409
+ fontWeight: selected
410
+ ? selectionControlRecipe.label.checkedFontWeight
411
+ : selectionControlRecipe.label.fontWeight,
412
+ },
413
+ labelStyle,
414
+ ], variant: metrics.labelVariant, children: label }), description ? (_jsx(Text, { style: [
415
+ {
416
+ color: resolveColorReference(selectionControlRecipe.description.color, theme.palette),
417
+ },
418
+ descriptionStyle,
419
+ ], variant: metrics.descriptionVariant, children: description })) : null] })] }));
420
+ }
421
+ export function Checkbox({ label, checked, defaultChecked = false, onCheckedChange, disabled = false, readOnly = false, required = false, invalid = false, description, readOnlyLabel, requiredLabel, invalidLabel, leading, renderLeading, renderIndicator, accessibilityHint, ...visual }) {
422
+ const [selected, setSelected] = useControllableState({
423
+ ...(checked === undefined ? {} : { value: checked }),
424
+ defaultValue: defaultChecked,
425
+ ...(onCheckedChange === undefined
426
+ ? {}
427
+ : { onChange: (next) => onCheckedChange(next === true) }),
428
+ });
429
+ return (_jsx(ChoiceRow, { ...visual, accessibilityHint: accessibilityHint, checked: selected, description: description, disabled: disabled, indicator: visual.indicator ?? "default", invalid: invalid, invalidLabel: invalidLabel, kind: "checkbox", label: label, leading: leading, onActivate: () => setSelected(getCheckboxNextState(selected)), readOnly: readOnly, readOnlyLabel: readOnlyLabel, renderIndicator: renderIndicator, renderLeading: renderLeading, required: required, requiredLabel: requiredLabel }));
430
+ }
431
+ /** Standalone native radio item. Prefer RadioGroup when group state is owned here. */
432
+ export function Radio({ label, checked, defaultChecked = false, onCheckedChange, disabled = false, readOnly = false, required = false, invalid = false, description, readOnlyLabel, requiredLabel, invalidLabel, leading, renderLeading, renderIndicator, accessibilityHint, ...visual }) {
433
+ const [selected, setSelected] = useControllableState({
434
+ ...(checked === undefined ? {} : { value: checked }),
435
+ defaultValue: defaultChecked,
436
+ ...(onCheckedChange === undefined
437
+ ? {}
438
+ : { onChange: (next) => next && onCheckedChange(true) }),
439
+ });
440
+ return (_jsx(ChoiceRow, { ...visual, accessibilityHint: accessibilityHint, checked: selected, description: description, disabled: disabled, indicator: visual.indicator ?? "default", invalid: invalid, invalidLabel: invalidLabel, kind: "radio", label: label, leading: leading, onActivate: () => setSelected(true), readOnly: readOnly, readOnlyLabel: readOnlyLabel, renderIndicator: renderIndicator, renderLeading: renderLeading, required: required, requiredLabel: requiredLabel }));
441
+ }
442
+ function ChoiceGroupFrame({ label, accessibilityLabel, required, requiredLabel, readOnly, readOnlyLabel, disabled, description, error, role, orientation, presentation, style, children, }) {
443
+ const theme = useHjmNativeTheme();
444
+ const id = useId().replaceAll(":", "");
445
+ const labelId = `${id}-label`;
446
+ const accessibleName = resolveControlAccessibleName(label, accessibilityLabel, "Choice group");
447
+ const announcedName = [
448
+ accessibleName,
449
+ required ? requiredLabel ?? "*" : undefined,
450
+ readOnly ? readOnlyLabel : undefined,
451
+ ].filter(Boolean).join(", ");
452
+ const gap = selectionGroupRecipe.orientations[orientation].gap[presentation];
453
+ return (_jsxs(View, { accessibilityHint: [error ?? description, readOnly ? readOnlyLabel : undefined]
454
+ .filter(Boolean).join(". ") || undefined, accessibilityLabel: announcedName, accessibilityLabelledBy: label ? labelId : undefined, accessibilityRole: role, accessibilityState: { disabled: disabled || readOnly }, accessibilityValue: error ? { text: error } : undefined, style: [{ direction: theme.environment.direction, gap: selectionGroupRecipe.supportGap }, style], children: [label ? (_jsxs(Text, { nativeID: labelId, tone: "primary", variant: selectionGroupRecipe.label.textVariant, children: [label, required ? requiredLabel ? ` (${requiredLabel})` : " *" : ""] })) : null, _jsx(View, { style: {
455
+ direction: theme.environment.direction,
456
+ flexDirection: orientation === "horizontal" && theme.environment.textScale < 1.6
457
+ ? "row"
458
+ : "column",
459
+ gap,
460
+ }, children: children }), error ? (_jsx(Text, { accessibilityLiveRegion: "assertive", accessibilityRole: "alert", tone: "danger", variant: selectionGroupRecipe.error.textVariant, children: error })) : description ? (_jsx(Text, { tone: "muted", variant: selectionGroupRecipe.description.textVariant, children: description })) : null] }));
461
+ }
462
+ export function RadioGroup({ label, accessibilityLabel, options, value, defaultValue, onValueChange, required = false, disabled = false, readOnly = false, invalid = false, description, error, requiredLabel, readOnlyLabel, invalidLabel, orientation = selectionGroupBehaviorDefaults.orientation, presentation = selectionGroupRecipe.defaults.presentation, size = selectionControlRecipe.defaults.size, indicator = "default", renderLeading, renderIndicator, style, ...slotStyles }) {
463
+ const selectionItems = options.map((option) => ({
464
+ id: option.value,
465
+ label: option.label,
466
+ ...(option.description === undefined ? {} : { description: option.description }),
467
+ ...(option.disabled === undefined ? {} : { disabled: option.disabled }),
468
+ }));
469
+ validateSelectionItems(selectionItems);
470
+ if (value !== undefined)
471
+ validateRadioSelection(selectionItems, value);
472
+ const initialRef = useRef(null);
473
+ initialRef.current ??= {
474
+ value: resolveInitialRadioValue(selectionItems, value ?? defaultValue, required),
475
+ };
476
+ const [storedValue, setSelected] = useControllableState({
477
+ ...(value === undefined ? {} : { value }),
478
+ defaultValue: initialRef.current.value,
479
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
480
+ });
481
+ const selected = reconcileRadioSelection(selectionItems, storedValue, required);
482
+ useEffect(() => {
483
+ if (value === undefined && selected !== storedValue)
484
+ setSelected(selected);
485
+ }, [selected, setSelected, storedValue, value]);
486
+ const hasError = invalid || error !== undefined;
487
+ return (_jsx(ChoiceGroupFrame, { accessibilityLabel: accessibilityLabel, description: description, disabled: disabled, error: error, label: label, orientation: orientation, presentation: presentation, readOnly: readOnly, readOnlyLabel: readOnlyLabel, required: required, requiredLabel: requiredLabel, role: "radiogroup", style: style, children: options.map((option) => {
488
+ const optionDisabled = disabled || option.disabled === true;
489
+ const optionSelected = selected === option.value;
490
+ return (_createElement(ChoiceRow, { ...slotStyles, key: option.value, accessibilityHint: option.accessibilityHint, checked: optionSelected, description: option.description, disabled: optionDisabled, indicator: indicator, invalid: hasError, invalidLabel: invalidLabel ?? error, kind: "radio", label: option.label, leading: option.leading, onActivate: () => setSelected(option.value), presentation: presentation, readOnly: readOnly, readOnlyLabel: readOnlyLabel, renderIndicator: renderIndicator ? (props) => renderIndicator(option, props) : undefined, renderLeading: renderLeading ? (props) => renderLeading(option, props) : undefined, required: required, requiredLabel: requiredLabel, size: size }));
491
+ }) }));
492
+ }
493
+ /** Validated controlled/uncontrolled checkbox collection using immutable Sets. */
494
+ export function CheckboxGroup({ label, accessibilityLabel, items, value, defaultValue = new Set(), onValueChange, required = false, disabled = false, readOnly = false, invalid = false, description, error, requiredLabel, readOnlyLabel, invalidLabel, orientation = selectionGroupBehaviorDefaults.orientation, presentation = selectionGroupRecipe.defaults.presentation, size = selectionControlRecipe.defaults.size, indicator = "default", renderLeading, renderIndicator, style, ...slotStyles }) {
495
+ validateSelectionItems(items);
496
+ if (value !== undefined)
497
+ validateCheckboxSelection(items, value);
498
+ const [storedValue, setSelected] = useControllableState({
499
+ ...(value === undefined ? {} : { value }),
500
+ defaultValue,
501
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
502
+ });
503
+ const selected = reconcileCheckboxSelection(items, storedValue);
504
+ useEffect(() => {
505
+ if (value === undefined && selected !== storedValue)
506
+ setSelected(selected);
507
+ }, [selected, setSelected, storedValue, value]);
508
+ const hasError = invalid || error !== undefined;
509
+ return (_jsx(ChoiceGroupFrame, { accessibilityLabel: accessibilityLabel, description: description, disabled: disabled, error: error, label: label, orientation: orientation, presentation: presentation, readOnly: readOnly, readOnlyLabel: readOnlyLabel, required: required, requiredLabel: requiredLabel, style: style, children: items.map((item) => {
510
+ const optionDisabled = disabled || item.disabled === true;
511
+ const optionSelected = selected.has(item.id);
512
+ return (_createElement(ChoiceRow, { ...slotStyles, key: item.id, checked: optionSelected, description: item.description, disabled: optionDisabled, indicator: indicator, invalid: hasError, invalidLabel: invalidLabel ?? error, kind: "checkbox", label: item.label, onActivate: () => setSelected(toggleCheckboxSelection(items, selected, item.id)), presentation: presentation, readOnly: readOnly, readOnlyLabel: readOnlyLabel, renderIndicator: renderIndicator ? (props) => renderIndicator(item, props) : undefined, renderLeading: renderLeading ? (props) => renderLeading(item, props) : undefined, required: required, requiredLabel: requiredLabel, size: size }));
513
+ }) }));
514
+ }
515
+ export function Switch({ label, description, size = switchRecipe.defaults.size, value, defaultValue = false, onValueChange, disabled = false, accessibilityLabel, accessibilityHint, style, ...props }) {
516
+ const { colors, environment } = useHjmNativeTheme();
517
+ const dimensions = switchRecipe.sizes[size];
518
+ const [enabled, setEnabled] = useControllableState({
519
+ ...(value === undefined ? {} : { value }),
520
+ defaultValue,
521
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
522
+ });
523
+ return (_jsxs(Pressable, { accessibilityHint: accessibilityHint ?? description, accessibilityLabel: accessibilityLabel ?? label, accessibilityRole: "switch", accessibilityState: { checked: enabled, disabled }, disabled: disabled, onPress: () => setEnabled(!enabled), style: ({ pressed }) => [
524
+ minimumTargetStyle,
525
+ {
526
+ alignItems: "center",
527
+ direction: environment.direction,
528
+ flexDirection: "row",
529
+ gap: spacing.sm,
530
+ minHeight: description
531
+ ? switchRecipe.rowTwoLineMinHeight
532
+ : switchRecipe.rowMinHeight,
533
+ opacity: disabled ? 0.5 : pressed ? 0.86 : 1,
534
+ },
535
+ style,
536
+ ], children: [_jsxs(View, { style: { flex: 1, gap: spacing.xxs }, children: [_jsx(Text, { tone: "body", variant: "bodyLarge", children: label }), description ? (_jsx(Text, { tone: "muted", variant: "caption", children: description })) : null] }), _jsx(NativeSwitch, { ...props, accessible: false, disabled: disabled, ios_backgroundColor: colors.surfaceAlt, pointerEvents: "none", style: { height: dimensions.height, width: dimensions.width }, thumbColor: colors.bg, trackColor: { false: colors.surfaceAlt, true: colors.primary }, value: enabled })] }));
537
+ }
538
+ export function SegmentedControl({ label, options, value, defaultValue, onValueChange, size = segmentedControlRecipe.defaults.size, disabled = false, style, }) {
539
+ const theme = useHjmNativeTheme();
540
+ const { environment } = theme;
541
+ const sizeContract = segmentedControlRecipe.sizes[size];
542
+ const stacked = segmentedControlRecipe.adaptive.largeTextLayout === "stacked"
543
+ && environment.textScale >= segmentedControlRecipe.adaptive.stackAtFontScale;
544
+ const descriptors = options.map((option) => ({
545
+ id: option.value,
546
+ label: option.label,
547
+ ...(option.disabled === undefined ? {} : { disabled: option.disabled }),
548
+ }));
549
+ const collectionFallback = resolveInitialTabValue(descriptors);
550
+ if (collectionFallback === undefined)
551
+ throw new Error("SegmentedControl requires an enabled option");
552
+ if (value !== undefined)
553
+ resolveInitialTabValue(descriptors, value);
554
+ const initialRef = useRef(null);
555
+ if (initialRef.current === null) {
556
+ const initial = resolveInitialTabValue(descriptors, value ?? defaultValue);
557
+ if (initial === undefined)
558
+ throw new Error("SegmentedControl requires an enabled option");
559
+ initialRef.current = { value: initial };
560
+ }
561
+ const [storedValue, setSelected] = useControllableState({
562
+ ...(value === undefined ? {} : { value }),
563
+ defaultValue: initialRef.current.value,
564
+ ...(onValueChange === undefined ? {} : { onChange: onValueChange }),
565
+ });
566
+ const storedValueValid = descriptors.some((item) => item.id === storedValue && !item.disabled);
567
+ const selected = storedValueValid ? storedValue : collectionFallback;
568
+ const controlled = value !== undefined;
569
+ useEffect(() => {
570
+ if (!controlled && !storedValueValid)
571
+ setSelected(collectionFallback);
572
+ }, [collectionFallback, controlled, setSelected, storedValueValid]);
573
+ return (_jsx(View, { accessibilityLabel: label, accessibilityRole: "radiogroup", style: [
574
+ {
575
+ backgroundColor: resolveColorReference(segmentedControlRecipe.container.background, theme.palette),
576
+ borderColor: resolveColorReference(segmentedControlRecipe.container.border, theme.palette),
577
+ borderRadius: radius[segmentedControlRecipe.container.radius],
578
+ borderWidth: segmentedControlRecipe.container.borderWidth,
579
+ direction: environment.direction,
580
+ flexDirection: stacked ? "column" : "row",
581
+ gap: segmentedControlRecipe.container.gap,
582
+ padding: segmentedControlRecipe.container.padding,
583
+ },
584
+ style,
585
+ ], children: options.map((option) => {
586
+ const isSelected = option.value === selected;
587
+ const optionDisabled = disabled || option.disabled === true;
588
+ const contentColor = resolveColorReference(isSelected
589
+ ? segmentedControlRecipe.item.selectedContent
590
+ : segmentedControlRecipe.item.idleContent, theme.palette);
591
+ const leading = option.leading ?? option.renderLeading?.({
592
+ selected: isSelected,
593
+ disabled: optionDisabled,
594
+ color: contentColor,
595
+ size: glyph.sm,
596
+ });
597
+ return (_jsxs(Pressable, { accessibilityLabel: option.label, accessibilityRole: "radio", accessibilityState: { checked: isSelected, disabled: optionDisabled }, disabled: optionDisabled, hitSlop: sizeContract.hitSlop, onPress: () => setSelected(option.value), style: ({ pressed }) => [
598
+ {
599
+ alignItems: "center",
600
+ backgroundColor: isSelected
601
+ ? resolveColorReference(segmentedControlRecipe.item.selectedBackground, theme.palette)
602
+ : "transparent",
603
+ borderColor: isSelected
604
+ ? resolveColorReference(segmentedControlRecipe.item.selectedBorder, theme.palette)
605
+ : "transparent",
606
+ borderRadius: radius[segmentedControlRecipe.item.radius],
607
+ borderWidth: isSelected
608
+ ? segmentedControlRecipe.item.selectedBorderWidth
609
+ : 0,
610
+ flex: stacked ? undefined : 1,
611
+ gap: segmentedControlRecipe.item.gap,
612
+ justifyContent: "center",
613
+ minHeight: sizeContract.minHeight,
614
+ opacity: optionDisabled
615
+ ? segmentedControlRecipe.item.disabledOpacity
616
+ : pressed
617
+ ? segmentedControlRecipe.item.pressedOpacity
618
+ : 1,
619
+ paddingHorizontal: sizeContract.paddingHorizontal,
620
+ width: stacked ? "100%" : undefined,
621
+ },
622
+ ], children: [leading ? (_jsx(View, { accessibilityElementsHidden: true, accessible: false, importantForAccessibility: "no-hide-descendants", children: leading })) : null, _jsx(Text, { align: "center", style: {
623
+ color: contentColor,
624
+ fontWeight: isSelected
625
+ ? segmentedControlRecipe.item.selectedFontWeight
626
+ : segmentedControlRecipe.item.fontWeight,
627
+ }, tone: isSelected ? "brand" : "muted", variant: sizeContract.textVariant, children: option.label })] }, option.value));
628
+ }) }));
629
+ }
630
+ /** Action/filter chip with role-specific, controlled selection semantics. */
631
+ export function Chip({ label, size = chipRecipe.defaults.size, disabled = false, leading, trailing, accessibilityLabel, accessibilityHint, style, leadingStyle, indicatorStyle, labelStyle, trailingStyle, renderSelectionIndicator, selectionMode = "action", selected, onPress, }) {
632
+ const theme = useHjmNativeTheme();
633
+ const selectable = selectionMode !== "action";
634
+ const active = selectable && selected === true;
635
+ const metrics = chipRecipe.sizes[size];
636
+ const presentation = chipRecipe.states[active ? "selected" : "idle"];
637
+ const contentColor = resolveColorReference(presentation.content, theme.palette);
638
+ const indicatorColor = resolveColorReference(chipRecipe.selectionIndicator.color, theme.palette);
639
+ const role = selectionMode === "single" ? "radio" : selectionMode === "multiple" ? "checkbox" : "button";
640
+ return (_jsxs(Pressable, { accessibilityHint: accessibilityHint, accessibilityLabel: accessibilityLabel ?? label, accessibilityRole: role, accessibilityState: selectable ? { checked: active, disabled } : { disabled }, disabled: disabled, hitSlop: metrics.hitSlop, onPress: (event) => {
641
+ if (selectionMode === "action") {
642
+ onPress(event);
643
+ }
644
+ else {
645
+ onPress(!active, event);
646
+ }
647
+ }, style: ({ pressed }) => [
648
+ {
649
+ alignItems: "center",
650
+ alignSelf: "flex-start",
651
+ backgroundColor: resolveColorReference(presentation.background, theme.palette),
652
+ borderColor: resolveColorReference(presentation.border, theme.palette),
653
+ borderRadius: radius[chipRecipe.radius],
654
+ borderWidth: chipRecipe.borderWidth,
655
+ direction: theme.environment.direction,
656
+ flexDirection: "row",
657
+ gap: metrics.gap,
658
+ height: metrics.height,
659
+ opacity: disabled
660
+ ? chipRecipe.states.disabledOpacity
661
+ : pressed
662
+ ? chipRecipe.states.pressedOpacity
663
+ : 1,
664
+ paddingHorizontal: metrics.paddingHorizontal,
665
+ },
666
+ style,
667
+ ], children: [leading ? _jsx(View, { accessible: false, style: leadingStyle, children: leading }) : null, active ? (_jsx(View, { accessible: false, style: indicatorStyle, children: renderSelectionIndicator ? (renderSelectionIndicator({
668
+ selected: active,
669
+ color: indicatorColor,
670
+ size: glyph[chipRecipe.selectionIndicator.glyph],
671
+ })) : (_jsx(Text, { style: { color: indicatorColor }, variant: "caption", children: "\u2713" })) })) : null, _jsx(Text, { align: "center", style: [
672
+ {
673
+ color: contentColor,
674
+ fontWeight: active
675
+ ? chipRecipe.label.selectedFontWeight
676
+ : chipRecipe.label.fontWeight,
677
+ },
678
+ labelStyle,
679
+ ], variant: metrics.textVariant, children: label }), trailing ? _jsx(View, { accessible: false, style: trailingStyle, children: trailing }) : null] }));
680
+ }
681
+ //# sourceMappingURL=inputs.js.map