@dloizides/ui-forms 1.18.7 → 1.20.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>`.
@@ -470,6 +501,8 @@ interface UseThemedInputOptions {
470
501
  onFocus?: (e: FocusEvent) => void;
471
502
  /** Consumer blur handler — composed with the internal focus-state toggle. */
472
503
  onBlur?: (e: BlurEvent) => void;
504
+ /** `false` renders the read-only treatment: the recessed ground fill and the secondary ink. */
505
+ editable?: boolean;
473
506
  }
474
507
  interface ThemedInput {
475
508
  /** The themed input style for the current focus/hover state (memoised). Merge AFTER your box style. */
@@ -1029,4 +1062,4 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1029
1062
  */
1030
1063
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1031
1064
 
1032
- 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>`.
@@ -470,6 +501,8 @@ interface UseThemedInputOptions {
470
501
  onFocus?: (e: FocusEvent) => void;
471
502
  /** Consumer blur handler — composed with the internal focus-state toggle. */
472
503
  onBlur?: (e: BlurEvent) => void;
504
+ /** `false` renders the read-only treatment: the recessed ground fill and the secondary ink. */
505
+ editable?: boolean;
473
506
  }
474
507
  interface ThemedInput {
475
508
  /** The themed input style for the current focus/hover state (memoised). Merge AFTER your box style. */
@@ -1029,4 +1062,4 @@ declare function groupAriaChecked(state: GroupSelection): boolean | 'mixed';
1029
1062
  */
1030
1063
  declare function toggleGroupSelection<T>(selected: readonly T[], groupKeys: readonly T[], order?: readonly T[]): T[];
1031
1064
 
1032
- 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
@@ -4,10 +4,10 @@ var React2 = 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 designTokens = require('@dloizides/design-tokens');
7
8
  var uiButtons = require('@dloizides/ui-buttons');
8
9
  var reactDom = require('react-dom');
9
10
  var a11y = require('@dloizides/a11y');
10
- var designTokens = require('@dloizides/design-tokens');
11
11
 
12
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
13
 
@@ -146,6 +146,11 @@ function useFormGridMetrics() {
146
146
  function useIsGapOwned() {
147
147
  return React2__default.default.useContext(GapOwnedContext);
148
148
  }
149
+ var ERROR_LIGHT_STEPS = ["500", "600", "700"];
150
+ var ERROR_DARK_STEPS = ["300", "200", "400", "100", "500"];
151
+ function fieldErrorInk(theme) {
152
+ return designTokens.readableScaleInk({ ...theme.semantic.error }, theme.colors.surface, ERROR_LIGHT_STEPS, ERROR_DARK_STEPS);
153
+ }
149
154
  var ERROR_FONT_SIZE = 12;
150
155
  var HINT_FONT_SIZE = 12;
151
156
  var OPTIONAL_MARK_FONT_WEIGHT = "400";
@@ -201,8 +206,8 @@ var Field = ({
201
206
  const { theme } = uiFeedback.useUi();
202
207
  const gapOwned = useIsGapOwned();
203
208
  const spacingStyles = fieldSpacingStyleSet(resolveFieldSpacing(spacing, gapOwned));
204
- const { colors, semantic } = theme;
205
- const errorColor = semantic.error["500"];
209
+ const { colors } = theme;
210
+ const errorColor = fieldErrorInk(theme);
206
211
  const hasError = hasFieldError(error);
207
212
  const hasHint = isPresent(hint);
208
213
  const labelText = label ?? "";
@@ -248,6 +253,7 @@ var FORM_GRID_DEFAULT_MIN_WIDTH = 220;
248
253
  var FORM_GRID_DEFAULT_BASIS = 260;
249
254
  var styles2 = reactNative.StyleSheet.create({
250
255
  grid: {
256
+ alignItems: "flex-start",
251
257
  flexDirection: "row",
252
258
  flexWrap: "wrap"
253
259
  }
@@ -263,6 +269,36 @@ var FormGrid = ({
263
269
  const metrics = React2__default.default.useMemo(() => ({ minWidth, basis }), [minWidth, basis]);
264
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 }) }) });
265
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
+ };
266
302
  var GROW = 1;
267
303
  var NO_GROW = 0;
268
304
  var FormCell = ({
@@ -270,6 +306,7 @@ var FormCell = ({
270
306
  minWidth,
271
307
  basis,
272
308
  grow = true,
309
+ alignToControl = false,
273
310
  style,
274
311
  testID
275
312
  }) => {
@@ -281,11 +318,54 @@ var FormCell = ({
281
318
  flexBasis: resolvedBasis,
282
319
  flexGrow: grow ? GROW : NO_GROW
283
320
  };
284
- 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
+ ] });
285
365
  };
286
366
  var SECTION_GAP = 10;
287
367
  var DESCRIPTION_FONT_SIZE = 12;
288
- var styles3 = reactNative.StyleSheet.create({
368
+ var styles5 = reactNative.StyleSheet.create({
289
369
  section: {
290
370
  gap: SECTION_GAP
291
371
  },
@@ -320,7 +400,7 @@ var FormSection = ({
320
400
  // The section spaces its children with `gap`, so it owns their vertical rhythm exactly as a
321
401
  // `FormGrid` owns a row's — without this a `Field` placed directly in a section would stack its
322
402
  // 16px margin on the section's gap and recreate the F3 bug one level up.
323
- /* @__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: [
324
404
  hasTitle ? /* @__PURE__ */ jsxRuntime.jsx(
325
405
  reactNative.Text,
326
406
  {
@@ -329,13 +409,13 @@ var FormSection = ({
329
409
  children: title
330
410
  }
331
411
  ) : null,
332
- 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,
333
413
  children
334
414
  ] }) })
335
415
  );
336
416
  };
337
417
  var ACTIONS_GAP = 12;
338
- var styles4 = reactNative.StyleSheet.create({
418
+ var styles6 = reactNative.StyleSheet.create({
339
419
  container: {
340
420
  flexDirection: "row",
341
421
  justifyContent: "flex-end",
@@ -355,7 +435,7 @@ var FormActions = ({
355
435
  saveTestID = "save-button",
356
436
  cancelTestID = "cancel-button",
357
437
  testID
358
- }) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles4.container, containerStyle], testID, children: [
438
+ }) => /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles6.container, containerStyle], testID, children: [
359
439
  typeof onCancel === "function" ? /* @__PURE__ */ jsxRuntime.jsx(
360
440
  uiButtons.Button,
361
441
  {
@@ -635,9 +715,9 @@ function withAlpha(color, alpha) {
635
715
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
636
716
  }
637
717
  function useThemedInput(options = {}) {
638
- const { hasError = false, onFocus, onBlur } = options;
718
+ const { hasError = false, onFocus, onBlur, editable = true } = options;
639
719
  const { theme } = uiFeedback.useUi();
640
- const { colors, palette, semantic } = theme;
720
+ const { colors, palette } = theme;
641
721
  const [isFocused, setIsFocused] = React2.useState(false);
642
722
  const [isHovered, setIsHovered] = React2.useState(false);
643
723
  const handleFocus = React2.useCallback(
@@ -657,13 +737,14 @@ function useThemedInput(options = {}) {
657
737
  const handleHoverIn = React2.useCallback(() => setIsHovered(true), []);
658
738
  const handleHoverOut = React2.useCallback(() => setIsHovered(false), []);
659
739
  const primary = palette.primary["500"];
660
- const errorColor = semantic.error["500"];
740
+ const errorColor = fieldErrorInk(theme);
661
741
  const style = React2.useMemo(() => {
662
742
  const restBorder = hasError ? errorColor : colors.border;
663
743
  const focusBorder = hasError ? errorColor : primary;
664
744
  const borderColor = isFocused ? focusBorder : isHovered ? withAlpha(colors.text, HOVER_BORDER_ALPHA) : restBorder;
665
- const backgroundColor = isFocused ? colors.surface : colors.surfaceElevated;
666
- const base = { color: colors.text, borderColor, backgroundColor };
745
+ const editableFill = isFocused ? colors.surface : colors.surfaceElevated;
746
+ const backgroundColor = editable ? editableFill : colors.background;
747
+ const base = { color: editable ? colors.text : colors.textSecondary, borderColor, backgroundColor };
667
748
  if (!IS_WEB5) return base;
668
749
  const ringColor = hasError ? errorColor : uiButtons.themeFocusRingColor(theme);
669
750
  const ring = isFocused ? designTokens.focusRingOutline(ringColor) : NO_RING;
@@ -683,6 +764,9 @@ function useThemedInput(options = {}) {
683
764
  colors.border,
684
765
  colors.surface,
685
766
  colors.surfaceElevated,
767
+ colors.background,
768
+ colors.textSecondary,
769
+ editable,
686
770
  primary,
687
771
  errorColor,
688
772
  theme
@@ -735,7 +819,7 @@ var ThemedTextInput = React2__default.default.forwardRef(function ThemedTextInpu
735
819
  placeholderTextColor: themedPlaceholder,
736
820
  focusBind,
737
821
  hoverBind
738
- } = useThemedInput({ hasError, onFocus, onBlur });
822
+ } = useThemedInput({ hasError, onFocus, onBlur, editable: rest.editable });
739
823
  const webA11y = webFieldA11y({ describedById, hasError, required: requiredField });
740
824
  const boxStyle = unstyledBox ? null : controlStyles.input;
741
825
  const multilineStyle = rest.multiline === true && !unstyledBox ? boxStyles.multiline : null;
@@ -1171,7 +1255,7 @@ function chipIdentity(option, selected, config) {
1171
1255
  ariaChecked: isRadio ? selected : void 0
1172
1256
  };
1173
1257
  }
1174
- var styles5 = reactNative.StyleSheet.create({
1258
+ var styles7 = reactNative.StyleSheet.create({
1175
1259
  chipContainer: {
1176
1260
  flexDirection: "row",
1177
1261
  flexWrap: "wrap",
@@ -1257,7 +1341,7 @@ var ChipSelector = ({
1257
1341
  reactNative.View,
1258
1342
  {
1259
1343
  accessibilityRole: isRadioGroup ? "radiogroup" : void 0,
1260
- style: styles5.chipContainer,
1344
+ style: styles7.chipContainer,
1261
1345
  ...webFieldA11y({ describedById, hasError }),
1262
1346
  ...radio.groupProps,
1263
1347
  children: options.map(renderChip)
@@ -1267,7 +1351,7 @@ var ChipSelector = ({
1267
1351
  );
1268
1352
  };
1269
1353
  var DESCRIPTION_FONT_SIZE2 = 12;
1270
- var styles6 = reactNative.StyleSheet.create({
1354
+ var styles8 = reactNative.StyleSheet.create({
1271
1355
  container: {
1272
1356
  flexDirection: "row",
1273
1357
  justifyContent: "space-between",
@@ -1328,15 +1412,15 @@ var FormSwitch = ({
1328
1412
  accessible: false,
1329
1413
  disabled,
1330
1414
  onPress: toggle,
1331
- style: [styles6.container, containerStyle],
1415
+ style: [styles8.container, containerStyle],
1332
1416
  tabIndex: -1,
1333
1417
  testID: `${testID}-row`,
1334
1418
  children: [
1335
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles6.textColumn, children: [
1336
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles6.label, themeStyles.label], children: label }),
1337
- 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
1338
1422
  ] }),
1339
- /* @__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(
1340
1424
  reactNative.Switch,
1341
1425
  {
1342
1426
  accessibilityHint: accessibilityHint ?? label,
@@ -1359,7 +1443,7 @@ var BOX_SIZE = 20;
1359
1443
  var BOX_RADIUS = 5;
1360
1444
  var CHECK_FONT_SIZE = 14;
1361
1445
  var DISABLED_OPACITY = 0.5;
1362
- var styles7 = reactNative.StyleSheet.create({
1446
+ var styles9 = reactNative.StyleSheet.create({
1363
1447
  container: {
1364
1448
  flexDirection: "row",
1365
1449
  alignItems: "flex-start",
@@ -1451,18 +1535,18 @@ var FormCheckbox = ({
1451
1535
  onPress: toggle,
1452
1536
  role: "checkbox",
1453
1537
  style: [
1454
- styles7.container,
1455
- hasHint ? null : styles7.centered,
1538
+ styles9.container,
1539
+ hasHint ? null : styles9.centered,
1456
1540
  containerStyle,
1457
1541
  disabled ? { opacity: DISABLED_OPACITY } : null
1458
1542
  ],
1459
1543
  testID,
1460
1544
  ...keyboardProps,
1461
1545
  children: [
1462
- /* @__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 }),
1463
- /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles7.textColumn, children: [
1464
- /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles7.label, themeStyles.label], children: label }),
1465
- hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles7.hint, themeStyles.hint], children: hintText }) : null
1546
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles9.box, value ? themeStyles.boxOn : themeStyles.boxOff], children: value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null }),
1547
+ /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles9.textColumn, children: [
1548
+ /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles9.label, themeStyles.label], children: label }),
1549
+ hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: hintId, style: [styles9.hint, themeStyles.hint], children: hintText }) : null
1466
1550
  ] })
1467
1551
  ]
1468
1552
  }
@@ -1588,7 +1672,7 @@ function TypeaheadControl({
1588
1672
  testID
1589
1673
  }) {
1590
1674
  const { theme } = uiFeedback.useUi();
1591
- const { colors, palette, semantic } = theme;
1675
+ const { colors, palette } = theme;
1592
1676
  const anchorRef = React2.useRef(null);
1593
1677
  const [isOpen, setIsOpen] = React2.useState(false);
1594
1678
  const exactPick = React2.useMemo(() => options.some((o) => o.label === value), [options, value]);
@@ -1636,7 +1720,7 @@ function TypeaheadControl({
1636
1720
  onFocus: () => setIsOpen(true),
1637
1721
  onBlur: handleBlur,
1638
1722
  onSubmitEditing: handleSubmit,
1639
- style: [controlStyles.input, { borderColor: hasError ? semantic.error["500"] : colors.border, backgroundColor: colors.surface, color: colors.text }],
1723
+ style: [controlStyles.input, { borderColor: hasError ? fieldErrorInk(theme) : colors.border, backgroundColor: colors.surface, color: colors.text }],
1640
1724
  testID: `${testID}-input`
1641
1725
  }
1642
1726
  ),
@@ -1654,7 +1738,7 @@ function TypeaheadControl({
1654
1738
  usePortal: true
1655
1739
  }
1656
1740
  ) : null,
1657
- hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { role: "alert", style: [controlStyles.error, { color: semantic.error["500"] }], testID: `${testID}-error`, children: error }) : null
1741
+ hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { role: "alert", style: [controlStyles.error, { color: fieldErrorInk(theme) }], testID: `${testID}-error`, children: error }) : null
1658
1742
  ] });
1659
1743
  }
1660
1744
  var WEB_DATE_PROPS = typeof document !== "undefined" ? { type: "date" } : {};
@@ -1754,6 +1838,7 @@ function toggleGroupSelection(selected, groupKeys, order) {
1754
1838
  return order === void 0 ? merged : order.filter((key) => merged.includes(key));
1755
1839
  }
1756
1840
 
1841
+ exports.AlignToControl = AlignToControl;
1757
1842
  exports.AnchoredMenu = AnchoredMenu;
1758
1843
  exports.ChipSelector = ChipSelector;
1759
1844
  exports.DEFAULT_MAX_RECENTS = DEFAULT_MAX_RECENTS;
@@ -1769,11 +1854,14 @@ exports.FormField = FormField;
1769
1854
  exports.FormGrid = FormGrid;
1770
1855
  exports.FormSection = FormSection;
1771
1856
  exports.FormSwitch = FormSwitch;
1857
+ exports.INLINE_FIELD_ROW_MIN_WIDTH = INLINE_FIELD_ROW_MIN_WIDTH;
1858
+ exports.InlineFieldRow = InlineFieldRow;
1772
1859
  exports.SelectControl = SelectControl;
1773
1860
  exports.ThemedTextInput = ThemedTextInput;
1774
1861
  exports.TypeaheadControl = TypeaheadControl;
1775
1862
  exports.controlStyles = controlStyles;
1776
1863
  exports.groupAriaChecked = groupAriaChecked;
1864
+ exports.inlineFieldRowLayout = inlineFieldRowLayout;
1777
1865
  exports.isUnmatched = isUnmatched;
1778
1866
  exports.resolveGroupSelection = resolveGroupSelection;
1779
1867
  exports.suggestOptions = suggestOptions;