@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/dist/index.mjs CHANGED
@@ -2,10 +2,10 @@ import React2, { useState, useCallback, useMemo, useEffect, useRef, useLayoutEff
2
2
  import { Platform, StyleSheet, TextInput, View, Text, ScrollView, Pressable, Switch, TouchableOpacity } from 'react-native';
3
3
  import { useUi } from '@dloizides/ui-feedback';
4
4
  import { jsx, jsxs } from 'react/jsx-runtime';
5
- import { Button } from '@dloizides/ui-buttons';
5
+ import { Z_INDEX, focusRingOutline, readableScaleInk } from '@dloizides/design-tokens';
6
+ import { themeFocusRingColor, Button } from '@dloizides/ui-buttons';
6
7
  import { createPortal } from 'react-dom';
7
8
  import { MIN_TOUCH_TARGET_PX } from '@dloizides/a11y';
8
- import { Z_INDEX } from '@dloizides/design-tokens';
9
9
 
10
10
  // src/Field/Field.tsx
11
11
  function attachControlId(child, candidateId, describedById) {
@@ -140,6 +140,11 @@ function useFormGridMetrics() {
140
140
  function useIsGapOwned() {
141
141
  return React2.useContext(GapOwnedContext);
142
142
  }
143
+ var ERROR_LIGHT_STEPS = ["500", "600", "700"];
144
+ var ERROR_DARK_STEPS = ["300", "200", "400", "100", "500"];
145
+ function fieldErrorInk(theme) {
146
+ return readableScaleInk({ ...theme.semantic.error }, theme.colors.surface, ERROR_LIGHT_STEPS, ERROR_DARK_STEPS);
147
+ }
143
148
  var ERROR_FONT_SIZE = 12;
144
149
  var HINT_FONT_SIZE = 12;
145
150
  var OPTIONAL_MARK_FONT_WEIGHT = "400";
@@ -195,8 +200,8 @@ var Field = ({
195
200
  const { theme } = useUi();
196
201
  const gapOwned = useIsGapOwned();
197
202
  const spacingStyles = fieldSpacingStyleSet(resolveFieldSpacing(spacing, gapOwned));
198
- const { colors, semantic } = theme;
199
- const errorColor = semantic.error["500"];
203
+ const { colors } = theme;
204
+ const errorColor = fieldErrorInk(theme);
200
205
  const hasError = hasFieldError(error);
201
206
  const hasHint = isPresent(hint);
202
207
  const labelText = label ?? "";
@@ -604,8 +609,7 @@ var IS_WEB5 = Platform.OS === "web";
604
609
  var TRANSITION_PROPERTY = "border-color, background-color, box-shadow";
605
610
  var TRANSITION_DURATION = "0.14s";
606
611
  var TRANSITION_TIMING = "ease";
607
- var FOCUS_RING_WIDTH = 3;
608
- var FOCUS_RING_ALPHA = 0.16;
612
+ var NO_RING = { outlineWidth: 0 };
609
613
  var HOVER_BORDER_ALPHA = 0.22;
610
614
  var PLACEHOLDER_ALPHA = 0.6;
611
615
  var HEX_RADIX = 16;
@@ -630,9 +634,9 @@ function withAlpha(color, alpha) {
630
634
  return `rgba(${r}, ${g}, ${b}, ${alpha})`;
631
635
  }
632
636
  function useThemedInput(options = {}) {
633
- const { hasError = false, onFocus, onBlur } = options;
637
+ const { hasError = false, onFocus, onBlur, editable = true } = options;
634
638
  const { theme } = useUi();
635
- const { colors, palette, semantic } = theme;
639
+ const { colors, palette } = theme;
636
640
  const [isFocused, setIsFocused] = useState(false);
637
641
  const [isHovered, setIsHovered] = useState(false);
638
642
  const handleFocus = useCallback(
@@ -652,23 +656,23 @@ function useThemedInput(options = {}) {
652
656
  const handleHoverIn = useCallback(() => setIsHovered(true), []);
653
657
  const handleHoverOut = useCallback(() => setIsHovered(false), []);
654
658
  const primary = palette.primary["500"];
655
- const errorColor = semantic.error["500"];
659
+ const errorColor = fieldErrorInk(theme);
656
660
  const style = useMemo(() => {
657
661
  const restBorder = hasError ? errorColor : colors.border;
658
662
  const focusBorder = hasError ? errorColor : primary;
659
663
  const borderColor = isFocused ? focusBorder : isHovered ? withAlpha(colors.text, HOVER_BORDER_ALPHA) : restBorder;
660
- const backgroundColor = isFocused ? colors.surface : colors.surfaceElevated;
661
- const base = { color: colors.text, borderColor, backgroundColor };
664
+ const editableFill = isFocused ? colors.surface : colors.surfaceElevated;
665
+ const backgroundColor = editable ? editableFill : colors.background;
666
+ const base = { color: editable ? colors.text : colors.textSecondary, borderColor, backgroundColor };
662
667
  if (!IS_WEB5) return base;
663
- const ringColor = hasError ? errorColor : primary;
664
- const ring = isFocused ? `0 0 0 ${FOCUS_RING_WIDTH}px ${withAlpha(ringColor, FOCUS_RING_ALPHA)}` : "none";
668
+ const ringColor = hasError ? errorColor : themeFocusRingColor(theme);
669
+ const ring = isFocused ? focusRingOutline(ringColor) : NO_RING;
665
670
  const webStyle = {
666
671
  transitionProperty: TRANSITION_PROPERTY,
667
672
  // Collapse the eased transition to instant when the user prefers reduced motion.
668
673
  transitionDuration: prefersReducedMotion() ? "0s" : TRANSITION_DURATION,
669
674
  transitionTimingFunction: TRANSITION_TIMING,
670
- boxShadow: ring,
671
- outlineStyle: "none"
675
+ ...ring
672
676
  };
673
677
  return { ...base, ...webStyle };
674
678
  }, [
@@ -679,8 +683,12 @@ function useThemedInput(options = {}) {
679
683
  colors.border,
680
684
  colors.surface,
681
685
  colors.surfaceElevated,
686
+ colors.background,
687
+ colors.textSecondary,
688
+ editable,
682
689
  primary,
683
- errorColor
690
+ errorColor,
691
+ theme
684
692
  ]);
685
693
  const focusBind = useMemo(() => ({ onFocus: handleFocus, onBlur: handleBlur }), [handleFocus, handleBlur]);
686
694
  const hoverBind = useMemo(
@@ -730,7 +738,7 @@ var ThemedTextInput = React2.forwardRef(function ThemedTextInput2({
730
738
  placeholderTextColor: themedPlaceholder,
731
739
  focusBind,
732
740
  hoverBind
733
- } = useThemedInput({ hasError, onFocus, onBlur });
741
+ } = useThemedInput({ hasError, onFocus, onBlur, editable: rest.editable });
734
742
  const webA11y = webFieldA11y({ describedById, hasError, required: requiredField });
735
743
  const boxStyle = unstyledBox ? null : controlStyles.input;
736
744
  const multilineStyle = rest.multiline === true && !unstyledBox ? boxStyles.multiline : null;
@@ -1583,7 +1591,7 @@ function TypeaheadControl({
1583
1591
  testID
1584
1592
  }) {
1585
1593
  const { theme } = useUi();
1586
- const { colors, palette, semantic } = theme;
1594
+ const { colors, palette } = theme;
1587
1595
  const anchorRef = useRef(null);
1588
1596
  const [isOpen, setIsOpen] = useState(false);
1589
1597
  const exactPick = useMemo(() => options.some((o) => o.label === value), [options, value]);
@@ -1631,7 +1639,7 @@ function TypeaheadControl({
1631
1639
  onFocus: () => setIsOpen(true),
1632
1640
  onBlur: handleBlur,
1633
1641
  onSubmitEditing: handleSubmit,
1634
- style: [controlStyles.input, { borderColor: hasError ? semantic.error["500"] : colors.border, backgroundColor: colors.surface, color: colors.text }],
1642
+ style: [controlStyles.input, { borderColor: hasError ? fieldErrorInk(theme) : colors.border, backgroundColor: colors.surface, color: colors.text }],
1635
1643
  testID: `${testID}-input`
1636
1644
  }
1637
1645
  ),
@@ -1649,7 +1657,7 @@ function TypeaheadControl({
1649
1657
  usePortal: true
1650
1658
  }
1651
1659
  ) : null,
1652
- hasError ? /* @__PURE__ */ jsx(Text, { role: "alert", style: [controlStyles.error, { color: semantic.error["500"] }], testID: `${testID}-error`, children: error }) : null
1660
+ hasError ? /* @__PURE__ */ jsx(Text, { role: "alert", style: [controlStyles.error, { color: fieldErrorInk(theme) }], testID: `${testID}-error`, children: error }) : null
1653
1661
  ] });
1654
1662
  }
1655
1663
  var WEB_DATE_PROPS = typeof document !== "undefined" ? { type: "date" } : {};