@dloizides/ui-forms 1.19.0 → 1.21.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.d.mts CHANGED
@@ -264,10 +264,41 @@ interface FormCellProps {
264
264
  basis?: number;
265
265
  /** `false` pins the cell to its basis instead of letting it absorb the row's slack. */
266
266
  grow?: boolean;
267
+ /** Puts an unlabelled control (a button) on the input line of the labelled cells beside it. */
268
+ alignToControl?: boolean;
267
269
  style?: StyleProp<ViewStyle>;
268
270
  testID?: string;
269
271
  }
270
- declare const FormCell: ({ children, minWidth, basis, grow, style, testID, }: FormCellProps) => React.ReactElement;
272
+ declare const FormCell: ({ children, minWidth, basis, grow, alignToControl, style, testID, }: FormCellProps) => React.ReactElement;
273
+
274
+ interface AlignToControlProps {
275
+ children: React.ReactNode;
276
+ labelVariant?: FieldLabelVariant;
277
+ spacing?: FieldSpacing;
278
+ style?: StyleProp<ViewStyle>;
279
+ testID?: string;
280
+ }
281
+ /** Puts a button or other unlabelled control on the input line of the labelled `Field`s beside it. */
282
+ declare const AlignToControl: ({ children, labelVariant, spacing, style, testID, }: AlignToControlProps) => React.ReactElement;
283
+
284
+ interface InlineFieldRowProps {
285
+ field: React.ReactNode;
286
+ action: React.ReactNode;
287
+ fieldMaxWidth: number;
288
+ inlineMinWidth?: number;
289
+ gap?: number;
290
+ testID?: string;
291
+ }
292
+ /** A labelled field and its action: stacked on phones, one row on desktop with the action on the input line. */
293
+ declare const InlineFieldRow: ({ field, action, fieldMaxWidth, inlineMinWidth, gap, testID, }: InlineFieldRowProps) => React.ReactElement;
294
+
295
+ declare const INLINE_FIELD_ROW_MIN_WIDTH = 1024;
296
+ interface InlineFieldRowLayout {
297
+ inline: boolean;
298
+ fieldMaxWidth: number | undefined;
299
+ }
300
+ /** Field and action share one row only at `inlineMinWidth` and wider; below it they stack. */
301
+ declare function inlineFieldRowLayout(windowWidth: number, fieldMaxWidth: number, inlineMinWidth?: number): InlineFieldRowLayout;
271
302
 
272
303
  /**
273
304
  * `FormSection` — a titled group of fields. The React answer to v1's `<fieldset>` / `<legend>`.
@@ -1031,4 +1062,4 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1031
1062
  */
1032
1063
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1033
1064
 
1034
- export { AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormSwitch, type FormSwitchProps, type GroupSelection, type RecentValues, SelectControl, type SelectControlProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type UseThemedInputOptions, controlStyles, groupAriaChecked, isUnmatched, resolveGroupSelection, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
1065
+ export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
package/dist/index.d.ts CHANGED
@@ -264,10 +264,41 @@ interface FormCellProps {
264
264
  basis?: number;
265
265
  /** `false` pins the cell to its basis instead of letting it absorb the row's slack. */
266
266
  grow?: boolean;
267
+ /** Puts an unlabelled control (a button) on the input line of the labelled cells beside it. */
268
+ alignToControl?: boolean;
267
269
  style?: StyleProp<ViewStyle>;
268
270
  testID?: string;
269
271
  }
270
- declare const FormCell: ({ children, minWidth, basis, grow, style, testID, }: FormCellProps) => React.ReactElement;
272
+ declare const FormCell: ({ children, minWidth, basis, grow, alignToControl, style, testID, }: FormCellProps) => React.ReactElement;
273
+
274
+ interface AlignToControlProps {
275
+ children: React.ReactNode;
276
+ labelVariant?: FieldLabelVariant;
277
+ spacing?: FieldSpacing;
278
+ style?: StyleProp<ViewStyle>;
279
+ testID?: string;
280
+ }
281
+ /** Puts a button or other unlabelled control on the input line of the labelled `Field`s beside it. */
282
+ declare const AlignToControl: ({ children, labelVariant, spacing, style, testID, }: AlignToControlProps) => React.ReactElement;
283
+
284
+ interface InlineFieldRowProps {
285
+ field: React.ReactNode;
286
+ action: React.ReactNode;
287
+ fieldMaxWidth: number;
288
+ inlineMinWidth?: number;
289
+ gap?: number;
290
+ testID?: string;
291
+ }
292
+ /** A labelled field and its action: stacked on phones, one row on desktop with the action on the input line. */
293
+ declare const InlineFieldRow: ({ field, action, fieldMaxWidth, inlineMinWidth, gap, testID, }: InlineFieldRowProps) => React.ReactElement;
294
+
295
+ declare const INLINE_FIELD_ROW_MIN_WIDTH = 1024;
296
+ interface InlineFieldRowLayout {
297
+ inline: boolean;
298
+ fieldMaxWidth: number | undefined;
299
+ }
300
+ /** Field and action share one row only at `inlineMinWidth` and wider; below it they stack. */
301
+ declare function inlineFieldRowLayout(windowWidth: number, fieldMaxWidth: number, inlineMinWidth?: number): InlineFieldRowLayout;
271
302
 
272
303
  /**
273
304
  * `FormSection` — a titled group of fields. The React answer to v1's `<fieldset>` / `<legend>`.
@@ -1031,4 +1062,4 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1031
1062
  */
1032
1063
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1033
1064
 
1034
- export { AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormSwitch, type FormSwitchProps, type GroupSelection, type RecentValues, SelectControl, type SelectControlProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type UseThemedInputOptions, controlStyles, groupAriaChecked, isUnmatched, resolveGroupSelection, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
1065
+ export { AlignToControl, type AlignToControlProps, AnchoredMenu, type AnchoredMenuColors, type AnchoredMenuProps, type ChipOption, ChipSelector, type ChipSelectorProps, type ChipSingleSelectRole, type ChipVariant, type ControlOption, DEFAULT_MAX_RECENTS, DEFAULT_OPTIONAL_LABEL, DEFAULT_TYPEAHEAD_MAX_SUGGESTIONS, DEFAULT_TYPEAHEAD_MIN_CHARS, DateRangeControl, type DateRangeControlProps, type DateRangeValue, Field, type FieldChildContext, type FieldChildren, type FieldLabelVariant, type FieldMarker, type FieldProps, type FieldSpacing, FormActions, type FormActionsProps, FormCell, type FormCellProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormGrid, type FormGridProps, FormSection, type FormSectionProps, FormSwitch, type FormSwitchProps, type GroupSelection, INLINE_FIELD_ROW_MIN_WIDTH, InlineFieldRow, type InlineFieldRowLayout, type InlineFieldRowProps, type RecentValues, SelectControl, type SelectControlProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, TypeaheadControl, type TypeaheadControlProps, type UseThemedInputOptions, controlStyles, groupAriaChecked, inlineFieldRowLayout, isUnmatched, resolveGroupSelection, suggestOptions, toggleGroupSelection, useRecentValues, useThemedInput };
package/dist/index.js CHANGED
@@ -253,6 +253,7 @@ var FORM_GRID_DEFAULT_MIN_WIDTH = 220;
253
253
  var FORM_GRID_DEFAULT_BASIS = 260;
254
254
  var styles2 = reactNative.StyleSheet.create({
255
255
  grid: {
256
+ alignItems: "flex-start",
256
257
  flexDirection: "row",
257
258
  flexWrap: "wrap"
258
259
  }
@@ -268,6 +269,36 @@ var FormGrid = ({
268
269
  const metrics = React2__default.default.useMemo(() => ({ minWidth, basis }), [minWidth, basis]);
269
270
  return /* @__PURE__ */ jsxRuntime.jsx(FormGridProvider, { value: metrics, children: /* @__PURE__ */ jsxRuntime.jsx(GapOwnedProvider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.grid, { gap }, style], testID, children }) }) });
270
271
  };
272
+ var LABEL_LINE_PLACEHOLDER = "\xA0";
273
+ var styles3 = reactNative.StyleSheet.create({
274
+ labelLine: {
275
+ userSelect: "none"
276
+ }
277
+ });
278
+ var AlignToControl = ({
279
+ children,
280
+ labelVariant,
281
+ spacing,
282
+ style,
283
+ testID
284
+ }) => {
285
+ const spacingStyles = fieldSpacingStyleSet(resolveFieldSpacing(spacing, useIsGapOwned()));
286
+ const labelLineTestID = testID !== void 0 ? `${testID}-label-line` : void 0;
287
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [spacingStyles.container, style], testID, children: [
288
+ /* @__PURE__ */ jsxRuntime.jsx(
289
+ reactNative.Text,
290
+ {
291
+ accessibilityElementsHidden: true,
292
+ "aria-hidden": true,
293
+ importantForAccessibility: "no",
294
+ style: [spacingStyles.label, resolveLabelVariantStyle(labelVariant), styles3.labelLine],
295
+ testID: labelLineTestID,
296
+ children: LABEL_LINE_PLACEHOLDER
297
+ }
298
+ ),
299
+ children
300
+ ] });
301
+ };
271
302
  var GROW = 1;
272
303
  var NO_GROW = 0;
273
304
  var FormCell = ({
@@ -275,6 +306,7 @@ var FormCell = ({
275
306
  minWidth,
276
307
  basis,
277
308
  grow = true,
309
+ alignToControl = false,
278
310
  style,
279
311
  testID
280
312
  }) => {
@@ -286,11 +318,54 @@ var FormCell = ({
286
318
  flexBasis: resolvedBasis,
287
319
  flexGrow: grow ? GROW : NO_GROW
288
320
  };
289
- return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [cellStyle, style], testID, children });
321
+ return /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [cellStyle, style], testID, children: alignToControl ? /* @__PURE__ */ jsxRuntime.jsx(AlignToControl, { children }) : children });
322
+ };
323
+
324
+ // src/InlineFieldRow/inlineFieldRowLayout.ts
325
+ var INLINE_FIELD_ROW_MIN_WIDTH = 1024;
326
+ function inlineFieldRowLayout(windowWidth, fieldMaxWidth, inlineMinWidth = INLINE_FIELD_ROW_MIN_WIDTH) {
327
+ const inline = windowWidth >= inlineMinWidth;
328
+ return { inline, fieldMaxWidth: inline ? fieldMaxWidth : void 0 };
329
+ }
330
+ var styles4 = reactNative.StyleSheet.create({
331
+ action: {
332
+ flexShrink: 0
333
+ },
334
+ field: {
335
+ flexBasis: 0,
336
+ flexGrow: 1,
337
+ flexShrink: 1
338
+ },
339
+ row: {
340
+ alignItems: "flex-start",
341
+ flexDirection: "row"
342
+ }
343
+ });
344
+ var InlineFieldRow = ({
345
+ field,
346
+ action,
347
+ fieldMaxWidth,
348
+ inlineMinWidth,
349
+ gap = FORM_GRID_DEFAULT_GAP,
350
+ testID
351
+ }) => {
352
+ const { width } = reactNative.useWindowDimensions();
353
+ const layout = inlineFieldRowLayout(width, fieldMaxWidth, inlineMinWidth);
354
+ const rowStyle = React2.useMemo(() => [styles4.row, { gap }], [gap]);
355
+ const fieldStyle = React2.useMemo(() => [styles4.field, { maxWidth: layout.fieldMaxWidth }], [layout.fieldMaxWidth]);
356
+ if (!layout.inline)
357
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
358
+ field,
359
+ action
360
+ ] });
361
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: rowStyle, testID, children: [
362
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: fieldStyle, children: field }),
363
+ /* @__PURE__ */ jsxRuntime.jsx(AlignToControl, { style: styles4.action, children: action })
364
+ ] });
290
365
  };
291
366
  var SECTION_GAP = 10;
292
367
  var DESCRIPTION_FONT_SIZE = 12;
293
- var styles3 = reactNative.StyleSheet.create({
368
+ var styles5 = reactNative.StyleSheet.create({
294
369
  section: {
295
370
  gap: SECTION_GAP
296
371
  },
@@ -325,7 +400,7 @@ var FormSection = ({
325
400
  // The section spaces its children with `gap`, so it owns their vertical rhythm exactly as a
326
401
  // `FormGrid` owns a row's — without this a `Field` placed directly in a section would stack its
327
402
  // 16px margin on the section's gap and recreate the F3 bug one level up.
328
- /* @__PURE__ */ jsxRuntime.jsx(GapOwnedProvider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { role: "group", style: [styles3.section, style], testID, ...a11y, children: [
403
+ /* @__PURE__ */ jsxRuntime.jsx(GapOwnedProvider, { value: true, children: /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { role: "group", style: [styles5.section, style], testID, ...a11y, children: [
329
404
  hasTitle ? /* @__PURE__ */ jsxRuntime.jsx(
330
405
  reactNative.Text,
331
406
  {
@@ -334,13 +409,13 @@ var FormSection = ({
334
409
  children: title
335
410
  }
336
411
  ) : null,
337
- hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.description, { color: colors.textSecondary }], children: description }) : null,
412
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.description, { color: colors.textSecondary }], children: description }) : null,
338
413
  children
339
414
  ] }) })
340
415
  );
341
416
  };
342
417
  var ACTIONS_GAP = 12;
343
- var styles4 = reactNative.StyleSheet.create({
418
+ var styles6 = reactNative.StyleSheet.create({
344
419
  container: {
345
420
  flexDirection: "row",
346
421
  justifyContent: "flex-end",
@@ -360,7 +435,7 @@ var FormActions = ({
360
435
  saveTestID = "save-button",
361
436
  cancelTestID = "cancel-button",
362
437
  testID
363
- }) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles4.container, containerStyle], testID, children: [
438
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles6.container, containerStyle], testID, children: [
364
439
  typeof onCancel === "function" ? /* @__PURE__ */ jsxRuntime.jsx(
365
440
  uiButtons.Button,
366
441
  {
@@ -1180,7 +1255,7 @@ function chipIdentity(option, selected, config) {
1180
1255
  ariaChecked: isRadio ? selected : void 0
1181
1256
  };
1182
1257
  }
1183
- var styles5 = reactNative.StyleSheet.create({
1258
+ var styles7 = reactNative.StyleSheet.create({
1184
1259
  chipContainer: {
1185
1260
  flexDirection: "row",
1186
1261
  flexWrap: "wrap",
@@ -1266,7 +1341,7 @@ var ChipSelector = ({
1266
1341
  reactNative.View,
1267
1342
  {
1268
1343
  accessibilityRole: isRadioGroup ? "radiogroup" : void 0,
1269
- style: styles5.chipContainer,
1344
+ style: styles7.chipContainer,
1270
1345
  ...webFieldA11y({ describedById, hasError }),
1271
1346
  ...radio.groupProps,
1272
1347
  children: options.map(renderChip)
@@ -1276,7 +1351,7 @@ var ChipSelector = ({
1276
1351
  );
1277
1352
  };
1278
1353
  var DESCRIPTION_FONT_SIZE2 = 12;
1279
- var styles6 = reactNative.StyleSheet.create({
1354
+ var styles8 = reactNative.StyleSheet.create({
1280
1355
  container: {
1281
1356
  flexDirection: "row",
1282
1357
  justifyContent: "space-between",
@@ -1337,15 +1412,15 @@ var FormSwitch = ({
1337
1412
  accessible: false,
1338
1413
  disabled,
1339
1414
  onPress: toggle,
1340
- style: [styles6.container, containerStyle],
1415
+ style: [styles8.container, containerStyle],
1341
1416
  tabIndex: -1,
1342
1417
  testID: `${testID}-row`,
1343
1418
  children: [
1344
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.textColumn, children: [
1345
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.label, themeStyles.label], children: label }),
1346
- hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.description, themeStyles.description], children: description }) : null
1419
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles8.textColumn, children: [
1420
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.label, themeStyles.label], children: label }),
1421
+ hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles8.description, themeStyles.description], children: description }) : null
1347
1422
  ] }),
1348
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { pointerEvents: "none", style: styles6.switchSlot, testID: `${testID}-hitbox`, children: /* @__PURE__ */ jsxRuntime.jsx(
1423
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { pointerEvents: "none", style: styles8.switchSlot, testID: `${testID}-hitbox`, children: /* @__PURE__ */ jsxRuntime.jsx(
1349
1424
  reactNative.Switch,
1350
1425
  {
1351
1426
  accessibilityHint: accessibilityHint ?? label,
@@ -1362,13 +1437,19 @@ var FormSwitch = ({
1362
1437
  )
1363
1438
  );
1364
1439
  };
1440
+
1441
+ // src/FormCheckbox/checkboxColors.ts
1442
+ var checkboxBoxColors = (colors, brand, checked) => checked ? { backgroundColor: brand, borderColor: brand } : { backgroundColor: "transparent", borderColor: colors.textSecondary };
1365
1443
  var ACTIVATION_KEYS = ["Enter", " ", "Spacebar"];
1366
1444
  var HINT_FONT_SIZE2 = 12;
1367
1445
  var BOX_SIZE = 20;
1368
1446
  var BOX_RADIUS = 5;
1369
1447
  var CHECK_FONT_SIZE = 14;
1370
1448
  var DISABLED_OPACITY = 0.5;
1371
- var styles7 = reactNative.StyleSheet.create({
1449
+ var FOCUS_RING_WIDTH = 2;
1450
+ var WEB_NO_DEFAULT_OUTLINE = { outlineStyle: "none" };
1451
+ var FOCUS_RING_INSET = -6;
1452
+ var styles9 = reactNative.StyleSheet.create({
1372
1453
  container: {
1373
1454
  flexDirection: "row",
1374
1455
  alignItems: "flex-start",
@@ -1392,6 +1473,15 @@ var styles7 = reactNative.StyleSheet.create({
1392
1473
  // Nudge the box to sit on the label's first text line.
1393
1474
  marginTop: 1
1394
1475
  },
1476
+ focusRing: {
1477
+ position: "absolute",
1478
+ top: FOCUS_RING_INSET,
1479
+ left: FOCUS_RING_INSET,
1480
+ right: FOCUS_RING_INSET,
1481
+ bottom: FOCUS_RING_INSET,
1482
+ borderWidth: FOCUS_RING_WIDTH,
1483
+ borderRadius: BOX_RADIUS - FOCUS_RING_INSET
1484
+ },
1395
1485
  check: {
1396
1486
  fontSize: CHECK_FONT_SIZE,
1397
1487
  fontWeight: "700",
@@ -1427,13 +1517,15 @@ var FormCheckbox = ({
1427
1517
  const hintText = typeof hint === "string" && hint !== "" ? hint : description;
1428
1518
  const hasHint = typeof hintText === "string" && hintText !== "";
1429
1519
  const { hintId } = useFieldIds();
1520
+ const [focused, setFocused] = React2__default.default.useState(false);
1430
1521
  const themeStyles = React2__default.default.useMemo(() => {
1431
- const boxOn = { backgroundColor: brand, borderColor: brand };
1432
- const boxOff = { backgroundColor: "transparent", borderColor: colors.border };
1522
+ const boxOn = checkboxBoxColors(colors, brand, true);
1523
+ const boxOff = checkboxBoxColors(colors, brand, false);
1524
+ const ring = { borderColor: brand };
1433
1525
  const labelStyle = { color: colors.text };
1434
1526
  const hintStyle = { color: colors.textSecondary };
1435
- return { boxOn, boxOff, label: labelStyle, hint: hintStyle };
1436
- }, [brand, colors.border, colors.text, colors.textSecondary]);
1527
+ return { boxOn, boxOff, ring, label: labelStyle, hint: hintStyle };
1528
+ }, [brand, colors]);
1437
1529
  const toggle = () => {
1438
1530
  const next = !value;
1439
1531
  if (onValueChange) onValueChange(next);
@@ -1457,21 +1549,27 @@ var FormCheckbox = ({
1457
1549
  "aria-checked": value,
1458
1550
  "aria-describedby": hasHint ? hintId : void 0,
1459
1551
  disabled,
1552
+ onBlur: () => setFocused(false),
1553
+ onFocus: () => setFocused(true),
1460
1554
  onPress: toggle,
1461
1555
  role: "checkbox",
1462
1556
  style: [
1463
- styles7.container,
1464
- hasHint ? null : styles7.centered,
1557
+ styles9.container,
1558
+ hasHint ? null : styles9.centered,
1465
1559
  containerStyle,
1466
- disabled ? { opacity: DISABLED_OPACITY } : null
1560
+ disabled ? { opacity: DISABLED_OPACITY } : null,
1561
+ reactNative.Platform.OS === "web" ? WEB_NO_DEFAULT_OUTLINE : null
1467
1562
  ],
1468
1563
  testID,
1469
1564
  ...keyboardProps,
1470
1565
  children: [
1471
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles7.box, value ? themeStyles.boxOn : themeStyles.boxOff], children: value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null }),
1472
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.textColumn, children: [
1473
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.label, themeStyles.label], children: label }),
1474
- hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles7.hint, themeStyles.hint], children: hintText }) : null
1566
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles9.box, value ? themeStyles.boxOn : themeStyles.boxOff], testID: `${testID}-box`, children: [
1567
+ focused ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { pointerEvents: "none", style: [styles9.focusRing, themeStyles.ring], testID: `${testID}-focus-ring` }) : null,
1568
+ value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null
1569
+ ] }),
1570
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.textColumn, children: [
1571
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.label, themeStyles.label], children: label }),
1572
+ hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles9.hint, themeStyles.hint], children: hintText }) : null
1475
1573
  ] })
1476
1574
  ]
1477
1575
  }
@@ -1763,6 +1861,7 @@ function toggleGroupSelection(selected, groupKeys, order) {
1763
1861
  return order === void 0 ? merged : order.filter((key) => merged.includes(key));
1764
1862
  }
1765
1863
 
1864
+ exports.AlignToControl = AlignToControl;
1766
1865
  exports.AnchoredMenu = AnchoredMenu;
1767
1866
  exports.ChipSelector = ChipSelector;
1768
1867
  exports.DEFAULT_MAX_RECENTS = DEFAULT_MAX_RECENTS;
@@ -1778,11 +1877,14 @@ exports.FormField = FormField;
1778
1877
  exports.FormGrid = FormGrid;
1779
1878
  exports.FormSection = FormSection;
1780
1879
  exports.FormSwitch = FormSwitch;
1880
+ exports.INLINE_FIELD_ROW_MIN_WIDTH = INLINE_FIELD_ROW_MIN_WIDTH;
1881
+ exports.InlineFieldRow = InlineFieldRow;
1781
1882
  exports.SelectControl = SelectControl;
1782
1883
  exports.ThemedTextInput = ThemedTextInput;
1783
1884
  exports.TypeaheadControl = TypeaheadControl;
1784
1885
  exports.controlStyles = controlStyles;
1785
1886
  exports.groupAriaChecked = groupAriaChecked;
1887
+ exports.inlineFieldRowLayout = inlineFieldRowLayout;
1786
1888
  exports.isUnmatched = isUnmatched;
1787
1889
  exports.resolveGroupSelection = resolveGroupSelection;
1788
1890
  exports.suggestOptions = suggestOptions;