@dloizides/ui-forms 1.18.6 → 1.19.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/CHANGELOG.md CHANGED
@@ -1,6 +1,10 @@
1
1
  # Changelog
2
2
 
3
- ## 1.18.5
3
+ ## 1.18.7
4
+
5
+ - Focused inputs draw the fleet focus ring (`@dloizides/design-tokens` 1.14 `FOCUS_RING`: 2 px solid outline, 2 px offset, contrast-checked colour; error colour when errored) instead of the 3 px 16% box-shadow halo (FOCUS-RING-1 "One focus ring across the shared kit").
6
+
7
+ ## 1.18.6
4
8
 
5
9
  **ChipSelector: a short chip (e.g. "All") is at least 44 px wide, not only 44 px tall (KEFI-FIT-1 "kefi-web fit and hit-box fixes").**
6
10
 
package/dist/index.d.mts CHANGED
@@ -470,6 +470,8 @@ interface UseThemedInputOptions {
470
470
  onFocus?: (e: FocusEvent) => void;
471
471
  /** Consumer blur handler — composed with the internal focus-state toggle. */
472
472
  onBlur?: (e: BlurEvent) => void;
473
+ /** `false` renders the read-only treatment: the recessed ground fill and the secondary ink. */
474
+ editable?: boolean;
473
475
  }
474
476
  interface ThemedInput {
475
477
  /** The themed input style for the current focus/hover state (memoised). Merge AFTER your box style. */
package/dist/index.d.ts CHANGED
@@ -470,6 +470,8 @@ interface UseThemedInputOptions {
470
470
  onFocus?: (e: FocusEvent) => void;
471
471
  /** Consumer blur handler — composed with the internal focus-state toggle. */
472
472
  onBlur?: (e: BlurEvent) => void;
473
+ /** `false` renders the read-only treatment: the recessed ground fill and the secondary ink. */
474
+ editable?: boolean;
473
475
  }
474
476
  interface ThemedInput {
475
477
  /** The themed input style for the current focus/hover state (memoised). Merge AFTER your box style. */
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 ?? "";
@@ -610,8 +615,7 @@ var IS_WEB5 = reactNative.Platform.OS === "web";
610
615
  var TRANSITION_PROPERTY = "border-color, background-color, box-shadow";
611
616
  var TRANSITION_DURATION = "0.14s";
612
617
  var TRANSITION_TIMING = "ease";
613
- var FOCUS_RING_WIDTH = 3;
614
- var FOCUS_RING_ALPHA = 0.16;
618
+ var NO_RING = { outlineWidth: 0 };
615
619
  var HOVER_BORDER_ALPHA = 0.22;
616
620
  var PLACEHOLDER_ALPHA = 0.6;
617
621
  var HEX_RADIX = 16;
@@ -636,9 +640,9 @@ function withAlpha(color, alpha) {
636
640
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
637
641
  }
638
642
  function useThemedInput(options = {}) {
639
- const { hasError = false, onFocus, onBlur } = options;
643
+ const { hasError = false, onFocus, onBlur, editable = true } = options;
640
644
  const { theme } = uiFeedback.useUi();
641
- const { colors, palette, semantic } = theme;
645
+ const { colors, palette } = theme;
642
646
  const [isFocused, setIsFocused] = React2.useState(false);
643
647
  const [isHovered, setIsHovered] = React2.useState(false);
644
648
  const handleFocus = React2.useCallback(
@@ -658,23 +662,23 @@ function useThemedInput(options = {}) {
658
662
  const handleHoverIn = React2.useCallback(() => setIsHovered(true), []);
659
663
  const handleHoverOut = React2.useCallback(() => setIsHovered(false), []);
660
664
  const primary = palette.primary["500"];
661
- const errorColor = semantic.error["500"];
665
+ const errorColor = fieldErrorInk(theme);
662
666
  const style = React2.useMemo(() => {
663
667
  const restBorder = hasError ? errorColor : colors.border;
664
668
  const focusBorder = hasError ? errorColor : primary;
665
669
  const borderColor = isFocused ? focusBorder : isHovered ? withAlpha(colors.text, HOVER_BORDER_ALPHA) : restBorder;
666
- const backgroundColor = isFocused ? colors.surface : colors.surfaceElevated;
667
- const base = { color: colors.text, borderColor, backgroundColor };
670
+ const editableFill = isFocused ? colors.surface : colors.surfaceElevated;
671
+ const backgroundColor = editable ? editableFill : colors.background;
672
+ const base = { color: editable ? colors.text : colors.textSecondary, borderColor, backgroundColor };
668
673
  if (!IS_WEB5) return base;
669
- const ringColor = hasError ? errorColor : primary;
670
- const ring = isFocused ? `0 0 0 ${FOCUS_RING_WIDTH}px ${withAlpha(ringColor, FOCUS_RING_ALPHA)}` : "none";
674
+ const ringColor = hasError ? errorColor : uiButtons.themeFocusRingColor(theme);
675
+ const ring = isFocused ? designTokens.focusRingOutline(ringColor) : NO_RING;
671
676
  const webStyle = {
672
677
  transitionProperty: TRANSITION_PROPERTY,
673
678
  // Collapse the eased transition to instant when the user prefers reduced motion.
674
679
  transitionDuration: prefersReducedMotion() ? "0s" : TRANSITION_DURATION,
675
680
  transitionTimingFunction: TRANSITION_TIMING,
676
- boxShadow: ring,
677
- outlineStyle: "none"
681
+ ...ring
678
682
  };
679
683
  return { ...base, ...webStyle };
680
684
  }, [
@@ -685,8 +689,12 @@ function useThemedInput(options = {}) {
685
689
  colors.border,
686
690
  colors.surface,
687
691
  colors.surfaceElevated,
692
+ colors.background,
693
+ colors.textSecondary,
694
+ editable,
688
695
  primary,
689
- errorColor
696
+ errorColor,
697
+ theme
690
698
  ]);
691
699
  const focusBind = React2.useMemo(() => ({ onFocus: handleFocus, onBlur: handleBlur }), [handleFocus, handleBlur]);
692
700
  const hoverBind = React2.useMemo(
@@ -736,7 +744,7 @@ var ThemedTextInput = React2__default.default.forwardRef(function ThemedTextInpu
736
744
  placeholderTextColor: themedPlaceholder,
737
745
  focusBind,
738
746
  hoverBind
739
- } = useThemedInput({ hasError, onFocus, onBlur });
747
+ } = useThemedInput({ hasError, onFocus, onBlur, editable: rest.editable });
740
748
  const webA11y = webFieldA11y({ describedById, hasError, required: requiredField });
741
749
  const boxStyle = unstyledBox ? null : controlStyles.input;
742
750
  const multilineStyle = rest.multiline === true && !unstyledBox ? boxStyles.multiline : null;
@@ -1589,7 +1597,7 @@ function TypeaheadControl({
1589
1597
  testID
1590
1598
  }) {
1591
1599
  const { theme } = uiFeedback.useUi();
1592
- const { colors, palette, semantic } = theme;
1600
+ const { colors, palette } = theme;
1593
1601
  const anchorRef = React2.useRef(null);
1594
1602
  const [isOpen, setIsOpen] = React2.useState(false);
1595
1603
  const exactPick = React2.useMemo(() => options.some((o) => o.label === value), [options, value]);
@@ -1637,7 +1645,7 @@ function TypeaheadControl({
1637
1645
  onFocus: () => setIsOpen(true),
1638
1646
  onBlur: handleBlur,
1639
1647
  onSubmitEditing: handleSubmit,
1640
- style: [controlStyles.input, { borderColor: hasError ? semantic.error["500"] : colors.border, backgroundColor: colors.surface, color: colors.text }],
1648
+ style: [controlStyles.input, { borderColor: hasError ? fieldErrorInk(theme) : colors.border, backgroundColor: colors.surface, color: colors.text }],
1641
1649
  testID: `${testID}-input`
1642
1650
  }
1643
1651
  ),
@@ -1655,7 +1663,7 @@ function TypeaheadControl({
1655
1663
  usePortal: true
1656
1664
  }
1657
1665
  ) : null,
1658
- hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { role: "alert", style: [controlStyles.error, { color: semantic.error["500"] }], testID: `${testID}-error`, children: error }) : null
1666
+ hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { role: "alert", style: [controlStyles.error, { color: fieldErrorInk(theme) }], testID: `${testID}-error`, children: error }) : null
1659
1667
  ] });
1660
1668
  }
1661
1669
  var WEB_DATE_PROPS = typeof document !== "undefined" ? { type: "date" } : {};