@dloizides/ui-forms 1.6.0 → 1.7.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.
package/dist/index.js CHANGED
@@ -4,48 +4,119 @@ var React = require('react');
4
4
  var reactNative = require('react-native');
5
5
  var uiFeedback = require('@dloizides/ui-feedback');
6
6
  var jsxRuntime = require('react/jsx-runtime');
7
+ var uiButtons = require('@dloizides/ui-buttons');
7
8
 
8
9
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
10
 
10
11
  var React__default = /*#__PURE__*/_interopDefault(React);
11
12
 
12
13
  // src/Field/Field.tsx
14
+ function FieldLabel({
15
+ label,
16
+ marker,
17
+ optionalLabel,
18
+ style,
19
+ requiredMarkStyle,
20
+ optionalMarkStyle
21
+ }) {
22
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style, children: [
23
+ label,
24
+ " ",
25
+ marker === "required" ? (
26
+ // The asterisk is decorative — the control's `aria-required` conveys "required" to
27
+ // assistive tech, so a screen reader says "required" instead of "star".
28
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { "aria-hidden": true, accessibilityElementsHidden: true, importantForAccessibility: "no", style: requiredMarkStyle, children: "*" })
29
+ ) : null,
30
+ marker === "optional" && optionalLabel !== "" ? (
31
+ // Also decorative: "optional" is the ABSENCE of `aria-required`, which assistive tech
32
+ // already conveys. Rendering it to a screen reader would double-announce the same fact.
33
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { "aria-hidden": true, accessibilityElementsHidden: true, importantForAccessibility: "no", style: optionalMarkStyle, children: optionalLabel })
34
+ ) : null
35
+ ] });
36
+ }
37
+
38
+ // src/Field/fieldMarkers.ts
39
+ var DEFAULT_OPTIONAL_LABEL = "(optional)";
40
+ function resolveFieldMarker(required, optional) {
41
+ if (required) return "required";
42
+ if (optional) return "optional";
43
+ return "none";
44
+ }
45
+ var FIELD_FONT_SIZE = 13;
46
+ var FIELD_FONT_WEIGHT = "600";
47
+ var CONTROL_FONT_SIZE = 11;
48
+ var CONTROL_FONT_WEIGHT = "700";
49
+ var CONTROL_LETTER_SPACING = 0.4;
50
+ var labelVariantStyles = reactNative.StyleSheet.create({
51
+ field: {
52
+ fontSize: FIELD_FONT_SIZE,
53
+ fontWeight: FIELD_FONT_WEIGHT
54
+ },
55
+ control: {
56
+ fontSize: CONTROL_FONT_SIZE,
57
+ fontWeight: CONTROL_FONT_WEIGHT,
58
+ letterSpacing: CONTROL_LETTER_SPACING,
59
+ textTransform: "uppercase"
60
+ }
61
+ });
62
+ function resolveLabelVariantStyle(variant) {
63
+ return variant === "control" ? labelVariantStyles.control : labelVariantStyles.field;
64
+ }
13
65
  var CONTAINER_MARGIN_BOTTOM = 16;
14
- var LABEL_FONT_SIZE = 13;
15
- var LABEL_FONT_WEIGHT = "600";
16
66
  var LABEL_MARGIN_BOTTOM = 4;
17
67
  var ERROR_FONT_SIZE = 12;
18
68
  var ERROR_MARGIN_TOP = 4;
69
+ var HINT_FONT_SIZE = 12;
70
+ var HINT_MARGIN_TOP = 4;
71
+ var OPTIONAL_MARK_FONT_WEIGHT = "400";
19
72
  var styles = reactNative.StyleSheet.create({
20
73
  container: {
21
74
  marginBottom: CONTAINER_MARGIN_BOTTOM
22
75
  },
23
76
  label: {
24
- marginBottom: LABEL_MARGIN_BOTTOM,
25
- fontSize: LABEL_FONT_SIZE,
26
- fontWeight: LABEL_FONT_WEIGHT
77
+ marginBottom: LABEL_MARGIN_BOTTOM
78
+ },
79
+ hintText: {
80
+ fontSize: HINT_FONT_SIZE,
81
+ marginTop: HINT_MARGIN_TOP
27
82
  },
28
83
  errorText: {
29
84
  fontSize: ERROR_FONT_SIZE,
30
85
  marginTop: ERROR_MARGIN_TOP
86
+ },
87
+ optionalMark: {
88
+ fontWeight: OPTIONAL_MARK_FONT_WEIGHT
31
89
  }
32
90
  });
33
91
  var fieldSeq = 0;
34
- function useFieldErrorId() {
35
- const [id] = React__default.default.useState(() => {
92
+ function useFieldIds() {
93
+ const [ids] = React__default.default.useState(() => {
36
94
  fieldSeq += 1;
37
- return `field-error-${String(fieldSeq)}`;
95
+ const seq = String(fieldSeq);
96
+ return { hintId: `field-hint-${seq}`, errorId: `field-error-${seq}` };
38
97
  });
39
- return id;
98
+ return ids;
99
+ }
100
+ function isPresent(value) {
101
+ return typeof value === "string" && value !== "";
40
102
  }
41
103
  function hasFieldError(error) {
42
- return typeof error === "string" && error !== "";
104
+ return isPresent(error);
105
+ }
106
+ function joinDescribedBy(hintId, errorId) {
107
+ const ids = [hintId, errorId].filter((id) => isPresent(id));
108
+ return ids.length > 0 ? ids.join(" ") : void 0;
43
109
  }
44
110
  var Field = ({
45
111
  label,
46
112
  children,
47
113
  required = false,
114
+ optional = false,
115
+ optionalLabel = DEFAULT_OPTIONAL_LABEL,
116
+ hint,
48
117
  error,
118
+ labelVariant,
119
+ labelStyle,
49
120
  containerStyle,
50
121
  testID
51
122
  }) => {
@@ -53,31 +124,89 @@ var Field = ({
53
124
  const { colors, semantic } = theme;
54
125
  const errorColor = semantic.error["500"];
55
126
  const hasError = hasFieldError(error);
56
- const hasLabel = typeof label === "string" && label !== "";
57
- const errorId = useFieldErrorId();
127
+ const hasHint = isPresent(hint);
128
+ const labelText = label ?? "";
129
+ const hasLabel = labelText !== "";
130
+ const marker = resolveFieldMarker(required, optional);
131
+ const { hintId, errorId } = useFieldIds();
58
132
  const themeStyles = React__default.default.useMemo(
59
133
  () => ({
60
134
  label: { color: colors.textSecondary },
61
135
  requiredMark: { color: errorColor },
136
+ // The optional marker is an aside, so it sits a step back from the label's own ink.
137
+ optionalMark: { color: colors.textSecondary },
138
+ hintText: { color: colors.textSecondary },
62
139
  errorText: { color: errorColor }
63
140
  }),
64
141
  [colors.textSecondary, errorColor]
65
142
  );
66
- const control = typeof children === "function" ? children({ describedById: hasError ? errorId : void 0, hasError }) : children;
143
+ const describedById = joinDescribedBy(hasHint ? hintId : void 0, hasError ? errorId : void 0);
144
+ const control = typeof children === "function" ? children({ describedById, hasError }) : children;
67
145
  return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.container, containerStyle], testID, children: [
68
- hasLabel ? /* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles.label, themeStyles.label], children: [
69
- label,
70
- " ",
71
- required ? (
72
- // The asterisk is decorative — the control's `aria-required` conveys "required" to
73
- // assistive tech, so a screen reader says "required" instead of "star".
74
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { "aria-hidden": true, accessibilityElementsHidden: true, importantForAccessibility: "no", style: themeStyles.requiredMark, children: "*" })
75
- ) : null
76
- ] }) : null,
146
+ hasLabel ? /* @__PURE__ */ jsxRuntime.jsx(
147
+ FieldLabel,
148
+ {
149
+ label: labelText,
150
+ marker,
151
+ optionalLabel,
152
+ optionalMarkStyle: [styles.optionalMark, themeStyles.optionalMark],
153
+ requiredMarkStyle: themeStyles.requiredMark,
154
+ style: [styles.label, resolveLabelVariantStyle(labelVariant), themeStyles.label, labelStyle]
155
+ }
156
+ ) : null,
77
157
  control,
158
+ hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles.hintText, themeStyles.hintText], children: hint }) : null,
78
159
  hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: errorId, role: "alert", style: [styles.errorText, themeStyles.errorText], children: error }) : null
79
160
  ] });
80
161
  };
162
+ var ACTIONS_GAP = 12;
163
+ var styles2 = reactNative.StyleSheet.create({
164
+ container: {
165
+ flexDirection: "row",
166
+ justifyContent: "flex-end",
167
+ gap: ACTIONS_GAP
168
+ }
169
+ });
170
+ var FormActions = ({
171
+ onSave,
172
+ onCancel,
173
+ saveLabel,
174
+ cancelLabel = "",
175
+ saveHint,
176
+ cancelHint,
177
+ saving = false,
178
+ saveDisabled = false,
179
+ containerStyle,
180
+ saveTestID = "save-button",
181
+ cancelTestID = "cancel-button",
182
+ testID
183
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles2.container, containerStyle], testID, children: [
184
+ typeof onCancel === "function" ? /* @__PURE__ */ jsxRuntime.jsx(
185
+ uiButtons.Button,
186
+ {
187
+ accessibilityHint: cancelHint ?? cancelLabel,
188
+ accessibilityLabel: cancelLabel,
189
+ disabled: saving,
190
+ label: cancelLabel,
191
+ testID: cancelTestID,
192
+ variant: "outline",
193
+ onPress: onCancel
194
+ }
195
+ ) : null,
196
+ /* @__PURE__ */ jsxRuntime.jsx(
197
+ uiButtons.Button,
198
+ {
199
+ accessibilityHint: saveHint ?? saveLabel,
200
+ accessibilityLabel: saveLabel,
201
+ disabled: saveDisabled,
202
+ label: saveLabel,
203
+ loading: saving,
204
+ testID: saveTestID,
205
+ variant: "primary",
206
+ onPress: onSave
207
+ }
208
+ )
209
+ ] });
81
210
  var IS_WEB = reactNative.Platform.OS === "web";
82
211
  var TRANSITION_PROPERTY = "border-color, background-color, box-shadow";
83
212
  var TRANSITION_DURATION = "0.14s";
@@ -137,7 +266,8 @@ function useThemedInput(options = {}) {
137
266
  const backgroundColor = isFocused ? colors.surface : colors.surfaceElevated;
138
267
  const base = { color: colors.text, borderColor, backgroundColor };
139
268
  if (!IS_WEB) return base;
140
- const ring = isFocused && !hasError ? `0 0 0 ${FOCUS_RING_WIDTH}px ${withAlpha(primary, FOCUS_RING_ALPHA)}` : "none";
269
+ const ringColor = hasError ? errorColor : primary;
270
+ const ring = isFocused ? `0 0 0 ${FOCUS_RING_WIDTH}px ${withAlpha(ringColor, FOCUS_RING_ALPHA)}` : "none";
141
271
  const webStyle = {
142
272
  transitionProperty: TRANSITION_PROPERTY,
143
273
  // Collapse the eased transition to instant when the user prefers reduced motion.
@@ -203,7 +333,7 @@ var INPUT_PADDING_V = 10;
203
333
  var INPUT_PADDING_H = 12;
204
334
  var INPUT_BORDER_RADIUS = 8;
205
335
  var INPUT_BORDER_WIDTH = 1;
206
- var styles2 = reactNative.StyleSheet.create({
336
+ var styles3 = reactNative.StyleSheet.create({
207
337
  input: {
208
338
  paddingVertical: INPUT_PADDING_V,
209
339
  paddingHorizontal: INPUT_PADDING_H,
@@ -225,7 +355,7 @@ var FormField = ({
225
355
  describedById,
226
356
  hasError,
227
357
  requiredField: required,
228
- style: styles2.input,
358
+ style: styles3.input,
229
359
  testID: "form-field-input",
230
360
  ...textInputProps
231
361
  }
@@ -246,6 +376,13 @@ var RGB_G_END = 4;
246
376
  var RGB_B_END = 6;
247
377
  var CHIP_HIT_SLOP = { top: 10, bottom: 10, left: 4, right: 4 };
248
378
  var CHIP_GUTTER = 8;
379
+ var DEFAULT_CHIP_TESTID_PREFIX = "chip-selector-chip";
380
+ var ON_BRAND_SCALE = "onBrand";
381
+ var MAIN_STEP = "500";
382
+ function onBrandInk(palette) {
383
+ const scales = palette;
384
+ return scales[ON_BRAND_SCALE]?.[MAIN_STEP] ?? WHITE_COLOR;
385
+ }
249
386
  function withAlpha2(hex, alpha) {
250
387
  const normalized = hex.replace("#", "");
251
388
  const isShort = normalized.length === HEX_SHORT_LENGTH2;
@@ -256,7 +393,7 @@ function withAlpha2(hex, alpha) {
256
393
  const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
257
394
  return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
258
395
  }
259
- var styles3 = reactNative.StyleSheet.create({
396
+ var styles4 = reactNative.StyleSheet.create({
260
397
  chipContainer: {
261
398
  flexDirection: "row",
262
399
  flexWrap: "wrap",
@@ -285,11 +422,23 @@ var styles3 = reactNative.StyleSheet.create({
285
422
  chipText: {},
286
423
  chipTextOutline: { fontSize: OUTLINE_FONT_SIZE }
287
424
  });
425
+ function chipIdentity(option, selected, config) {
426
+ return {
427
+ testID: `${config.prefix}-${String(option.value)}`,
428
+ // The English default is retained verbatim: erevna/katalogos assert the exact string
429
+ // `Selects Red`. Consumers that localize pass `optionAccessibilityHint`.
430
+ accessibilityHint: config.hint ?? `Selects ${option.label}`,
431
+ ariaPressed: config.multiple ? selected : void 0
432
+ };
433
+ }
288
434
  function OutlineChip({
289
435
  option,
290
436
  selected,
291
437
  disabled,
292
438
  colors,
439
+ testID,
440
+ accessibilityHint,
441
+ ariaPressed,
293
442
  onPress
294
443
  }) {
295
444
  const [hovered, setHovered] = React__default.default.useState(false);
@@ -300,18 +449,19 @@ function OutlineChip({
300
449
  return /* @__PURE__ */ jsxRuntime.jsx(
301
450
  reactNative.Pressable,
302
451
  {
303
- accessibilityHint: `Selects ${option.label}`,
452
+ accessibilityHint,
304
453
  accessibilityLabel: option.label,
305
454
  accessibilityRole: "button",
306
455
  accessibilityState: { selected, disabled },
456
+ "aria-pressed": ariaPressed,
307
457
  disabled,
308
458
  hitSlop: CHIP_HIT_SLOP,
309
- style: styles3.chipWrapper,
310
- testID: `chip-selector-chip-${String(option.value)}`,
459
+ style: styles4.chipWrapper,
460
+ testID,
311
461
  onHoverIn: () => setHovered(true),
312
462
  onHoverOut: () => setHovered(false),
313
463
  onPress,
314
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.chipText, styles3.chipTextOutline, { color: textColor }], children: option.label }) })
464
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.chipText, styles4.chipTextOutline, { color: textColor }], children: option.label }) })
315
465
  }
316
466
  );
317
467
  }
@@ -320,23 +470,27 @@ function SolidChip({
320
470
  selected,
321
471
  disabled,
322
472
  colors,
473
+ testID,
474
+ accessibilityHint,
475
+ ariaPressed,
323
476
  onPress
324
477
  }) {
325
478
  const backgroundColor = selected ? colors.primary : TRANSPARENT_COLOR;
326
- const textColor = selected ? WHITE_COLOR : colors.textStrong;
479
+ const textColor = selected ? colors.onPrimary : colors.textStrong;
327
480
  return /* @__PURE__ */ jsxRuntime.jsx(
328
481
  reactNative.TouchableOpacity,
329
482
  {
330
- accessibilityHint: `Selects ${option.label}`,
483
+ accessibilityHint,
331
484
  accessibilityLabel: option.label,
332
485
  accessibilityRole: "button",
333
486
  accessibilityState: { selected, disabled },
487
+ "aria-pressed": ariaPressed,
334
488
  disabled,
335
489
  hitSlop: CHIP_HIT_SLOP,
336
- style: styles3.chipWrapper,
337
- testID: `chip-selector-chip-${String(option.value)}`,
490
+ style: styles4.chipWrapper,
491
+ testID,
338
492
  onPress,
339
- children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.chipText, { color: textColor }], children: option.label }) })
493
+ children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles4.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.chipText, { color: textColor }], children: option.label }) })
340
494
  }
341
495
  );
342
496
  }
@@ -356,7 +510,9 @@ var ChipSelector = ({
356
510
  containerStyle,
357
511
  required = false,
358
512
  error,
359
- testID
513
+ testID,
514
+ chipTestIDPrefix = DEFAULT_CHIP_TESTID_PREFIX,
515
+ optionAccessibilityHint
360
516
  }) => {
361
517
  const { theme } = uiFeedback.useUi();
362
518
  const { colors, palette } = theme;
@@ -367,30 +523,37 @@ var ChipSelector = ({
367
523
  textStrong: colors.text,
368
524
  textMuted: colors.textSecondary,
369
525
  primary,
526
+ onPrimary: onBrandInk(palette),
370
527
  muted: colors.background,
371
528
  tint: withAlpha2(primary, OUTLINE_TINT_ALPHA)
372
529
  };
373
- }, [colors.border, colors.text, colors.textSecondary, colors.background, palette.primary]);
530
+ }, [colors.border, colors.text, colors.textSecondary, colors.background, palette]);
374
531
  function isSelected(optionValue) {
375
532
  if (multiple && Array.isArray(value))
376
533
  return value.includes(optionValue);
377
534
  return value === optionValue;
378
535
  }
379
536
  function renderChip(option) {
537
+ const selected = isSelected(option.value);
380
538
  const chipProps = {
381
539
  colors: chipColors,
382
540
  disabled,
383
541
  option,
384
- selected: isSelected(option.value),
542
+ selected,
543
+ ...chipIdentity(option, selected, {
544
+ prefix: chipTestIDPrefix,
545
+ hint: optionAccessibilityHint,
546
+ multiple
547
+ }),
385
548
  onPress: () => onChange(option.value)
386
549
  };
387
550
  const key = String(option.value);
388
551
  return variant === "outline" ? /* @__PURE__ */ jsxRuntime.jsx(OutlineChip, { ...chipProps }, key) : /* @__PURE__ */ jsxRuntime.jsx(SolidChip, { ...chipProps }, key);
389
552
  }
390
- return /* @__PURE__ */ jsxRuntime.jsx(Field, { containerStyle, error, label, required, testID, children: ({ describedById, hasError }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.chipContainer, ...groupA11yProps(describedById, hasError), children: options.map(renderChip) }) });
553
+ return /* @__PURE__ */ jsxRuntime.jsx(Field, { containerStyle, error, label, required, testID, children: ({ describedById, hasError }) => /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles4.chipContainer, ...groupA11yProps(describedById, hasError), children: options.map(renderChip) }) });
391
554
  };
392
555
  var DESCRIPTION_FONT_SIZE = 12;
393
- var styles4 = reactNative.StyleSheet.create({
556
+ var styles5 = reactNative.StyleSheet.create({
394
557
  container: {
395
558
  flexDirection: "row",
396
559
  justifyContent: "space-between",
@@ -430,13 +593,13 @@ var FormSwitch = ({
430
593
  reactNative.View,
431
594
  {
432
595
  style: [
433
- styles4.container,
596
+ styles5.container,
434
597
  containerStyle
435
598
  ],
436
599
  children: [
437
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.textColumn, children: [
438
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.label, themeStyles.label], children: label }),
439
- hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.description, themeStyles.description], children: description }) : null
600
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.textColumn, children: [
601
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.label, themeStyles.label], children: label }),
602
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.description, themeStyles.description], children: description }) : null
440
603
  ] }),
441
604
  /* @__PURE__ */ jsxRuntime.jsx(
442
605
  reactNative.Switch,
@@ -456,12 +619,12 @@ var FormSwitch = ({
456
619
  );
457
620
  };
458
621
  var ACTIVATION_KEYS = ["Enter", " ", "Spacebar"];
459
- var HINT_FONT_SIZE = 12;
622
+ var HINT_FONT_SIZE2 = 12;
460
623
  var BOX_SIZE = 20;
461
624
  var BOX_RADIUS = 5;
462
625
  var CHECK_FONT_SIZE = 14;
463
626
  var DISABLED_OPACITY = 0.5;
464
- var styles5 = reactNative.StyleSheet.create({
627
+ var styles6 = reactNative.StyleSheet.create({
465
628
  container: {
466
629
  flexDirection: "row",
467
630
  alignItems: "flex-start",
@@ -490,7 +653,7 @@ var styles5 = reactNative.StyleSheet.create({
490
653
  fontWeight: "600"
491
654
  },
492
655
  hint: {
493
- fontSize: HINT_FONT_SIZE,
656
+ fontSize: HINT_FONT_SIZE2,
494
657
  marginTop: 2
495
658
  }
496
659
  });
@@ -543,14 +706,14 @@ var FormCheckbox = ({
543
706
  disabled,
544
707
  onPress: toggle,
545
708
  role: "checkbox",
546
- style: [styles5.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null],
709
+ style: [styles6.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null],
547
710
  testID,
548
711
  ...keyboardProps,
549
712
  children: [
550
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.box, value ? themeStyles.boxOn : themeStyles.boxOff], children: value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null }),
551
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.textColumn, children: [
552
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.label, themeStyles.label], children: label }),
553
- hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.hint, themeStyles.hint], children: hintText }) : null
713
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles6.box, value ? themeStyles.boxOn : themeStyles.boxOff], children: value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null }),
714
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.textColumn, children: [
715
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.label, themeStyles.label], children: label }),
716
+ hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.hint, themeStyles.hint], children: hintText }) : null
554
717
  ] })
555
718
  ]
556
719
  }
@@ -558,7 +721,9 @@ var FormCheckbox = ({
558
721
  };
559
722
 
560
723
  exports.ChipSelector = ChipSelector;
724
+ exports.DEFAULT_OPTIONAL_LABEL = DEFAULT_OPTIONAL_LABEL;
561
725
  exports.Field = Field;
726
+ exports.FormActions = FormActions;
562
727
  exports.FormCheckbox = FormCheckbox;
563
728
  exports.FormField = FormField;
564
729
  exports.FormSwitch = FormSwitch;