@dloizides/ui-forms 1.5.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/CHANGELOG.md +88 -0
- package/README.md +107 -75
- package/dist/index.d.mts +182 -10
- package/dist/index.d.ts +182 -10
- package/dist/index.js +260 -103
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +249 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +110 -108
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/Field/Field.tsx","../src/useThemedInput/useThemedInput.ts","../src/ThemedTextInput/ThemedTextInput.tsx","../src/FormField/FormField.tsx","../src/ChipSelector/ChipSelector.tsx","../src/FormSwitch/FormSwitch.tsx","../src/FormCheckbox/FormCheckbox.tsx"],"names":["React","useUi","IS_WEB","Platform","ThemedTextInput","jsx","styles","StyleSheet","HEX_SHORT_LENGTH","HEX_RADIX","withAlpha","View","Text","jsxs","Pressable"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * Field — the generic \"label over a control, error under it\" wrapper.\n *\n * `FormField` is hard-wired to a text input, so any NON-text control (a dropdown, a date picker,\n * a chip selector) had no shared way to get a label — and ended up visually misaligned next to\n * its `FormField` siblings: its box started a label-row higher, and it missed the container's\n * bottom margin so wrapped rows lost their vertical rhythm.\n *\n * `Field` is that label row + spacing, control-agnostic. Its metrics are the single source of\n * truth: `FormField` composes `Field` internally, so the two can never drift apart.\n *\n * Children may be a plain node (the common case — just wrap your control) or a render function\n * receiving `{ describedById, hasError }`, so a custom control can wire the error line into its\n * own `aria-describedby` / invalid state exactly the way `FormField` does.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\n/** Bottom margin of the whole field block — the vertical rhythm every form row shares. */\nconst CONTAINER_MARGIN_BOTTOM = 16;\nconst LABEL_FONT_SIZE = 13;\nconst LABEL_FONT_WEIGHT = '600';\nconst LABEL_MARGIN_BOTTOM = 4;\nconst ERROR_FONT_SIZE = 12;\nconst ERROR_MARGIN_TOP = 4;\n\nconst styles = StyleSheet.create({\n container: {\n marginBottom: CONTAINER_MARGIN_BOTTOM,\n },\n label: {\n marginBottom: LABEL_MARGIN_BOTTOM,\n fontSize: LABEL_FONT_SIZE,\n fontWeight: LABEL_FONT_WEIGHT,\n },\n errorText: {\n fontSize: ERROR_FONT_SIZE,\n marginTop: ERROR_MARGIN_TOP,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n requiredMark: TextStyle;\n errorText: TextStyle;\n}\n\n/** What a render-function child receives, so it can mirror `FormField`'s error wiring. */\nexport interface FieldChildContext {\n /** id of the rendered error line, or `undefined` when there is no error. */\n describedById?: string;\n hasError: boolean;\n}\n\nexport type FieldChildren = React.ReactNode | ((context: FieldChildContext) => React.ReactNode);\n\nexport interface FieldProps {\n label: string;\n children: FieldChildren;\n required?: boolean;\n error?: string;\n containerStyle?: ViewStyle;\n testID?: string;\n}\n\nlet fieldSeq = 0;\n/** Stable-per-instance id so the error line can be linked to the control via aria-describedby. */\nexport function useFieldErrorId(): string {\n const [id] = React.useState(() => {\n fieldSeq += 1;\n return `field-error-${String(fieldSeq)}`;\n });\n return id;\n}\n\n/** True only for a present, non-empty error string. */\nexport function hasFieldError(error?: string): boolean {\n return typeof error === 'string' && error !== '';\n}\n\nexport const Field = ({\n label,\n children,\n required = false,\n error,\n containerStyle,\n testID,\n}: FieldProps): React.ReactElement => {\n const { theme } = useUi();\n const { colors, semantic } = theme;\n const errorColor = semantic.error['500'];\n const hasError = hasFieldError(error);\n const errorId = useFieldErrorId();\n\n const themeStyles = React.useMemo<ThemeStyles>(\n () => ({\n label: { color: colors.textSecondary },\n requiredMark: { color: errorColor },\n errorText: { color: errorColor },\n }),\n [colors.textSecondary, errorColor],\n );\n\n const control =\n typeof children === 'function'\n ? children({ describedById: hasError ? errorId : undefined, hasError })\n : children;\n\n return (\n <View style={[styles.container, containerStyle]} testID={testID}>\n <Text style={[styles.label, themeStyles.label]}>\n {label}{' '}\n {required ? (\n // The asterisk is decorative — the control's `aria-required` conveys \"required\" to\n // assistive tech, so a screen reader says \"required\" instead of \"star\".\n <Text aria-hidden accessibilityElementsHidden importantForAccessibility=\"no\" style={themeStyles.requiredMark}>\n *\n </Text>\n ) : null}\n </Text>\n {control}\n {hasError ? (\n <Text nativeID={errorId} role=\"alert\" style={[styles.errorText, themeStyles.errorText]}>\n {error}\n </Text>\n ) : null}\n </View>\n );\n};\n\nexport default Field;\n","/**\n * `useThemedInput` — the shared \"readable + lively\" text-input treatment, driven entirely by\n * the active `@dloizides/ui-feedback` theme (so it re-themes per tenant, no hard-coded hex).\n *\n * At rest: dark readable text on a subtle off-white surface with a soft border.\n * On hover (web): the border strengthens a touch.\n * On focus: the border becomes the brand primary, the background brightens to the plain surface\n * (white), and a soft 3px brand-tinted focus ring fades in.\n *\n * Kept FAST: the animation is a pure GPU-cheap CSS transition on `border-color`,\n * `background-color` and `box-shadow` (the focus ring is a `box-shadow`, so it never triggers\n * layout/reflow). There is NO `Animated`, `LayoutAnimation` or JS timer — only React state\n * toggled by focus/blur/hover. Web-only style keys (`transition*`, `boxShadow`, `outlineStyle`)\n * and the mouse-hover handlers are guarded behind `Platform.OS === 'web'`, so the hook stays\n * native-safe (native simply applies the state-driven colours instantly).\n */\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { Platform, type TextInputProps, type TextStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\n/** The exact focus/blur event types of the installed `react-native` `TextInput` (version-safe). */\ntype FocusEvent = Parameters<NonNullable<TextInputProps['onFocus']>>[0];\ntype BlurEvent = Parameters<NonNullable<TextInputProps['onBlur']>>[0];\n\nconst IS_WEB = Platform.OS === 'web';\n\nconst TRANSITION_PROPERTY = 'border-color, background-color, box-shadow';\nconst TRANSITION_DURATION = '0.14s';\nconst TRANSITION_TIMING = 'ease';\nconst FOCUS_RING_WIDTH = 3;\nconst FOCUS_RING_ALPHA = 0.16;\nconst HOVER_BORDER_ALPHA = 0.22;\n\nconst HEX_RADIX = 16;\nconst HEX_SHORT_LENGTH = 4;\nconst HEX_FULL_LENGTH = 7;\nconst RED_START = 1;\nconst GREEN_START = 3;\nconst BLUE_START = 5;\nconst CHANNEL_END_OFFSET = 2;\n\n/**\n * Convert an `#rgb` / `#rrggbb` colour to an `rgba(...)` string at the given alpha. Any other\n * colour form (already `rgba()`, a CSS name, …) is returned unchanged — so the caller degrades\n * gracefully rather than emitting an invalid value.\n */\n/**\n * True when the user asked the OS to reduce motion (web only). Read at render so the\n * focus/hover transition collapses to an instant change for those users (WCAG 2.3.3 / the\n * `prefers-reduced-motion: reduce` contract). Safe under SSR / no `matchMedia`.\n */\nfunction prefersReducedMotion(): boolean {\n if (!IS_WEB || typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\nfunction withAlpha(color: string, alpha: number): string {\n const hex = color.trim();\n const isHex = hex.charAt(0) === '#' && (hex.length === HEX_FULL_LENGTH || hex.length === HEX_SHORT_LENGTH);\n if (!isHex) return color;\n const full =\n hex.length === HEX_SHORT_LENGTH\n ? `#${hex.charAt(1)}${hex.charAt(1)}${hex.charAt(2)}${hex.charAt(2)}${hex.charAt(3)}${hex.charAt(3)}`\n : hex;\n const r = parseInt(full.slice(RED_START, RED_START + CHANNEL_END_OFFSET), HEX_RADIX);\n const g = parseInt(full.slice(GREEN_START, GREEN_START + CHANNEL_END_OFFSET), HEX_RADIX);\n const b = parseInt(full.slice(BLUE_START, BLUE_START + CHANNEL_END_OFFSET), HEX_RADIX);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport interface UseThemedInputOptions {\n /** Render with the error border colour (the brand focus border is suppressed while errored). */\n hasError?: boolean;\n /** Consumer focus handler — composed with the internal focus-state toggle. */\n onFocus?: (e: FocusEvent) => void;\n /** Consumer blur handler — composed with the internal focus-state toggle. */\n onBlur?: (e: BlurEvent) => void;\n}\n\nexport interface ThemedInput {\n /** The themed input style for the current focus/hover state (memoised). Merge AFTER your box style. */\n style: TextStyle;\n /** A readable mid-grey placeholder colour from the theme. */\n placeholderTextColor: string;\n isFocused: boolean;\n isHovered: boolean;\n /** Spread/attach onto the `<TextInput>` to drive the focus treatment. */\n focusBind: {\n onFocus: (e: FocusEvent) => void;\n onBlur: (e: BlurEvent) => void;\n };\n /** Web-only mouse-hover handlers, pre-typed for `<TextInput>` (an empty object on native). */\n hoverBind: TextInputProps;\n}\n\nexport function useThemedInput(options: UseThemedInputOptions = {}): ThemedInput {\n const { hasError = false, onFocus, onBlur } = options;\n const { theme } = useUi();\n const { colors, palette, semantic } = theme;\n\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n\n const handleFocus = useCallback(\n (e: FocusEvent) => {\n setIsFocused(true);\n onFocus?.(e);\n },\n [onFocus],\n );\n const handleBlur = useCallback(\n (e: BlurEvent) => {\n setIsFocused(false);\n onBlur?.(e);\n },\n [onBlur],\n );\n const handleHoverIn = useCallback(() => setIsHovered(true), []);\n const handleHoverOut = useCallback(() => setIsHovered(false), []);\n\n const primary = palette.primary['500'];\n const errorColor = semantic.error['500'];\n\n const style = useMemo<TextStyle>(() => {\n const restBorder = hasError ? errorColor : colors.border;\n const focusBorder = hasError ? errorColor : primary;\n const borderColor = isFocused ? focusBorder : isHovered ? withAlpha(colors.text, HOVER_BORDER_ALPHA) : restBorder;\n const backgroundColor = isFocused ? colors.surface : colors.surfaceElevated;\n const base: TextStyle = { color: colors.text, borderColor, backgroundColor };\n if (!IS_WEB) return base;\n const ring =\n isFocused && !hasError ? `0 0 0 ${FOCUS_RING_WIDTH}px ${withAlpha(primary, FOCUS_RING_ALPHA)}` : 'none';\n const webStyle = {\n transitionProperty: TRANSITION_PROPERTY,\n // Collapse the eased transition to instant when the user prefers reduced motion.\n transitionDuration: prefersReducedMotion() ? '0s' : TRANSITION_DURATION,\n transitionTimingFunction: TRANSITION_TIMING,\n boxShadow: ring,\n outlineStyle: 'none',\n };\n return { ...base, ...webStyle } as TextStyle;\n }, [\n isFocused,\n isHovered,\n hasError,\n colors.text,\n colors.border,\n colors.surface,\n colors.surfaceElevated,\n primary,\n errorColor,\n ]);\n\n const focusBind = useMemo(() => ({ onFocus: handleFocus, onBlur: handleBlur }), [handleFocus, handleBlur]);\n\n const hoverBind = useMemo<TextInputProps>(\n () =>\n IS_WEB ? ({ onMouseEnter: handleHoverIn, onMouseLeave: handleHoverOut } as unknown as TextInputProps) : {},\n [handleHoverIn, handleHoverOut],\n );\n\n return {\n style,\n placeholderTextColor: colors.textSecondary,\n isFocused,\n isHovered,\n focusBind,\n hoverBind,\n };\n}\n","/**\n * `ThemedTextInput` — the shared, readable + lively text-input primitive. A thin `<TextInput>`\n * wrapper that applies the `useThemedInput` treatment (dark readable text, subtle off-white rest\n * background, and the brand focus animation: indigo border + white background + soft 3px ring,\n * eased over .14s via a GPU-cheap CSS transition on web; instant, native-safe off web).\n *\n * It is the ONE source of truth for the input look: `FormField` renders it, and raw filter inputs\n * (search / country / year / date fallbacks) use it directly instead of forking the styles.\n *\n * Every existing `TextInputProps` (value, placeholder, onChangeText, testID, accessibility…) is\n * forwarded untouched; `onFocus`/`onBlur` you pass are composed with the internal focus state.\n */\nimport React from 'react';\n\nimport { Platform, TextInput, type TextInputProps } from 'react-native';\n\nimport { useThemedInput } from '../useThemedInput/useThemedInput';\n\nconst IS_WEB = Platform.OS === 'web';\n\n/**\n * Web-only ARIA attributes react-native-web forwards to the underlying `<input>` but that RN's\n * `TextInputProps` type does not enumerate. Cast through the TextInput props at the call site\n * (never `any`) so error/label semantics reach a screen reader without a type escape hatch.\n */\ninterface WebInputA11y {\n 'aria-invalid'?: boolean;\n 'aria-describedby'?: string;\n 'aria-required'?: boolean;\n}\n\nexport interface ThemedTextInputProps extends TextInputProps {\n /** Render with the error border colour (matches `FormField`'s error treatment). */\n hasError?: boolean;\n /**\n * id of an element describing this input (e.g. an error/hint line). Linked via\n * `aria-describedby` on web so a screen reader reads it after the field's name. No-op native.\n */\n describedById?: string;\n /** Marks the field required for assistive tech (`aria-required` on web). No-op on native. */\n requiredField?: boolean;\n}\n\nexport const ThemedTextInput = React.forwardRef<TextInput, ThemedTextInputProps>(function ThemedTextInput(\n { hasError = false, describedById, requiredField = false, onFocus, onBlur, style, placeholderTextColor, ...rest },\n ref,\n): React.ReactElement {\n const {\n style: themedStyle,\n placeholderTextColor: themedPlaceholder,\n focusBind,\n hoverBind,\n } = useThemedInput({ hasError, onFocus, onBlur });\n\n // aria-invalid announces the error state; aria-describedby ties the error/hint text to the\n // field; aria-required marks it mandatory. Web-only (RN-web → DOM); omitted on native.\n const webA11y: WebInputA11y = IS_WEB\n ? {\n 'aria-invalid': hasError ? true : undefined,\n 'aria-describedby': describedById,\n 'aria-required': requiredField ? true : undefined,\n }\n : {};\n\n return (\n <TextInput\n ref={ref}\n placeholderTextColor={placeholderTextColor ?? themedPlaceholder}\n {...rest}\n {...(webA11y as TextInputProps)}\n {...hoverBind}\n onFocus={focusBind.onFocus}\n onBlur={focusBind.onBlur}\n style={[style, themedStyle]}\n />\n );\n});\n","/**\n * Reusable form field — labelled text input with optional required mark + error.\n *\n * The label row, the required mark, the error line and the container spacing all come from the\n * generic `Field` wrapper, so a `FormField` and a `Field`-wrapped dropdown sitting next to each\n * other line up exactly and can never drift apart. FormField only adds the control itself.\n *\n * The input is the shared `ThemedTextInput` primitive, so every FormField gets the readable +\n * lively treatment (dark text, subtle off-white rest background, brand focus animation with a\n * soft ring) for free, driven by the active theme.\n */\nimport React from 'react';\n\nimport { StyleSheet, type TextInputProps, type ViewStyle } from 'react-native';\n\nimport { Field } from '../Field/Field';\nimport { ThemedTextInput } from '../ThemedTextInput/ThemedTextInput';\n\nconst INPUT_PADDING_V = 10;\nconst INPUT_PADDING_H = 12;\nconst INPUT_BORDER_RADIUS = 8;\nconst INPUT_BORDER_WIDTH = 1;\n\nconst styles = StyleSheet.create({\n input: {\n paddingVertical: INPUT_PADDING_V,\n paddingHorizontal: INPUT_PADDING_H,\n borderRadius: INPUT_BORDER_RADIUS,\n borderWidth: INPUT_BORDER_WIDTH,\n },\n});\n\nexport interface FormFieldProps extends Omit<TextInputProps, 'style'> {\n label: string;\n required?: boolean;\n error?: string;\n containerStyle?: ViewStyle;\n}\n\nexport const FormField = ({\n label,\n required = false,\n error,\n containerStyle,\n ...textInputProps\n}: FormFieldProps): React.ReactElement => (\n <Field containerStyle={containerStyle} error={error} label={label} required={required}>\n {({ describedById, hasError }) => (\n <ThemedTextInput\n accessibilityHint={`Enter ${label}`}\n accessibilityLabel={label}\n describedById={describedById}\n hasError={hasError}\n requiredField={required}\n style={styles.input}\n testID=\"form-field-input\"\n {...textInputProps}\n />\n )}\n </Field>\n);\n\nexport default FormField;\n","/**\n * Chip/pill selector for selecting one or multiple options.\n *\n * Two visual variants (both fully theme-driven):\n * - `solid` (default) — the original filled-pill look: selected = solid primary fill with\n * white ink. Unchanged, so existing consumers (erevna / katalogos / kefi) render identically.\n * - `outline` — the AML v1 console look: an outlined pill on a muted fill; selected = a subtle\n * tinted-outline (primary border + primary ink + a low-alpha primary wash), NOT a solid fill.\n * Hover (web) lifts the border/ink to the primary colour.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, Pressable, TouchableOpacity, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nconst TRANSPARENT_COLOR = 'transparent';\nconst WHITE_COLOR = '#fff';\nconst SOLID_RADIUS = 20;\nconst OUTLINE_RADIUS = 999;\nconst OUTLINE_PAD_H = 12;\nconst OUTLINE_PAD_V = 5;\nconst OUTLINE_FONT_SIZE = 13;\nconst OUTLINE_TINT_ALPHA = 0.1;\nconst HEX_SHORT_LENGTH = 3;\nconst HEX_RADIX = 16;\nconst RGB_R_START = 0;\nconst RGB_R_END = 2;\nconst RGB_G_END = 4;\nconst RGB_B_END = 6;\n/**\n * Chips are visually compact (≈24–26px tall). `hitSlop` expands the pressable's TOUCH area\n * toward the WCAG ≥44px target WITHOUT changing the rendered pill size, so existing layouts are\n * byte-identical while taps/clicks get an easier target.\n */\nconst CHIP_HIT_SLOP = { top: 10, bottom: 10, left: 4, right: 4 } as const;\n\n/** Visual variant. `solid` = filled selected pill (default); `outline` = v1 tinted-outline. */\nexport type ChipVariant = 'solid' | 'outline';\n\n/** Composite a hex colour over the background at a given alpha (theme-driven tint). */\nfunction withAlpha(hex: string, alpha: number): string {\n const normalized = hex.replace('#', '');\n const isShort = normalized.length === HEX_SHORT_LENGTH;\n const full = isShort ? normalized.split('').map((c) => c + c).join('') : normalized;\n const r = parseInt(full.slice(RGB_R_START, RGB_R_END), HEX_RADIX);\n const g = parseInt(full.slice(RGB_R_END, RGB_G_END), HEX_RADIX);\n const b = parseInt(full.slice(RGB_G_END, RGB_B_END), HEX_RADIX);\n const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);\n return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;\n}\n\nconst styles = StyleSheet.create({\n label: {\n marginBottom: 8,\n fontWeight: '600',\n },\n chipContainer: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n },\n chipWrapper: {\n marginRight: 8,\n marginBottom: 8,\n },\n chip: {\n paddingHorizontal: 12,\n paddingVertical: 6,\n borderRadius: SOLID_RADIUS,\n backgroundColor: TRANSPARENT_COLOR,\n borderWidth: 1,\n },\n chipOutline: {\n paddingHorizontal: OUTLINE_PAD_H,\n paddingVertical: OUTLINE_PAD_V,\n borderRadius: OUTLINE_RADIUS,\n borderWidth: 1,\n },\n chipText: {},\n chipTextOutline: { fontSize: OUTLINE_FONT_SIZE },\n});\n\n/** Resolved, theme-derived colours for the two variants. */\ninterface ChipColors {\n border: string;\n /** Strong ink for the solid variant's rest text (unchanged from the original). */\n textStrong: string;\n /** Muted ink for the outline variant's rest text (v1 ink-soft). */\n textMuted: string;\n primary: string;\n muted: string;\n tint: string;\n}\n\nexport interface ChipOption<T> {\n value: T;\n label: string;\n}\n\nexport interface ChipSelectorProps<T> {\n label?: string;\n options: Array<ChipOption<T>>;\n value: T | T[];\n onChange: (value: T) => void;\n multiple?: boolean;\n disabled?: boolean;\n /** Visual variant. `solid` (default) = filled selected pill; `outline` = v1 tinted-outline. */\n variant?: ChipVariant;\n containerStyle?: ViewStyle;\n}\n\ninterface ChipProps<T> {\n option: ChipOption<T>;\n selected: boolean;\n disabled: boolean;\n colors: ChipColors;\n}\n\n/** A single outline chip — owns its own hover state (web) for the border/ink lift. */\nfunction OutlineChip<T extends string | number>({\n option,\n selected,\n disabled,\n colors,\n onPress,\n}: ChipProps<T> & { onPress: () => void }): React.ReactElement {\n const [hovered, setHovered] = React.useState(false);\n const active = selected || hovered;\n\n const borderColor = active ? colors.primary : colors.border;\n const backgroundColor = selected ? colors.tint : colors.muted;\n // Selected AND hovered both lift the ink to the primary colour (v1's indigo / indigo-dark);\n // the theme surface only guarantees the 500 step, so both use it — border + fill carry the state.\n const textColor = active ? colors.primary : colors.textMuted;\n\n return (\n <Pressable\n accessibilityHint={`Selects ${option.label}`}\n accessibilityLabel={option.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected, disabled }}\n disabled={disabled}\n hitSlop={CHIP_HIT_SLOP}\n style={styles.chipWrapper}\n testID={`chip-selector-chip-${String(option.value)}`}\n onHoverIn={() => setHovered(true)}\n onHoverOut={() => setHovered(false)}\n onPress={onPress}\n >\n <View style={[styles.chipOutline, { borderColor, backgroundColor }]}>\n <Text style={[styles.chipText, styles.chipTextOutline, { color: textColor }]}>{option.label}</Text>\n </View>\n </Pressable>\n );\n}\n\n/** A single solid chip — the original filled-pill look (unchanged for existing consumers). */\nfunction SolidChip<T extends string | number>({\n option,\n selected,\n disabled,\n colors,\n onPress,\n}: ChipProps<T> & { onPress: () => void }): React.ReactElement {\n const backgroundColor = selected ? colors.primary : TRANSPARENT_COLOR;\n const textColor = selected ? WHITE_COLOR : colors.textStrong;\n return (\n <TouchableOpacity\n accessibilityHint={`Selects ${option.label}`}\n accessibilityLabel={option.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected, disabled }}\n disabled={disabled}\n hitSlop={CHIP_HIT_SLOP}\n style={styles.chipWrapper}\n testID={`chip-selector-chip-${String(option.value)}`}\n onPress={onPress}\n >\n <View style={[styles.chip, { borderColor: colors.border, backgroundColor }]}>\n <Text style={[styles.chipText, { color: textColor }]}>{option.label}</Text>\n </View>\n </TouchableOpacity>\n );\n}\n\nexport const ChipSelector = <T extends string | number>({\n label,\n options,\n value,\n onChange,\n multiple = false,\n disabled = false,\n variant = 'solid',\n containerStyle,\n}: ChipSelectorProps<T>): React.ReactElement => {\n const { theme } = useUi();\n const { colors, palette } = theme;\n const hasLabel = typeof label === 'string' && label !== '';\n\n const chipColors = React.useMemo<ChipColors>(() => {\n const primary = palette.primary['500'];\n return {\n border: colors.border,\n textStrong: colors.text,\n textMuted: colors.textSecondary,\n primary,\n muted: colors.background,\n tint: withAlpha(primary, OUTLINE_TINT_ALPHA),\n };\n }, [colors.border, colors.text, colors.textSecondary, colors.background, palette.primary]);\n\n const labelStyle = React.useMemo<TextStyle>(() => ({ color: colors.text }), [colors.text]);\n\n function isSelected(optionValue: T): boolean {\n if (multiple && Array.isArray(value))\n return value.includes(optionValue);\n\n return value === optionValue;\n }\n\n return (\n <View style={containerStyle}>\n {hasLabel ? <Text style={[styles.label, labelStyle]}>{label}</Text> : null}\n <View style={styles.chipContainer}>\n {options.map((option) => {\n const selected = isSelected(option.value);\n const onPress = (): void => onChange(option.value);\n return variant === 'outline' ? (\n <OutlineChip\n key={String(option.value)}\n colors={chipColors}\n disabled={disabled}\n option={option}\n selected={selected}\n onPress={onPress}\n />\n ) : (\n <SolidChip\n key={String(option.value)}\n colors={chipColors}\n disabled={disabled}\n option={option}\n selected={selected}\n onPress={onPress}\n />\n );\n })}\n </View>\n </View>\n );\n};\n\nexport default ChipSelector;\n","/**\n * Reusable form switch/toggle with an optional description.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, Switch, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nconst DESCRIPTION_FONT_SIZE = 12;\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: 12,\n },\n textColumn: {\n flex: 1,\n },\n label: {\n fontWeight: '600',\n },\n description: {\n fontSize: DESCRIPTION_FONT_SIZE,\n marginTop: 2,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n description: TextStyle;\n}\n\nexport interface FormSwitchProps {\n label: string;\n value: boolean;\n onValueChange: (value: boolean) => void;\n disabled?: boolean;\n description?: string;\n containerStyle?: ViewStyle;\n testID?: string;\n accessibilityHint?: string;\n}\n\nexport const FormSwitch = ({\n label,\n value,\n onValueChange,\n disabled = false,\n description,\n containerStyle,\n testID = 'form-switch',\n accessibilityHint,\n}: FormSwitchProps): React.ReactElement => {\n const { theme } = useUi();\n const { colors } = theme;\n const hasDescription = typeof description === 'string' && description !== '';\n\n const themeStyles = React.useMemo<ThemeStyles>(() => {\n const labelStyle: TextStyle = { color: colors.text };\n const descriptionStyle: TextStyle = { color: colors.textSecondary };\n return { label: labelStyle, description: descriptionStyle };\n }, [colors.text, colors.textSecondary]);\n\n return (\n <View\n style={[\n styles.container,\n containerStyle,\n ]}\n >\n <View style={styles.textColumn}>\n <Text style={[styles.label, themeStyles.label]}>{label}</Text>\n {hasDescription ? (\n <Text style={[styles.description, themeStyles.description]}>{description}</Text>\n ) : null}\n </View>\n <Switch\n accessibilityHint={accessibilityHint ?? label}\n accessibilityLabel={label}\n accessibilityRole=\"switch\"\n accessibilityState={{ checked: value }}\n disabled={disabled}\n testID={testID}\n value={value}\n onValueChange={onValueChange}\n />\n </View>\n );\n};\n\nexport default FormSwitch;\n","/**\n * Reusable, native-safe checkbox — a themed `Pressable` (works on RN-web AND native, where RN has\n * no built-in checkbox). A small rounded square that fills with the brand colour and shows a check\n * glyph when on, with a label and an optional hint. Mirrors `FormSwitch`'s prop shape so it is a\n * drop-in replacement for the boolean toggles v1 renders as checkboxes.\n */\nimport React from 'react';\n\nimport { Platform, StyleSheet, View, Text, Pressable, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\n/**\n * Web-only keydown prop react-native-web's `Pressable` forwards but RN's types omit. A\n * `role=\"checkbox\"` Pressable renders a `<div>` (not a native `<button>`), so — unlike a\n * button-role Pressable — it gets NO free Enter/Space activation. We add it explicitly so the\n * checkbox is keyboard-operable (WCAG 2.1.1). `preventDefault()` stops Space from scrolling.\n */\ninterface WebKeyboardProps {\n onKeyDown?: (event: { key?: string; preventDefault?: () => void }) => void;\n}\n\nconst ACTIVATION_KEYS = ['Enter', ' ', 'Spacebar'];\n\nconst HINT_FONT_SIZE = 12;\nconst BOX_SIZE = 20;\nconst BOX_RADIUS = 5;\nconst CHECK_FONT_SIZE = 14;\nconst DISABLED_OPACITY = 0.5;\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 10,\n marginBottom: 12,\n },\n box: {\n width: BOX_SIZE,\n height: BOX_SIZE,\n borderRadius: BOX_RADIUS,\n borderWidth: 2,\n alignItems: 'center',\n justifyContent: 'center',\n // Nudge the box to sit on the label's first text line.\n marginTop: 1,\n },\n check: {\n fontSize: CHECK_FONT_SIZE,\n fontWeight: '700',\n lineHeight: CHECK_FONT_SIZE,\n },\n textColumn: {\n flex: 1,\n },\n label: {\n fontWeight: '600',\n },\n hint: {\n fontSize: HINT_FONT_SIZE,\n marginTop: 2,\n },\n});\n\nexport interface FormCheckboxProps {\n label: string;\n value: boolean;\n /** Primary change handler (mirrors `FormSwitch`). `onChange` is accepted as an alias. */\n onValueChange?: (value: boolean) => void;\n /** Alias for `onValueChange` so either name works as a drop-in. */\n onChange?: (value: boolean) => void;\n /** Optional secondary description shown under the label. `description` is accepted as an alias. */\n hint?: string;\n description?: string;\n disabled?: boolean;\n containerStyle?: ViewStyle;\n testID?: string;\n accessibilityLabel?: string;\n accessibilityHint?: string;\n}\n\nexport const FormCheckbox = ({\n label,\n value,\n onValueChange,\n onChange,\n hint,\n description,\n disabled = false,\n containerStyle,\n testID = 'form-checkbox',\n accessibilityLabel,\n accessibilityHint,\n}: FormCheckboxProps): React.ReactElement => {\n const { theme } = useUi();\n const { colors, palette } = theme;\n const brand = palette.primary['500'];\n const hintText = typeof hint === 'string' && hint !== '' ? hint : description;\n const hasHint = typeof hintText === 'string' && hintText !== '';\n\n const themeStyles = React.useMemo(() => {\n const boxOn: ViewStyle = { backgroundColor: brand, borderColor: brand };\n const boxOff: ViewStyle = { backgroundColor: 'transparent', borderColor: colors.border };\n const labelStyle: TextStyle = { color: colors.text };\n const hintStyle: TextStyle = { color: colors.textSecondary };\n return { boxOn, boxOff, label: labelStyle, hint: hintStyle };\n }, [brand, colors.border, colors.text, colors.textSecondary]);\n\n const toggle = (): void => {\n const next = !value;\n if (onValueChange) onValueChange(next);\n if (onChange) onChange(next);\n };\n\n const handleKeyDown = (event: { key?: string; preventDefault?: () => void }): void => {\n if (disabled) return;\n const key = event.key ?? '';\n if (!ACTIVATION_KEYS.includes(key)) return;\n if (typeof event.preventDefault === 'function') event.preventDefault();\n toggle();\n };\n\n const keyboardProps: WebKeyboardProps = Platform.OS === 'web' ? { onKeyDown: handleKeyDown } : {};\n\n return (\n <Pressable\n accessibilityHint={accessibilityHint ?? label}\n accessibilityLabel={accessibilityLabel ?? label}\n accessibilityRole=\"checkbox\"\n accessibilityState={{ checked: value, disabled }}\n // RN-web maps this to the ARIA `role=\"checkbox\"` + `aria-checked` a screen reader announces.\n aria-checked={value}\n disabled={disabled}\n onPress={toggle}\n role=\"checkbox\"\n style={[styles.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null]}\n testID={testID}\n {...keyboardProps}\n >\n <View style={[styles.box, value ? themeStyles.boxOn : themeStyles.boxOff]}>\n {value ? (\n <Text style={[styles.check, { color: colors.surface }]} accessibilityElementsHidden>\n ✓\n </Text>\n ) : null}\n </View>\n <View style={styles.textColumn}>\n <Text style={[styles.label, themeStyles.label]}>{label}</Text>\n {hasHint ? <Text style={[styles.hint, themeStyles.hint]}>{hintText}</Text> : null}\n </View>\n </Pressable>\n );\n};\n\nexport default FormCheckbox;\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/Field/FieldLabel.tsx","../src/Field/fieldMarkers.ts","../src/Field/labelVariants.ts","../src/Field/Field.tsx","../src/FormActions/FormActions.tsx","../src/useThemedInput/useThemedInput.ts","../src/ThemedTextInput/ThemedTextInput.tsx","../src/FormField/FormField.tsx","../src/ChipSelector/ChipSelector.tsx","../src/FormSwitch/FormSwitch.tsx","../src/FormCheckbox/FormCheckbox.tsx"],"names":["StyleSheet","jsxs","jsx","Text","styles","View","useUi","IS_WEB","Platform","React","ThemedTextInput","HEX_SHORT_LENGTH","HEX_RADIX","withAlpha","HINT_FONT_SIZE","Pressable"],"mappings":";;;;;;;AAuBO,SAAS,UAAA,CAAW;AAAA,EACzB,KAAA;AAAA,EACA,MAAA;AAAA,EACA,aAAA;AAAA,EACA,KAAA;AAAA,EACA,iBAAA;AAAA,EACA;AACF,CAAA,EAAwC;AACtC,EAAA,uBACE,IAAA,CAAC,QAAK,KAAA,EACH,QAAA,EAAA;AAAA,IAAA,KAAA;AAAA,IAAO,GAAA;AAAA,IACP,MAAA,KAAW,UAAA;AAAA;AAAA;AAAA,sBAGV,GAAA,CAAC,IAAA,EAAA,EAAK,aAAA,EAAW,IAAA,EAAC,2BAAA,EAA2B,MAAC,yBAAA,EAA0B,IAAA,EAAK,KAAA,EAAO,iBAAA,EAAmB,QAAA,EAAA,GAAA,EAEvG;AAAA,QACE,IAAA;AAAA,IACH,MAAA,KAAW,cAAc,aAAA,KAAkB,EAAA;AAAA;AAAA;AAAA,sBAG1C,GAAA,CAAC,IAAA,EAAA,EAAK,aAAA,EAAW,IAAA,EAAC,2BAAA,EAA2B,MAAC,yBAAA,EAA0B,IAAA,EAAK,KAAA,EAAO,iBAAA,EACjF,QAAA,EAAA,aAAA,EACH;AAAA,QACE;AAAA,GAAA,EACN,CAAA;AAEJ;;;ACnBO,IAAM,sBAAA,GAAyB;AAM/B,SAAS,kBAAA,CAAmB,UAAmB,QAAA,EAAgC;AACpF,EAAA,IAAI,UAAU,OAAO,UAAA;AACrB,EAAA,IAAI,UAAU,OAAO,UAAA;AACrB,EAAA,OAAO,MAAA;AACT;AChBA,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,iBAAA,GAAoB,KAAA;AAG1B,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,mBAAA,GAAsB,KAAA;AAC5B,IAAM,sBAAA,GAAyB,GAAA;AAExB,IAAM,kBAAA,GAAqB,WAAW,MAAA,CAAO;AAAA,EAClD,KAAA,EAAO;AAAA,IACL,QAAA,EAAU,eAAA;AAAA,IACV,UAAA,EAAY;AAAA,GACd;AAAA,EACA,OAAA,EAAS;AAAA,IACP,QAAA,EAAU,iBAAA;AAAA,IACV,UAAA,EAAY,mBAAA;AAAA,IACZ,aAAA,EAAe,sBAAA;AAAA,IACf,aAAA,EAAe;AAAA;AAEnB,CAAC,CAAA;AAMM,SAAS,yBAAyB,OAAA,EAAwC;AAC/E,EAAA,OAAO,OAAA,KAAY,SAAA,GAAY,kBAAA,CAAmB,OAAA,GAAU,kBAAA,CAAmB,KAAA;AACjF;ACtBA,IAAM,uBAAA,GAA0B,EAAA;AAChC,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,gBAAA,GAAmB,CAAA;AACzB,IAAM,cAAA,GAAiB,EAAA;AACvB,IAAM,eAAA,GAAkB,CAAA;AAExB,IAAM,yBAAA,GAA4B,KAAA;AAElC,IAAM,MAAA,GAASA,WAAW,MAAA,CAAO;AAAA,EAC/B,SAAA,EAAW;AAAA,IACT,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,KAAA,EAAO;AAAA,IACL,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,QAAA,EAAU;AAAA,IACR,QAAA,EAAU,cAAA;AAAA,IACV,SAAA,EAAW;AAAA,GACb;AAAA,EACA,SAAA,EAAW;AAAA,IACT,QAAA,EAAU,eAAA;AAAA,IACV,SAAA,EAAW;AAAA,GACb;AAAA,EACA,YAAA,EAAc;AAAA,IACZ,UAAA,EAAY;AAAA;AAEhB,CAAC,CAAA;AAyED,IAAI,QAAA,GAAW,CAAA;AAKR,SAAS,WAAA,GAAmD;AACjE,EAAA,MAAM,CAAC,GAAG,CAAA,GAAI,KAAA,CAAM,SAAS,MAAM;AACjC,IAAA,QAAA,IAAY,CAAA;AACZ,IAAA,MAAM,GAAA,GAAM,OAAO,QAAQ,CAAA;AAC3B,IAAA,OAAO,EAAE,QAAQ,CAAA,WAAA,EAAc,GAAG,IAAI,OAAA,EAAS,CAAA,YAAA,EAAe,GAAG,CAAA,CAAA,EAAG;AAAA,EACtE,CAAC,CAAA;AACD,EAAA,OAAO,GAAA;AACT;AAQA,SAAS,UAAU,KAAA,EAAyB;AAC1C,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,IAAY,KAAA,KAAU,EAAA;AAChD;AAGO,SAAS,cAAc,KAAA,EAAyB;AACrD,EAAA,OAAO,UAAU,KAAK,CAAA;AACxB;AAOO,SAAS,eAAA,CAAgB,QAAiB,OAAA,EAAsC;AACrF,EAAA,MAAM,GAAA,GAAM,CAAC,MAAA,EAAQ,OAAO,CAAA,CAAE,OAAO,CAAC,EAAA,KAAqB,SAAA,CAAU,EAAE,CAAC,CAAA;AACxE,EAAA,OAAO,IAAI,MAAA,GAAS,CAAA,GAAI,GAAA,CAAI,IAAA,CAAK,GAAG,CAAA,GAAI,MAAA;AAC1C;AAEO,IAAM,QAAQ,CAAC;AAAA,EACpB,KAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,QAAA,GAAW,KAAA;AAAA,EACX,aAAA,GAAgB,sBAAA;AAAA,EAChB,IAAA;AAAA,EACA,KAAA;AAAA,EACA,YAAA;AAAA,EACA,UAAA;AAAA,EACA,cAAA;AAAA,EACA;AACF,CAAA,KAAsC;AACpC,EAAA,MAAM,EAAE,KAAA,EAAM,GAAI,KAAA,EAAM;AACxB,EAAA,MAAM,EAAE,MAAA,EAAQ,QAAA,EAAS,GAAI,KAAA;AAC7B,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA;AACvC,EAAA,MAAM,QAAA,GAAW,cAAc,KAAK,CAAA;AACpC,EAAA,MAAM,OAAA,GAAU,UAAU,IAAI,CAAA;AAC9B,EAAA,MAAM,YAAY,KAAA,IAAS,EAAA;AAC3B,EAAA,MAAM,WAAW,SAAA,KAAc,EAAA;AAC/B,EAAA,MAAM,MAAA,GAAS,kBAAA,CAAmB,QAAA,EAAU,QAAQ,CAAA;AACpD,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAQ,GAAI,WAAA,EAAY;AAExC,EAAA,MAAM,cAAc,KAAA,CAAM,OAAA;AAAA,IACxB,OAAO;AAAA,MACL,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,CAAO,aAAA,EAAc;AAAA,MACrC,YAAA,EAAc,EAAE,KAAA,EAAO,UAAA,EAAW;AAAA;AAAA,MAElC,YAAA,EAAc,EAAE,KAAA,EAAO,MAAA,CAAO,aAAA,EAAc;AAAA,MAC5C,QAAA,EAAU,EAAE,KAAA,EAAO,MAAA,CAAO,aAAA,EAAc;AAAA,MACxC,SAAA,EAAW,EAAE,KAAA,EAAO,UAAA;AAAW,KACjC,CAAA;AAAA,IACA,CAAC,MAAA,CAAO,aAAA,EAAe,UAAU;AAAA,GACnC;AAEA,EAAA,MAAM,gBAAgB,eAAA,CAAgB,OAAA,GAAU,SAAS,MAAA,EAAW,QAAA,GAAW,UAAU,MAAS,CAAA;AAElG,EAAA,MAAM,OAAA,GAAU,OAAO,QAAA,KAAa,UAAA,GAAa,SAAS,EAAE,aAAA,EAAe,QAAA,EAAU,CAAA,GAAI,QAAA;AAEzF,EAAA,uBACEC,KAAC,IAAA,EAAA,EAAK,KAAA,EAAO,CAAC,MAAA,CAAO,SAAA,EAAW,cAAc,CAAA,EAAG,MAAA,EAC9C,QAAA,EAAA;AAAA,IAAA,QAAA,mBACCC,GAAAA;AAAA,MAAC,UAAA;AAAA,MAAA;AAAA,QACC,KAAA,EAAO,SAAA;AAAA,QACP,MAAA;AAAA,QACA,aAAA;AAAA,QACA,iBAAA,EAAmB,CAAC,MAAA,CAAO,YAAA,EAAc,YAAY,YAAY,CAAA;AAAA,QACjE,mBAAmB,WAAA,CAAY,YAAA;AAAA,QAC/B,KAAA,EAAO,CAAC,MAAA,CAAO,KAAA,EAAO,yBAAyB,YAAY,CAAA,EAAG,WAAA,CAAY,KAAA,EAAO,UAAU;AAAA;AAAA,KAC7F,GACE,IAAA;AAAA,IACH,OAAA;AAAA,IACA,OAAA,mBACCA,GAAAA,CAACC,IAAAA,EAAA,EAAK,QAAA,EAAU,MAAA,EAAQ,KAAA,EAAO,CAAC,OAAO,QAAA,EAAU,WAAA,CAAY,QAAQ,CAAA,EAClE,gBACH,CAAA,GACE,IAAA;AAAA,IACH,2BACCD,GAAAA,CAACC,IAAAA,EAAA,EAAK,UAAU,OAAA,EAAS,IAAA,EAAK,OAAA,EAAQ,KAAA,EAAO,CAAC,MAAA,CAAO,SAAA,EAAW,YAAY,SAAS,CAAA,EAClF,iBACH,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;AC9MA,IAAM,WAAA,GAAc,EAAA;AAEpB,IAAMC,OAAAA,GAASJ,WAAW,MAAA,CAAO;AAAA,EAC/B,SAAA,EAAW;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,UAAA;AAAA,IAChB,GAAA,EAAK;AAAA;AAET,CAAC,CAAA;AAyBM,IAAM,cAAc,CAAC;AAAA,EAC1B,MAAA;AAAA,EACA,QAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA,GAAc,EAAA;AAAA,EACd,QAAA;AAAA,EACA,UAAA;AAAA,EACA,MAAA,GAAS,KAAA;AAAA,EACT,YAAA,GAAe,KAAA;AAAA,EACf,cAAA;AAAA,EACA,UAAA,GAAa,aAAA;AAAA,EACb,YAAA,GAAe,eAAA;AAAA,EACf;AACF,CAAA,qBACEC,IAAAA,CAACI,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACD,OAAAA,CAAO,SAAA,EAAW,cAAc,CAAA,EAAG,MAAA,EAC9C,QAAA,EAAA;AAAA,EAAA,OAAO,QAAA,KAAa,6BACnBF,GAAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,mBAAmB,UAAA,IAAc,WAAA;AAAA,MACjC,kBAAA,EAAoB,WAAA;AAAA,MACpB,QAAA,EAAU,MAAA;AAAA,MACV,KAAA,EAAO,WAAA;AAAA,MACP,MAAA,EAAQ,YAAA;AAAA,MACR,OAAA,EAAQ,SAAA;AAAA,MACR,OAAA,EAAS;AAAA;AAAA,GACX,GACE,IAAA;AAAA,kBAEJA,GAAAA;AAAA,IAAC,MAAA;AAAA,IAAA;AAAA,MACC,mBAAmB,QAAA,IAAY,SAAA;AAAA,MAC/B,kBAAA,EAAoB,SAAA;AAAA,MACpB,QAAA,EAAU,YAAA;AAAA,MACV,KAAA,EAAO,SAAA;AAAA,MACP,OAAA,EAAS,MAAA;AAAA,MACT,MAAA,EAAQ,UAAA;AAAA,MACR,OAAA,EAAQ,SAAA;AAAA,MACR,OAAA,EAAS;AAAA;AAAA;AACX,CAAA,EACF;ACvEF,IAAM,MAAA,GAAS,SAAS,EAAA,KAAO,KAAA;AAE/B,IAAM,mBAAA,GAAsB,4CAAA;AAC5B,IAAM,mBAAA,GAAsB,OAAA;AAC5B,IAAM,iBAAA,GAAoB,MAAA;AAC1B,IAAM,gBAAA,GAAmB,CAAA;AACzB,IAAM,gBAAA,GAAmB,IAAA;AACzB,IAAM,kBAAA,GAAqB,IAAA;AAE3B,IAAM,SAAA,GAAY,EAAA;AAClB,IAAM,gBAAA,GAAmB,CAAA;AACzB,IAAM,eAAA,GAAkB,CAAA;AACxB,IAAM,SAAA,GAAY,CAAA;AAClB,IAAM,WAAA,GAAc,CAAA;AACpB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,kBAAA,GAAqB,CAAA;AAY3B,SAAS,oBAAA,GAAgC;AACvC,EAAA,IAAI,CAAC,UAAU,OAAO,MAAA,KAAW,eAAe,OAAO,MAAA,CAAO,UAAA,KAAe,UAAA,EAAY,OAAO,KAAA;AAChG,EAAA,OAAO,MAAA,CAAO,UAAA,CAAW,kCAAkC,CAAA,CAAE,OAAA;AAC/D;AAEA,SAAS,SAAA,CAAU,OAAe,KAAA,EAAuB;AACvD,EAAA,MAAM,GAAA,GAAM,MAAM,IAAA,EAAK;AACvB,EAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,MAAA,CAAO,CAAC,CAAA,KAAM,QAAQ,GAAA,CAAI,MAAA,KAAW,eAAA,IAAmB,GAAA,CAAI,MAAA,KAAW,gBAAA,CAAA;AACzF,EAAA,IAAI,CAAC,OAAO,OAAO,KAAA;AACnB,EAAA,MAAM,IAAA,GACJ,GAAA,CAAI,MAAA,KAAW,gBAAA,GACX,IAAI,GAAA,CAAI,MAAA,CAAO,CAAC,CAAC,GAAG,GAAA,CAAI,MAAA,CAAO,CAAC,CAAC,GAAG,GAAA,CAAI,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,GAAA,CAAI,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,GAAA,CAAI,MAAA,CAAO,CAAC,CAAC,CAAA,EAAG,GAAA,CAAI,MAAA,CAAO,CAAC,CAAC,CAAA,CAAA,GACjG,GAAA;AACN,EAAA,MAAM,CAAA,GAAI,SAAS,IAAA,CAAK,KAAA,CAAM,WAAW,SAAA,GAAY,kBAAkB,GAAG,SAAS,CAAA;AACnF,EAAA,MAAM,CAAA,GAAI,SAAS,IAAA,CAAK,KAAA,CAAM,aAAa,WAAA,GAAc,kBAAkB,GAAG,SAAS,CAAA;AACvF,EAAA,MAAM,CAAA,GAAI,SAAS,IAAA,CAAK,KAAA,CAAM,YAAY,UAAA,GAAa,kBAAkB,GAAG,SAAS,CAAA;AACrF,EAAA,OAAO,QAAQ,CAAC,CAAA,EAAA,EAAK,CAAC,CAAA,EAAA,EAAK,CAAC,KAAK,KAAK,CAAA,CAAA,CAAA;AACxC;AA2BO,SAAS,cAAA,CAAe,OAAA,GAAiC,EAAC,EAAgB;AAC/E,EAAA,MAAM,EAAE,QAAA,GAAW,KAAA,EAAO,OAAA,EAAS,QAAO,GAAI,OAAA;AAC9C,EAAA,MAAM,EAAE,KAAA,EAAM,GAAII,KAAAA,EAAM;AACxB,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAS,QAAA,EAAS,GAAI,KAAA;AAEtC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAChD,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAS,KAAK,CAAA;AAEhD,EAAA,MAAM,WAAA,GAAc,WAAA;AAAA,IAClB,CAAC,CAAA,KAAkB;AACjB,MAAA,YAAA,CAAa,IAAI,CAAA;AACjB,MAAA,OAAA,GAAU,CAAC,CAAA;AAAA,IACb,CAAA;AAAA,IACA,CAAC,OAAO;AAAA,GACV;AACA,EAAA,MAAM,UAAA,GAAa,WAAA;AAAA,IACjB,CAAC,CAAA,KAAiB;AAChB,MAAA,YAAA,CAAa,KAAK,CAAA;AAClB,MAAA,MAAA,GAAS,CAAC,CAAA;AAAA,IACZ,CAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACT;AACA,EAAA,MAAM,gBAAgB,WAAA,CAAY,MAAM,aAAa,IAAI,CAAA,EAAG,EAAE,CAAA;AAC9D,EAAA,MAAM,iBAAiB,WAAA,CAAY,MAAM,aAAa,KAAK,CAAA,EAAG,EAAE,CAAA;AAEhE,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AACrC,EAAA,MAAM,UAAA,GAAa,QAAA,CAAS,KAAA,CAAM,KAAK,CAAA;AAEvC,EAAA,MAAM,KAAA,GAAQ,QAAmB,MAAM;AACrC,IAAA,MAAM,UAAA,GAAa,QAAA,GAAW,UAAA,GAAa,MAAA,CAAO,MAAA;AAClD,IAAA,MAAM,WAAA,GAAc,WAAW,UAAA,GAAa,OAAA;AAC5C,IAAA,MAAM,WAAA,GAAc,YAAY,WAAA,GAAc,SAAA,GAAY,UAAU,MAAA,CAAO,IAAA,EAAM,kBAAkB,CAAA,GAAI,UAAA;AACvG,IAAA,MAAM,eAAA,GAAkB,SAAA,GAAY,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,eAAA;AAC5D,IAAA,MAAM,OAAkB,EAAE,KAAA,EAAO,MAAA,CAAO,IAAA,EAAM,aAAa,eAAA,EAAgB;AAC3E,IAAA,IAAI,CAAC,QAAQ,OAAO,IAAA;AAKpB,IAAA,MAAM,SAAA,GAAY,WAAW,UAAA,GAAa,OAAA;AAC1C,IAAA,MAAM,IAAA,GAAO,YAAY,CAAA,MAAA,EAAS,gBAAgB,MAAM,SAAA,CAAU,SAAA,EAAW,gBAAgB,CAAC,CAAA,CAAA,GAAK,MAAA;AACnG,IAAA,MAAM,QAAA,GAAW;AAAA,MACf,kBAAA,EAAoB,mBAAA;AAAA;AAAA,MAEpB,kBAAA,EAAoB,oBAAA,EAAqB,GAAI,IAAA,GAAO,mBAAA;AAAA,MACpD,wBAAA,EAA0B,iBAAA;AAAA,MAC1B,SAAA,EAAW,IAAA;AAAA,MACX,YAAA,EAAc;AAAA,KAChB;AACA,IAAA,OAAO,EAAE,GAAG,IAAA,EAAM,GAAG,QAAA,EAAS;AAAA,EAChC,CAAA,EAAG;AAAA,IACD,SAAA;AAAA,IACA,SAAA;AAAA,IACA,QAAA;AAAA,IACA,MAAA,CAAO,IAAA;AAAA,IACP,MAAA,CAAO,MAAA;AAAA,IACP,MAAA,CAAO,OAAA;AAAA,IACP,MAAA,CAAO,eAAA;AAAA,IACP,OAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,OAAO,EAAE,OAAA,EAAS,WAAA,EAAa,MAAA,EAAQ,UAAA,EAAW,CAAA,EAAI,CAAC,WAAA,EAAa,UAAU,CAAC,CAAA;AAEzG,EAAA,MAAM,SAAA,GAAY,OAAA;AAAA,IAChB,MACE,SAAU,EAAE,YAAA,EAAc,eAAe,YAAA,EAAc,cAAA,KAAiD,EAAC;AAAA,IAC3G,CAAC,eAAe,cAAc;AAAA,GAChC;AAEA,EAAA,OAAO;AAAA,IACL,KAAA;AAAA,IACA,sBAAsB,MAAA,CAAO,aAAA;AAAA,IAC7B,SAAA;AAAA,IACA,SAAA;AAAA,IACA,SAAA;AAAA,IACA;AAAA,GACF;AACF;AC7JA,IAAMC,OAAAA,GAASC,SAAS,EAAA,KAAO,KAAA;AAyBxB,IAAM,kBAAkBC,KAAAA,CAAM,UAAA,CAA4C,SAASC,gBAAAA,CACxF,EAAE,WAAW,KAAA,EAAO,aAAA,EAAe,aAAA,GAAgB,KAAA,EAAO,SAAS,MAAA,EAAQ,KAAA,EAAO,sBAAsB,GAAG,IAAA,IAC3G,GAAA,EACoB;AACpB,EAAA,MAAM;AAAA,IACJ,KAAA,EAAO,WAAA;AAAA,IACP,oBAAA,EAAsB,iBAAA;AAAA,IACtB,SAAA;AAAA,IACA;AAAA,MACE,cAAA,CAAe,EAAE,QAAA,EAAU,OAAA,EAAS,QAAQ,CAAA;AAIhD,EAAA,MAAM,UAAwBH,OAAAA,GAC1B;AAAA,IACE,cAAA,EAAgB,WAAW,IAAA,GAAO,MAAA;AAAA,IAClC,kBAAA,EAAoB,aAAA;AAAA,IACpB,eAAA,EAAiB,gBAAgB,IAAA,GAAO;AAAA,MAE1C,EAAC;AAEL,EAAA,uBACEL,GAAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,GAAA;AAAA,MACA,sBAAsB,oBAAA,IAAwB,iBAAA;AAAA,MAC7C,GAAG,IAAA;AAAA,MACH,GAAI,OAAA;AAAA,MACJ,GAAG,SAAA;AAAA,MACJ,SAAS,SAAA,CAAU,OAAA;AAAA,MACnB,QAAQ,SAAA,CAAU,MAAA;AAAA,MAClB,KAAA,EAAO,CAAC,KAAA,EAAO,WAAW;AAAA;AAAA,GAC5B;AAEJ,CAAC;AC1DD,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,mBAAA,GAAsB,CAAA;AAC5B,IAAM,kBAAA,GAAqB,CAAA;AAE3B,IAAME,OAAAA,GAASJ,WAAW,MAAA,CAAO;AAAA,EAC/B,KAAA,EAAO;AAAA,IACL,eAAA,EAAiB,eAAA;AAAA,IACjB,iBAAA,EAAmB,eAAA;AAAA,IACnB,YAAA,EAAc,mBAAA;AAAA,IACd,WAAA,EAAa;AAAA;AAEjB,CAAC,CAAA;AASM,IAAM,YAAY,CAAC;AAAA,EACxB,KAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,KAAA;AAAA,EACA,cAAA;AAAA,EACA,GAAG;AACL,CAAA,qBACEE,GAAAA,CAAC,KAAA,EAAA,EAAM,cAAA,EAAgC,KAAA,EAAc,KAAA,EAAc,QAAA,EAChE,QAAA,EAAA,CAAC,EAAE,aAAA,EAAe,QAAA,EAAS,qBAC1BA,GAAAA;AAAA,EAAC,eAAA;AAAA,EAAA;AAAA,IACC,iBAAA,EAAmB,SAAS,KAAK,CAAA,CAAA;AAAA,IACjC,kBAAA,EAAoB,KAAA;AAAA,IACpB,aAAA;AAAA,IACA,QAAA;AAAA,IACA,aAAA,EAAe,QAAA;AAAA,IACf,OAAOE,OAAAA,CAAO,KAAA;AAAA,IACd,MAAA,EAAO,kBAAA;AAAA,IACN,GAAG;AAAA;AACN,CAAA,EAEJ;AC1BF,IAAM,iBAAA,GAAoB,aAAA;AAC1B,IAAM,WAAA,GAAc,MAAA;AACpB,IAAM,YAAA,GAAe,EAAA;AACrB,IAAM,cAAA,GAAiB,GAAA;AACvB,IAAM,aAAA,GAAgB,EAAA;AACtB,IAAM,aAAA,GAAgB,CAAA;AACtB,IAAM,iBAAA,GAAoB,EAAA;AAC1B,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAMO,iBAAAA,GAAmB,CAAA;AACzB,IAAMC,UAAAA,GAAY,EAAA;AAClB,IAAM,WAAA,GAAc,CAAA;AACpB,IAAM,SAAA,GAAY,CAAA;AAClB,IAAM,SAAA,GAAY,CAAA;AAClB,IAAM,SAAA,GAAY,CAAA;AAMlB,IAAM,aAAA,GAAgB,EAAE,GAAA,EAAK,EAAA,EAAI,QAAQ,EAAA,EAAI,IAAA,EAAM,CAAA,EAAG,KAAA,EAAO,CAAA,EAAE;AAE/D,IAAM,WAAA,GAAc,CAAA;AAWpB,IAAM,0BAAA,GAA6B,oBAAA;AAGnC,IAAM,cAAA,GAAiB,SAAA;AAEvB,IAAM,SAAA,GAAY,KAAA;AAYlB,SAAS,WAAW,OAAA,EAAyB;AAC3C,EAAA,MAAM,MAAA,GAAS,OAAA;AACf,EAAA,OAAO,MAAA,CAAO,cAAc,CAAA,GAAI,SAAS,CAAA,IAAK,WAAA;AAChD;AAGA,SAASC,UAAAA,CAAU,KAAa,KAAA,EAAuB;AACrD,EAAA,MAAM,UAAA,GAAa,GAAA,CAAI,OAAA,CAAQ,GAAA,EAAK,EAAE,CAAA;AACtC,EAAA,MAAM,OAAA,GAAU,WAAW,MAAA,KAAWF,iBAAAA;AACtC,EAAA,MAAM,IAAA,GAAO,OAAA,GAAU,UAAA,CAAW,KAAA,CAAM,EAAE,CAAA,CAAE,GAAA,CAAI,CAAC,CAAA,KAAM,CAAA,GAAI,CAAC,CAAA,CAAE,IAAA,CAAK,EAAE,CAAA,GAAI,UAAA;AACzE,EAAA,MAAM,IAAI,QAAA,CAAS,IAAA,CAAK,MAAM,WAAA,EAAa,SAAS,GAAGC,UAAS,CAAA;AAChE,EAAA,MAAM,IAAI,QAAA,CAAS,IAAA,CAAK,MAAM,SAAA,EAAW,SAAS,GAAGA,UAAS,CAAA;AAC9D,EAAA,MAAM,IAAI,QAAA,CAAS,IAAA,CAAK,MAAM,SAAA,EAAW,SAAS,GAAGA,UAAS,CAAA;AAC9D,EAAA,MAAM,OAAA,GAAU,CAAC,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,IAAK,CAAC,MAAA,CAAO,KAAA,CAAM,CAAC,CAAA,IAAK,CAAC,MAAA,CAAO,MAAM,CAAC,CAAA;AACvE,EAAA,OAAO,OAAA,GAAU,QAAQ,CAAC,CAAA,EAAA,EAAK,CAAC,CAAA,EAAA,EAAK,CAAC,CAAA,EAAA,EAAK,KAAK,CAAA,CAAA,CAAA,GAAM,GAAA;AACxD;AAEA,IAAMR,OAAAA,GAASJ,WAAW,MAAA,CAAO;AAAA,EAC/B,aAAA,EAAe;AAAA,IACb,aAAA,EAAe,KAAA;AAAA,IACf,QAAA,EAAU,MAAA;AAAA;AAAA;AAAA;AAAA,IAIV,cAAc,CAAC;AAAA,GACjB;AAAA,EACA,WAAA,EAAa;AAAA,IACX,WAAA,EAAa,WAAA;AAAA,IACb,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,iBAAA,EAAmB,EAAA;AAAA,IACnB,eAAA,EAAiB,CAAA;AAAA,IACjB,YAAA,EAAc,YAAA;AAAA,IACd,eAAA,EAAiB,iBAAA;AAAA,IACjB,WAAA,EAAa;AAAA,GACf;AAAA,EACA,WAAA,EAAa;AAAA,IACX,iBAAA,EAAmB,aAAA;AAAA,IACnB,eAAA,EAAiB,aAAA;AAAA,IACjB,YAAA,EAAc,cAAA;AAAA,IACd,WAAA,EAAa;AAAA,GACf;AAAA,EACA,UAAU,EAAC;AAAA,EACX,eAAA,EAAiB,EAAE,QAAA,EAAU,iBAAA;AAC/B,CAAC,CAAA;AAoGM,SAAS,YAAA,CACd,MAAA,EACA,QAAA,EACA,MAAA,EACoE;AACpE,EAAA,OAAO;AAAA,IACL,MAAA,EAAQ,GAAG,MAAA,CAAO,MAAM,IAAI,MAAA,CAAO,MAAA,CAAO,KAAK,CAAC,CAAA,CAAA;AAAA;AAAA;AAAA,IAGhD,iBAAA,EAAmB,MAAA,CAAO,IAAA,IAAQ,CAAA,QAAA,EAAW,OAAO,KAAK,CAAA,CAAA;AAAA,IACzD,WAAA,EAAa,MAAA,CAAO,QAAA,GAAW,QAAA,GAAW;AAAA,GAC5C;AACF;AAGA,SAAS,WAAA,CAAuC;AAAA,EAC9C,MAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,iBAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAA+D;AAC7D,EAAA,MAAM,CAAC,OAAA,EAAS,UAAU,CAAA,GAAIS,KAAAA,CAAM,SAAS,KAAK,CAAA;AAClD,EAAA,MAAM,SAAS,QAAA,IAAY,OAAA;AAE3B,EAAA,MAAM,WAAA,GAAc,MAAA,GAAS,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,MAAA;AACrD,EAAA,MAAM,eAAA,GAAkB,QAAA,GAAW,MAAA,CAAO,IAAA,GAAO,MAAA,CAAO,KAAA;AAGxD,EAAA,MAAM,SAAA,GAAY,MAAA,GAAS,MAAA,CAAO,OAAA,GAAU,MAAA,CAAO,SAAA;AAEnD,EAAA,uBACEP,GAAAA;AAAA,IAAC,SAAA;AAAA,IAAA;AAAA,MACC,iBAAA;AAAA,MACA,oBAAoB,MAAA,CAAO,KAAA;AAAA,MAC3B,iBAAA,EAAkB,QAAA;AAAA,MAClB,kBAAA,EAAoB,EAAE,QAAA,EAAU,QAAA,EAAS;AAAA,MACzC,cAAA,EAAc,WAAA;AAAA,MACd,QAAA;AAAA,MACA,OAAA,EAAS,aAAA;AAAA,MACT,OAAOE,OAAAA,CAAO,WAAA;AAAA,MACd,MAAA;AAAA,MACA,SAAA,EAAW,MAAM,UAAA,CAAW,IAAI,CAAA;AAAA,MAChC,UAAA,EAAY,MAAM,UAAA,CAAW,KAAK,CAAA;AAAA,MAClC,OAAA;AAAA,MAEA,QAAA,kBAAAF,GAAAA,CAACG,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACD,OAAAA,CAAO,WAAA,EAAa,EAAE,WAAA,EAAa,eAAA,EAAiB,GAChE,QAAA,kBAAAF,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACC,OAAAA,CAAO,QAAA,EAAUA,OAAAA,CAAO,eAAA,EAAiB,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA,EAAI,QAAA,EAAA,MAAA,CAAO,OAAM,CAAA,EAC9F;AAAA;AAAA,GACF;AAEJ;AAGA,SAAS,SAAA,CAAqC;AAAA,EAC5C,MAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA,MAAA;AAAA,EACA,iBAAA;AAAA,EACA,WAAA;AAAA,EACA;AACF,CAAA,EAA+D;AAC7D,EAAA,MAAM,eAAA,GAAkB,QAAA,GAAW,MAAA,CAAO,OAAA,GAAU,iBAAA;AACpD,EAAA,MAAM,SAAA,GAAY,QAAA,GAAW,MAAA,CAAO,SAAA,GAAY,MAAA,CAAO,UAAA;AACvD,EAAA,uBACEF,GAAAA;AAAA,IAAC,gBAAA;AAAA,IAAA;AAAA,MACC,iBAAA;AAAA,MACA,oBAAoB,MAAA,CAAO,KAAA;AAAA,MAC3B,iBAAA,EAAkB,QAAA;AAAA,MAClB,kBAAA,EAAoB,EAAE,QAAA,EAAU,QAAA,EAAS;AAAA,MACzC,cAAA,EAAc,WAAA;AAAA,MACd,QAAA;AAAA,MACA,OAAA,EAAS,aAAA;AAAA,MACT,OAAOE,OAAAA,CAAO,WAAA;AAAA,MACd,MAAA;AAAA,MACA,OAAA;AAAA,MAEA,QAAA,kBAAAF,GAAAA,CAACG,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACD,OAAAA,CAAO,IAAA,EAAM,EAAE,WAAA,EAAa,MAAA,CAAO,MAAA,EAAQ,iBAAiB,CAAA,EACxE,QAAA,kBAAAF,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACC,OAAAA,CAAO,QAAA,EAAU,EAAE,KAAA,EAAO,SAAA,EAAW,CAAA,EAAI,QAAA,EAAA,MAAA,CAAO,OAAM,CAAA,EACtE;AAAA;AAAA,GACF;AAEJ;AAEA,IAAMG,OAAAA,GAASC,SAAS,EAAA,KAAO,KAAA;AAG/B,SAAS,cAAA,CAAe,eAAmC,QAAA,EAAiC;AAC1F,EAAA,IAAI,CAACD,OAAAA,EAAQ,OAAO,EAAC;AACrB,EAAA,OAAO,EAAE,cAAA,EAAgB,QAAA,GAAW,IAAA,GAAO,MAAA,EAAW,oBAAoB,aAAA,EAAc;AAC1F;AAEO,IAAM,eAAe,CAA4B;AAAA,EACtD,KAAA;AAAA,EACA,OAAA;AAAA,EACA,KAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,QAAA,GAAW,KAAA;AAAA,EACX,OAAA,GAAU,OAAA;AAAA,EACV,cAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,KAAA;AAAA,EACA,MAAA;AAAA,EACA,gBAAA,GAAmB,0BAAA;AAAA,EACnB;AACF,CAAA,KAAgD;AAC9C,EAAA,MAAM,EAAE,KAAA,EAAM,GAAID,KAAAA,EAAM;AACxB,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAQ,GAAI,KAAA;AAE5B,EAAA,MAAM,UAAA,GAAaG,KAAAA,CAAM,OAAA,CAAoB,MAAM;AACjD,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AACrC,IAAA,OAAO;AAAA,MACL,QAAQ,MAAA,CAAO,MAAA;AAAA,MACf,YAAY,MAAA,CAAO,IAAA;AAAA,MACnB,WAAW,MAAA,CAAO,aAAA;AAAA,MAClB,OAAA;AAAA,MACA,SAAA,EAAW,WAAW,OAAO,CAAA;AAAA,MAC7B,OAAO,MAAA,CAAO,UAAA;AAAA,MACd,IAAA,EAAMI,UAAAA,CAAU,OAAA,EAAS,kBAAkB;AAAA,KAC7C;AAAA,EACF,CAAA,EAAG,CAAC,MAAA,CAAO,MAAA,EAAQ,MAAA,CAAO,IAAA,EAAM,MAAA,CAAO,aAAA,EAAe,MAAA,CAAO,UAAA,EAAY,OAAO,CAAC,CAAA;AAEjF,EAAA,SAAS,WAAW,WAAA,EAAyB;AAC3C,IAAA,IAAI,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA;AACjC,MAAA,OAAO,KAAA,CAAM,SAAS,WAAW,CAAA;AAEnC,IAAA,OAAO,KAAA,KAAU,WAAA;AAAA,EACnB;AAEA,EAAA,SAAS,WAAW,MAAA,EAA2C;AAC7D,IAAA,MAAM,QAAA,GAAW,UAAA,CAAW,MAAA,CAAO,KAAK,CAAA;AACxC,IAAA,MAAM,SAAA,GAAY;AAAA,MAChB,MAAA,EAAQ,UAAA;AAAA,MACR,QAAA;AAAA,MACA,MAAA;AAAA,MACA,QAAA;AAAA,MACA,GAAG,YAAA,CAAa,MAAA,EAAQ,QAAA,EAAU;AAAA,QAChC,MAAA,EAAQ,gBAAA;AAAA,QACR,IAAA,EAAM,uBAAA;AAAA,QACN;AAAA,OACD,CAAA;AAAA,MACD,OAAA,EAAS,MAAY,QAAA,CAAS,MAAA,CAAO,KAAK;AAAA,KAC5C;AACA,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,MAAA,CAAO,KAAK,CAAA;AAC/B,IAAA,OAAO,OAAA,KAAY,SAAA,mBAAYX,GAAAA,CAAC,eAAuB,GAAG,SAAA,EAAA,EAAT,GAAoB,CAAA,mBAAKA,GAAAA,CAAC,SAAA,EAAA,EAAqB,GAAG,aAAT,GAAoB,CAAA;AAAA,EAChH;AAEA,EAAA,uBACEA,GAAAA,CAAC,KAAA,EAAA,EAAM,cAAA,EAAgC,KAAA,EAAc,KAAA,EAAc,QAAA,EAAoB,MAAA,EACpF,QAAA,EAAA,CAAC,EAAE,aAAA,EAAe,QAAA,EAAS,qBAC1BA,GAAAA,CAACG,IAAAA,EAAA,EAAK,KAAA,EAAOD,OAAAA,CAAO,aAAA,EAAgB,GAAI,cAAA,CAAe,aAAA,EAAe,QAAQ,CAAA,EAC3E,QAAA,EAAA,OAAA,CAAQ,GAAA,CAAI,UAAU,GACzB,CAAA,EAEJ,CAAA;AAEJ;AC5XA,IAAM,qBAAA,GAAwB,EAAA;AAE9B,IAAMA,OAAAA,GAASJ,WAAW,MAAA,CAAO;AAAA,EAC/B,SAAA,EAAW;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,cAAA,EAAgB,eAAA;AAAA,IAChB,UAAA,EAAY,QAAA;AAAA,IACZ,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,UAAA,EAAY;AAAA,IACV,IAAA,EAAM;AAAA,GACR;AAAA,EACA,KAAA,EAAO;AAAA,IACL,UAAA,EAAY;AAAA,GACd;AAAA,EACA,WAAA,EAAa;AAAA,IACX,QAAA,EAAU,qBAAA;AAAA,IACV,SAAA,EAAW;AAAA;AAEf,CAAC,CAAA;AAkBM,IAAM,aAAa,CAAC;AAAA,EACzB,KAAA;AAAA,EACA,KAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,WAAA;AAAA,EACA,cAAA;AAAA,EACA,MAAA,GAAS,aAAA;AAAA,EACT;AACF,CAAA,KAA2C;AACzC,EAAA,MAAM,EAAE,KAAA,EAAM,GAAIM,KAAAA,EAAM;AACxB,EAAA,MAAM,EAAE,QAAO,GAAI,KAAA;AACnB,EAAA,MAAM,cAAA,GAAiB,OAAO,WAAA,KAAgB,QAAA,IAAY,WAAA,KAAgB,EAAA;AAE1E,EAAA,MAAM,WAAA,GAAcG,KAAAA,CAAM,OAAA,CAAqB,MAAM;AACnD,IAAA,MAAM,UAAA,GAAwB,EAAE,KAAA,EAAO,MAAA,CAAO,IAAA,EAAK;AACnD,IAAA,MAAM,gBAAA,GAA8B,EAAE,KAAA,EAAO,MAAA,CAAO,aAAA,EAAc;AAClE,IAAA,OAAO,EAAE,KAAA,EAAO,UAAA,EAAY,WAAA,EAAa,gBAAA,EAAiB;AAAA,EAC5D,GAAG,CAAC,MAAA,CAAO,IAAA,EAAM,MAAA,CAAO,aAAa,CAAC,CAAA;AAEtC,EAAA,uBACER,IAAAA;AAAA,IAACI,IAAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO;AAAA,QACLD,OAAAA,CAAO,SAAA;AAAA,QACP;AAAA,OACF;AAAA,MAEA,QAAA,EAAA;AAAA,wBAAAH,IAAAA,CAACI,IAAAA,EAAA,EAAK,KAAA,EAAOD,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,0BAAAF,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACC,QAAO,KAAA,EAAO,WAAA,CAAY,KAAK,CAAA,EAAI,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,UACtD,cAAA,mBACCF,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACC,OAAAA,CAAO,WAAA,EAAa,WAAA,CAAY,WAAW,CAAA,EAAI,uBAAY,CAAA,GACvE;AAAA,SAAA,EACN,CAAA;AAAA,wBACAF,GAAAA;AAAA,UAAC,MAAA;AAAA,UAAA;AAAA,YACC,mBAAmB,iBAAA,IAAqB,KAAA;AAAA,YACxC,kBAAA,EAAoB,KAAA;AAAA,YACpB,iBAAA,EAAkB,QAAA;AAAA,YAClB,kBAAA,EAAoB,EAAE,OAAA,EAAS,KAAA,EAAM;AAAA,YACrC,QAAA;AAAA,YACA,MAAA;AAAA,YACA,KAAA;AAAA,YACA;AAAA;AAAA;AACF;AAAA;AAAA,GACF;AAEJ;ACrEA,IAAM,eAAA,GAAkB,CAAC,OAAA,EAAS,GAAA,EAAK,UAAU,CAAA;AAEjD,IAAMY,eAAAA,GAAiB,EAAA;AACvB,IAAM,QAAA,GAAW,EAAA;AACjB,IAAM,UAAA,GAAa,CAAA;AACnB,IAAM,eAAA,GAAkB,EAAA;AACxB,IAAM,gBAAA,GAAmB,GAAA;AAEzB,IAAMV,OAAAA,GAASJ,WAAW,MAAA,CAAO;AAAA,EAC/B,SAAA,EAAW;AAAA,IACT,aAAA,EAAe,KAAA;AAAA,IACf,UAAA,EAAY,YAAA;AAAA,IACZ,GAAA,EAAK,EAAA;AAAA,IACL,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,GAAA,EAAK;AAAA,IACH,KAAA,EAAO,QAAA;AAAA,IACP,MAAA,EAAQ,QAAA;AAAA,IACR,YAAA,EAAc,UAAA;AAAA,IACd,WAAA,EAAa,CAAA;AAAA,IACb,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB,QAAA;AAAA;AAAA,IAEhB,SAAA,EAAW;AAAA,GACb;AAAA,EACA,KAAA,EAAO;AAAA,IACL,QAAA,EAAU,eAAA;AAAA,IACV,UAAA,EAAY,KAAA;AAAA,IACZ,UAAA,EAAY;AAAA,GACd;AAAA,EACA,UAAA,EAAY;AAAA,IACV,IAAA,EAAM;AAAA,GACR;AAAA,EACA,KAAA,EAAO;AAAA,IACL,UAAA,EAAY;AAAA,GACd;AAAA,EACA,IAAA,EAAM;AAAA,IACJ,QAAA,EAAUc,eAAAA;AAAA,IACV,SAAA,EAAW;AAAA;AAEf,CAAC,CAAA;AAmBM,IAAM,eAAe,CAAC;AAAA,EAC3B,KAAA;AAAA,EACA,KAAA;AAAA,EACA,aAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,WAAA;AAAA,EACA,QAAA,GAAW,KAAA;AAAA,EACX,cAAA;AAAA,EACA,MAAA,GAAS,eAAA;AAAA,EACT,kBAAA;AAAA,EACA;AACF,CAAA,KAA6C;AAC3C,EAAA,MAAM,EAAE,KAAA,EAAM,GAAIR,KAAAA,EAAM;AACxB,EAAA,MAAM,EAAE,MAAA,EAAQ,OAAA,EAAQ,GAAI,KAAA;AAC5B,EAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AACnC,EAAA,MAAM,WAAW,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,KAAK,IAAA,GAAO,WAAA;AAClE,EAAA,MAAM,OAAA,GAAU,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,KAAa,EAAA;AAE7D,EAAA,MAAM,WAAA,GAAcG,KAAAA,CAAM,OAAA,CAAQ,MAAM;AACtC,IAAA,MAAM,KAAA,GAAmB,EAAE,eAAA,EAAiB,KAAA,EAAO,aAAa,KAAA,EAAM;AACtE,IAAA,MAAM,SAAoB,EAAE,eAAA,EAAiB,aAAA,EAAe,WAAA,EAAa,OAAO,MAAA,EAAO;AACvF,IAAA,MAAM,UAAA,GAAwB,EAAE,KAAA,EAAO,MAAA,CAAO,IAAA,EAAK;AACnD,IAAA,MAAM,SAAA,GAAuB,EAAE,KAAA,EAAO,MAAA,CAAO,aAAA,EAAc;AAC3D,IAAA,OAAO,EAAE,KAAA,EAAO,MAAA,EAAQ,KAAA,EAAO,UAAA,EAAY,MAAM,SAAA,EAAU;AAAA,EAC7D,CAAA,EAAG,CAAC,KAAA,EAAO,MAAA,CAAO,QAAQ,MAAA,CAAO,IAAA,EAAM,MAAA,CAAO,aAAa,CAAC,CAAA;AAE5D,EAAA,MAAM,SAAS,MAAY;AACzB,IAAA,MAAM,OAAO,CAAC,KAAA;AACd,IAAA,IAAI,aAAA,gBAA6B,IAAI,CAAA;AACrC,IAAA,IAAI,QAAA,WAAmB,IAAI,CAAA;AAAA,EAC7B,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,KAAA,KAA+D;AACpF,IAAA,IAAI,QAAA,EAAU;AACd,IAAA,MAAM,GAAA,GAAM,MAAM,GAAA,IAAO,EAAA;AACzB,IAAA,IAAI,CAAC,eAAA,CAAgB,QAAA,CAAS,GAAG,CAAA,EAAG;AACpC,IAAA,IAAI,OAAO,KAAA,CAAM,cAAA,KAAmB,UAAA,QAAkB,cAAA,EAAe;AACrE,IAAA,MAAA,EAAO;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,aAAA,GAAkCD,SAAS,EAAA,KAAO,KAAA,GAAQ,EAAE,SAAA,EAAW,aAAA,KAAkB,EAAC;AAEhG,EAAA,uBACEP,IAAAA;AAAA,IAACc,SAAAA;AAAA,IAAA;AAAA,MACC,mBAAmB,iBAAA,IAAqB,KAAA;AAAA,MACxC,oBAAoB,kBAAA,IAAsB,KAAA;AAAA,MAC1C,iBAAA,EAAkB,UAAA;AAAA,MAClB,kBAAA,EAAoB,EAAE,OAAA,EAAS,KAAA,EAAO,QAAA,EAAS;AAAA,MAE/C,cAAA,EAAc,KAAA;AAAA,MACd,QAAA;AAAA,MACA,OAAA,EAAS,MAAA;AAAA,MACT,IAAA,EAAK,UAAA;AAAA,MACL,KAAA,EAAO,CAACX,OAAAA,CAAO,SAAA,EAAW,cAAA,EAAgB,WAAW,EAAE,OAAA,EAAS,gBAAA,EAAiB,GAAI,IAAI,CAAA;AAAA,MACzF,MAAA;AAAA,MACC,GAAG,aAAA;AAAA,MAEJ,QAAA,EAAA;AAAA,wBAAAF,GAAAA,CAACG,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACD,OAAAA,CAAO,GAAA,EAAK,KAAA,GAAQ,WAAA,CAAY,KAAA,GAAQ,WAAA,CAAY,MAAM,CAAA,EACrE,kCACCF,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACC,OAAAA,CAAO,KAAA,EAAO,EAAE,KAAA,EAAO,MAAA,CAAO,OAAA,EAAS,CAAA,EAAG,2BAAA,EAA2B,IAAA,EAAC,QAAA,EAAA,QAAA,EAEpF,IACE,IAAA,EACN,CAAA;AAAA,wBACAH,IAAAA,CAACI,IAAAA,EAAA,EAAK,KAAA,EAAOD,QAAO,UAAA,EAClB,QAAA,EAAA;AAAA,0BAAAF,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACC,QAAO,KAAA,EAAO,WAAA,CAAY,KAAK,CAAA,EAAI,QAAA,EAAA,KAAA,EAAM,CAAA;AAAA,UACtD,OAAA,mBAAUF,GAAAA,CAACC,IAAAA,EAAA,EAAK,KAAA,EAAO,CAACC,OAAAA,CAAO,IAAA,EAAM,WAAA,CAAY,IAAI,CAAA,EAAI,oBAAS,CAAA,GAAU;AAAA,SAAA,EAC/E;AAAA;AAAA;AAAA,GACF;AAEJ","file":"index.mjs","sourcesContent":["/**\n * `FieldLabel` — the label row of a `Field`: the label text plus at most one marker.\n *\n * Split out of `Field` so the marker rules and the two label voices stay readable, and so `Field`\n * itself remains an orchestrator small enough to review.\n */\nimport React from 'react';\n\nimport { Text, type StyleProp, type TextStyle } from 'react-native';\n\nimport type { FieldMarker } from './fieldMarkers';\n\nexport interface FieldLabelProps {\n label: string;\n marker: FieldMarker;\n /** Pre-localized text for the optional marker. Ignored unless `marker` is `optional`. */\n optionalLabel: string;\n /** Composed style chain: base → variant → caller's `labelStyle` (applied last). */\n style: StyleProp<TextStyle>;\n requiredMarkStyle: StyleProp<TextStyle>;\n optionalMarkStyle: StyleProp<TextStyle>;\n}\n\nexport function FieldLabel({\n label,\n marker,\n optionalLabel,\n style,\n requiredMarkStyle,\n optionalMarkStyle,\n}: FieldLabelProps): React.ReactElement {\n return (\n <Text style={style}>\n {label}{' '}\n {marker === 'required' ? (\n // The asterisk is decorative — the control's `aria-required` conveys \"required\" to\n // assistive tech, so a screen reader says \"required\" instead of \"star\".\n <Text aria-hidden accessibilityElementsHidden importantForAccessibility=\"no\" style={requiredMarkStyle}>\n *\n </Text>\n ) : null}\n {marker === 'optional' && optionalLabel !== '' ? (\n // Also decorative: \"optional\" is the ABSENCE of `aria-required`, which assistive tech\n // already conveys. Rendering it to a screen reader would double-announce the same fact.\n <Text aria-hidden accessibilityElementsHidden importantForAccessibility=\"no\" style={optionalMarkStyle}>\n {optionalLabel}\n </Text>\n ) : null}\n </Text>\n );\n}\n\nexport default FieldLabel;\n","/**\n * Required / optional markers, per the shared forms contract\n * (`…/wwwroot/shared/FORMS.md` → \"Required and optional markers\").\n *\n * The contract says the two markers are MUTUALLY EXCLUSIVE — a field is required or optional, never\n * annotated as both — and that you mark the MINORITY: on a mostly-required form mark the optional\n * fields, on a mostly-optional form mark the required ones. Asterisking twelve of thirteen fields\n * is noise that trains the eye to ignore the marker.\n *\n * Exclusivity is enforced here rather than in the type system so that a caller spreading a props\n * object (`<Field {...fieldProps} />`, where both flags may be computed) still gets a defined,\n * single-marker result instead of a compile error it cannot act on.\n *\n * Precedence when a caller asks for BOTH: `required` wins. That is the safe failure direction —\n * showing \"optional\" on a field the server will reject sends the user into a failed submit, while\n * showing \"required\" on a genuinely optional field costs, at worst, an unnecessary keystroke.\n */\n\n/** Which marker a field label carries. Exactly one, never both. */\nexport type FieldMarker = 'none' | 'required' | 'optional';\n\n/**\n * The English fallback for the optional marker's text.\n *\n * `@dloizides/ui-forms` contains NO i18n runtime by design — aml-v2 uses `@dloizides/i18n` with\n * positional `{0}` params while the other six apps use i18next `{{p1}}`, and nothing bridges them,\n * so all user-visible copy arrives as pre-localized props. This constant exists ONLY so a\n * single-locale app can adopt `optional` in one line. It is exported precisely so it is greppable:\n * **a localized app MUST pass `optionalLabel`.** The required marker needs no such escape — `*` is\n * a glyph, not copy.\n */\nexport const DEFAULT_OPTIONAL_LABEL = '(optional)';\n\n/**\n * Resolve the two boolean flags to the single marker actually rendered.\n * `required` beats `optional`; neither flag yields `none`.\n */\nexport function resolveFieldMarker(required: boolean, optional: boolean): FieldMarker {\n if (required) return 'required';\n if (optional) return 'optional';\n return 'none';\n}\n","/**\n * The TWO legitimate label voices, per the shared forms contract\n * (`PROOViD/AMLService/AMLService/wwwroot/shared/FORMS.md` → \"The TWO legitimate label voices\").\n *\n * - `field` — 13 / 600 / sentence case. A label that is READ: prose addressed to the person\n * filling the form. This is `Field`'s historical, unchanged default, so every\n * existing consumer renders byte-identically.\n * - `control` — 11 / 700 / UPPERCASE + letter-spacing. A label that is SCANNED: a key over a value\n * in a dense row (filter bars, compact toolbars, pager controls). These are exactly\n * the metrics `@dloizides/ui-tables` forked into its private `FieldShell` because\n * `Field` hard-coded the `field` voice and offered no way out.\n *\n * A THIRD voice is drift, not a variant. Pick the voice from the SURFACE, not the component: every\n * label on one surface uses one voice, and voices are never mixed within a single row.\n *\n * Why a plain string union and not a `const enum`: this type crosses the package boundary into\n * consumers' `.d.ts`, and a cross-boundary `const enum` breaks `isolatedModules` / Babel-only\n * builds. `@dloizides/ui-buttons` sets the same precedent for `ButtonVariant` for the same reason.\n */\nimport { StyleSheet, type TextStyle } from 'react-native';\n\n/** Which of the two contract voices a field label speaks. */\nexport type FieldLabelVariant = 'field' | 'control';\n\n/** The historical `Field` label metrics. Changing these moves pixels in every consumer. */\nconst FIELD_FONT_SIZE = 13;\nconst FIELD_FONT_WEIGHT = '600';\n\n/** The dense-control metrics, taken verbatim from `ui-tables`' `FieldShell` fork so it can retire. */\nconst CONTROL_FONT_SIZE = 11;\nconst CONTROL_FONT_WEIGHT = '700';\nconst CONTROL_LETTER_SPACING = 0.4;\n\nexport const labelVariantStyles = StyleSheet.create({\n field: {\n fontSize: FIELD_FONT_SIZE,\n fontWeight: FIELD_FONT_WEIGHT,\n },\n control: {\n fontSize: CONTROL_FONT_SIZE,\n fontWeight: CONTROL_FONT_WEIGHT,\n letterSpacing: CONTROL_LETTER_SPACING,\n textTransform: 'uppercase',\n },\n});\n\n/**\n * Resolve a variant name to its style. An unknown/absent variant falls back to `field` — the\n * historical default — so a bad value degrades to \"unchanged\" rather than to \"unstyled\".\n */\nexport function resolveLabelVariantStyle(variant?: FieldLabelVariant): TextStyle {\n return variant === 'control' ? labelVariantStyles.control : labelVariantStyles.field;\n}\n","/**\n * Field — the generic \"label over a control, hint + error under it\" wrapper.\n *\n * `FormField` is hard-wired to a text input, so any NON-text control (a dropdown, a date picker,\n * a chip selector) had no shared way to get a label — and ended up visually misaligned next to\n * its `FormField` siblings: its box started a label-row higher, and it missed the container's\n * bottom margin so wrapped rows lost their vertical rhythm.\n *\n * `Field` is that label row + spacing, control-agnostic. Its metrics are the single source of\n * truth: `FormField` composes `Field` internally, so the two can never drift apart.\n *\n * Children may be a plain node (the common case — just wrap your control) or a render function\n * receiving `{ describedById, hasError }`, so a custom control can wire the hint AND error lines\n * into its own `aria-describedby` / invalid state exactly the way `FormField` does.\n *\n * The anatomy (label → control → hint → error), the two label voices, the mutually-exclusive\n * required/optional markers and the collapsing error slot all implement the shared cross-stack\n * contract in `PROOViD/AMLService/AMLService/wwwroot/shared/FORMS.md`.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, type StyleProp, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { FieldLabel } from './FieldLabel';\nimport { DEFAULT_OPTIONAL_LABEL, resolveFieldMarker } from './fieldMarkers';\nimport { resolveLabelVariantStyle, type FieldLabelVariant } from './labelVariants';\n\n/** Bottom margin of the whole field block — the vertical rhythm every form row shares. */\nconst CONTAINER_MARGIN_BOTTOM = 16;\nconst LABEL_MARGIN_BOTTOM = 4;\nconst ERROR_FONT_SIZE = 12;\nconst ERROR_MARGIN_TOP = 4;\nconst HINT_FONT_SIZE = 12;\nconst HINT_MARGIN_TOP = 4;\n/** The optional marker drops to normal weight so it reads as an aside inside a 600 label. */\nconst OPTIONAL_MARK_FONT_WEIGHT = '400';\n\nconst styles = StyleSheet.create({\n container: {\n marginBottom: CONTAINER_MARGIN_BOTTOM,\n },\n label: {\n marginBottom: LABEL_MARGIN_BOTTOM,\n },\n hintText: {\n fontSize: HINT_FONT_SIZE,\n marginTop: HINT_MARGIN_TOP,\n },\n errorText: {\n fontSize: ERROR_FONT_SIZE,\n marginTop: ERROR_MARGIN_TOP,\n },\n optionalMark: {\n fontWeight: OPTIONAL_MARK_FONT_WEIGHT,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n requiredMark: TextStyle;\n optionalMark: TextStyle;\n hintText: TextStyle;\n errorText: TextStyle;\n}\n\n/** What a render-function child receives, so it can mirror `FormField`'s error wiring. */\nexport interface FieldChildContext {\n /**\n * Space-separated ids of the lines describing this control — the hint, the error, or both, in\n * reading order. `undefined` when there is neither. Assign straight to `aria-describedby`.\n */\n describedById?: string;\n hasError: boolean;\n}\n\nexport type FieldChildren = React.ReactNode | ((context: FieldChildContext) => React.ReactNode);\n\nexport interface FieldProps {\n /**\n * Label shown above the control. Optional so a control whose label is supplied elsewhere (or\n * which genuinely has none) can still use the shared shell for its error line + spacing: an\n * absent or empty label renders NO label row at all, rather than an empty one that would add a\n * phantom gap and misalign the control against its labelled siblings.\n */\n label?: string;\n children: FieldChildren;\n required?: boolean;\n /**\n * Marks the field explicitly optional. MUTUALLY EXCLUSIVE with `required` — if both are set,\n * `required` wins (the safe direction: an under-marked required field causes a failed submit).\n * Use it to mark the MINORITY: on a mostly-required form, marking the two optional fields is far\n * less noise than asterisking the other eleven.\n */\n optional?: boolean;\n /**\n * Pre-localized text for the optional marker. Defaults to the English `DEFAULT_OPTIONAL_LABEL`\n * so a single-locale app can adopt `optional` in one line; a localized app MUST pass this.\n */\n optionalLabel?: string;\n /**\n * Help line rendered UNDER the control and ABOVE the error — the sentence that stops the user\n * guessing. It coexists with `error` (the hint states the rule, the error says which rule was\n * broken) and both are reachable from the control via `aria-describedby`.\n *\n * Rendering a hint INSIDE the field is the point: as an outside sibling it lands past the\n * container's 16px bottom margin and detaches from the control it explains.\n */\n hint?: string;\n error?: string;\n /**\n * Which of the two contract label voices to speak: `field` (13/600 sentence case — the default,\n * unchanged) or `control` (11/700 uppercase — dense filter bars and toolbars).\n */\n labelVariant?: FieldLabelVariant;\n /**\n * Escape hatch applied AFTER `labelVariant`, for the genuine one-off a variant does not cover.\n * Prefer `labelVariant`: it is the reviewable, named choice, and a bare `labelStyle` is the thing\n * to grep for when auditing label drift.\n */\n labelStyle?: StyleProp<TextStyle>;\n /**\n * `StyleProp` (not a bare `ViewStyle`) so a caller can compose an array — e.g. a base field style\n * plus a `grow` modifier — instead of having to restate a COMPLETE style per variant.\n */\n containerStyle?: StyleProp<ViewStyle>;\n testID?: string;\n}\n\nlet fieldSeq = 0;\n/**\n * Stable-per-instance id pair so the hint and error lines can be linked to the control via\n * `aria-describedby`. One counter bump per field keeps the two ids of a field in lockstep.\n */\nexport function useFieldIds(): { hintId: string; errorId: string } {\n const [ids] = React.useState(() => {\n fieldSeq += 1;\n const seq = String(fieldSeq);\n return { hintId: `field-hint-${seq}`, errorId: `field-error-${seq}` };\n });\n return ids;\n}\n\n/** Stable-per-instance id so the error line can be linked to the control via aria-describedby. */\nexport function useFieldErrorId(): string {\n return useFieldIds().errorId;\n}\n\n/** True only for a present, non-empty string. */\nfunction isPresent(value?: string): boolean {\n return typeof value === 'string' && value !== '';\n}\n\n/** True only for a present, non-empty error string. */\nexport function hasFieldError(error?: string): boolean {\n return isPresent(error);\n}\n\n/**\n * Join the ids of the lines describing the control, in reading order (hint then error), skipping\n * any that is not rendered. `undefined` — not `''` — when there is nothing, so the attribute is\n * omitted entirely rather than emitted empty.\n */\nexport function joinDescribedBy(hintId?: string, errorId?: string): string | undefined {\n const ids = [hintId, errorId].filter((id): id is string => isPresent(id));\n return ids.length > 0 ? ids.join(' ') : undefined;\n}\n\nexport const Field = ({\n label,\n children,\n required = false,\n optional = false,\n optionalLabel = DEFAULT_OPTIONAL_LABEL,\n hint,\n error,\n labelVariant,\n labelStyle,\n containerStyle,\n testID,\n}: FieldProps): React.ReactElement => {\n const { theme } = useUi();\n const { colors, semantic } = theme;\n const errorColor = semantic.error['500'];\n const hasError = hasFieldError(error);\n const hasHint = isPresent(hint);\n const labelText = label ?? '';\n const hasLabel = labelText !== '';\n const marker = resolveFieldMarker(required, optional);\n const { hintId, errorId } = useFieldIds();\n\n const themeStyles = React.useMemo<ThemeStyles>(\n () => ({\n label: { color: colors.textSecondary },\n requiredMark: { color: errorColor },\n // The optional marker is an aside, so it sits a step back from the label's own ink.\n optionalMark: { color: colors.textSecondary },\n hintText: { color: colors.textSecondary },\n errorText: { color: errorColor },\n }),\n [colors.textSecondary, errorColor],\n );\n\n const describedById = joinDescribedBy(hasHint ? hintId : undefined, hasError ? errorId : undefined);\n\n const control = typeof children === 'function' ? children({ describedById, hasError }) : children;\n\n return (\n <View style={[styles.container, containerStyle]} testID={testID}>\n {hasLabel ? (\n <FieldLabel\n label={labelText}\n marker={marker}\n optionalLabel={optionalLabel}\n optionalMarkStyle={[styles.optionalMark, themeStyles.optionalMark]}\n requiredMarkStyle={themeStyles.requiredMark}\n style={[styles.label, resolveLabelVariantStyle(labelVariant), themeStyles.label, labelStyle]}\n />\n ) : null}\n {control}\n {hasHint ? (\n <Text nativeID={hintId} style={[styles.hintText, themeStyles.hintText]}>\n {hint}\n </Text>\n ) : null}\n {hasError ? (\n <Text nativeID={errorId} role=\"alert\" style={[styles.errorText, themeStyles.errorText]}>\n {error}\n </Text>\n ) : null}\n </View>\n );\n};\n\nexport default Field;\n","/**\n * `FormActions` — the submit/cancel button row every form ends with.\n *\n * Promoted from the BYTE-IDENTICAL `erevna-web/src/components/Forms/FormActions.tsx` and\n * `katalogos-web/src/components/Forms/FormActions.tsx` (68 lines each, `diff` returns nothing);\n * all seven apps hand-roll the same row. Buttons come from the shared `@dloizides/ui-buttons` kit\n * rather than being forked here, so there is exactly one button implementation in the estate.\n *\n * The layout implements the contract's actions row\n * (`…/wwwroot/shared/FORMS.md` → \"Actions row\"): the primary action is LAST in DOM order, so tab\n * order reaches Cancel before Save, and `saving` drives the primary button's spinner rather than\n * disabling-and-relabelling it.\n *\n * Two minimal generalizations over the app-local twins:\n * 1. Labels and hints arrive as PRE-LOCALIZED props. The twins called `FM()` internally, which\n * cannot work here: aml-v2 localizes via `@dloizides/i18n` with positional `{0}` params while\n * the other six use i18next `{{p1}}`, and nothing bridges them.\n * 2. `testID`s are overridable but default to the twins' `save-button` / `cancel-button`, so the\n * existing Playwright selectors in every app keep matching.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, type StyleProp, type ViewStyle } from 'react-native';\n\nimport { Button } from '@dloizides/ui-buttons';\n\n/** Gap between the actions, matching the contract's `.actions { gap: 12px }`. */\nconst ACTIONS_GAP = 12;\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n justifyContent: 'flex-end',\n gap: ACTIONS_GAP,\n },\n});\n\nexport interface FormActionsProps {\n /** Submit handler. May be async — the shared Button drives its own spinner for the promise. */\n onSave: () => void | Promise<unknown>;\n /** Cancel handler. Omit it entirely to render a save-only row (no empty Cancel slot). */\n onCancel?: () => void | Promise<unknown>;\n /** Pre-localized label for the primary action. */\n saveLabel: string;\n /** Pre-localized label for the cancel action. Required whenever `onCancel` is supplied. */\n cancelLabel?: string;\n /** Pre-localized accessibility hint for the primary action. Falls back to its label. */\n saveHint?: string;\n /** Pre-localized accessibility hint for the cancel action. Falls back to its label. */\n cancelHint?: string;\n /** In-flight submit: spins the primary action and disables cancel so the form can't be abandoned mid-write. */\n saving?: boolean;\n /** Disables the primary action independently of `saving` (e.g. an invalid form). */\n saveDisabled?: boolean;\n containerStyle?: StyleProp<ViewStyle>;\n saveTestID?: string;\n cancelTestID?: string;\n testID?: string;\n}\n\nexport const FormActions = ({\n onSave,\n onCancel,\n saveLabel,\n cancelLabel = '',\n saveHint,\n cancelHint,\n saving = false,\n saveDisabled = false,\n containerStyle,\n saveTestID = 'save-button',\n cancelTestID = 'cancel-button',\n testID,\n}: FormActionsProps): React.ReactElement => (\n <View style={[styles.container, containerStyle]} testID={testID}>\n {typeof onCancel === 'function' ? (\n <Button\n accessibilityHint={cancelHint ?? cancelLabel}\n accessibilityLabel={cancelLabel}\n disabled={saving}\n label={cancelLabel}\n testID={cancelTestID}\n variant=\"outline\"\n onPress={onCancel}\n />\n ) : null}\n\n <Button\n accessibilityHint={saveHint ?? saveLabel}\n accessibilityLabel={saveLabel}\n disabled={saveDisabled}\n label={saveLabel}\n loading={saving}\n testID={saveTestID}\n variant=\"primary\"\n onPress={onSave}\n />\n </View>\n);\n\nexport default FormActions;\n","/**\n * `useThemedInput` — the shared \"readable + lively\" text-input treatment, driven entirely by\n * the active `@dloizides/ui-feedback` theme (so it re-themes per tenant, no hard-coded hex).\n *\n * At rest: dark readable text on a subtle off-white surface with a soft border.\n * On hover (web): the border strengthens a touch.\n * On focus: the border becomes the brand primary, the background brightens to the plain surface\n * (white), and a soft 3px brand-tinted focus ring fades in.\n *\n * Kept FAST: the animation is a pure GPU-cheap CSS transition on `border-color`,\n * `background-color` and `box-shadow` (the focus ring is a `box-shadow`, so it never triggers\n * layout/reflow). There is NO `Animated`, `LayoutAnimation` or JS timer — only React state\n * toggled by focus/blur/hover. Web-only style keys (`transition*`, `boxShadow`, `outlineStyle`)\n * and the mouse-hover handlers are guarded behind `Platform.OS === 'web'`, so the hook stays\n * native-safe (native simply applies the state-driven colours instantly).\n */\nimport { useCallback, useMemo, useState } from 'react';\n\nimport { Platform, type TextInputProps, type TextStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\n/** The exact focus/blur event types of the installed `react-native` `TextInput` (version-safe). */\ntype FocusEvent = Parameters<NonNullable<TextInputProps['onFocus']>>[0];\ntype BlurEvent = Parameters<NonNullable<TextInputProps['onBlur']>>[0];\n\nconst IS_WEB = Platform.OS === 'web';\n\nconst TRANSITION_PROPERTY = 'border-color, background-color, box-shadow';\nconst TRANSITION_DURATION = '0.14s';\nconst TRANSITION_TIMING = 'ease';\nconst FOCUS_RING_WIDTH = 3;\nconst FOCUS_RING_ALPHA = 0.16;\nconst HOVER_BORDER_ALPHA = 0.22;\n\nconst HEX_RADIX = 16;\nconst HEX_SHORT_LENGTH = 4;\nconst HEX_FULL_LENGTH = 7;\nconst RED_START = 1;\nconst GREEN_START = 3;\nconst BLUE_START = 5;\nconst CHANNEL_END_OFFSET = 2;\n\n/**\n * Convert an `#rgb` / `#rrggbb` colour to an `rgba(...)` string at the given alpha. Any other\n * colour form (already `rgba()`, a CSS name, …) is returned unchanged — so the caller degrades\n * gracefully rather than emitting an invalid value.\n */\n/**\n * True when the user asked the OS to reduce motion (web only). Read at render so the\n * focus/hover transition collapses to an instant change for those users (WCAG 2.3.3 / the\n * `prefers-reduced-motion: reduce` contract). Safe under SSR / no `matchMedia`.\n */\nfunction prefersReducedMotion(): boolean {\n if (!IS_WEB || typeof window === 'undefined' || typeof window.matchMedia !== 'function') return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\nfunction withAlpha(color: string, alpha: number): string {\n const hex = color.trim();\n const isHex = hex.charAt(0) === '#' && (hex.length === HEX_FULL_LENGTH || hex.length === HEX_SHORT_LENGTH);\n if (!isHex) return color;\n const full =\n hex.length === HEX_SHORT_LENGTH\n ? `#${hex.charAt(1)}${hex.charAt(1)}${hex.charAt(2)}${hex.charAt(2)}${hex.charAt(3)}${hex.charAt(3)}`\n : hex;\n const r = parseInt(full.slice(RED_START, RED_START + CHANNEL_END_OFFSET), HEX_RADIX);\n const g = parseInt(full.slice(GREEN_START, GREEN_START + CHANNEL_END_OFFSET), HEX_RADIX);\n const b = parseInt(full.slice(BLUE_START, BLUE_START + CHANNEL_END_OFFSET), HEX_RADIX);\n return `rgba(${r}, ${g}, ${b}, ${alpha})`;\n}\n\nexport interface UseThemedInputOptions {\n /** Render with the error border colour (the brand focus border is suppressed while errored). */\n hasError?: boolean;\n /** Consumer focus handler — composed with the internal focus-state toggle. */\n onFocus?: (e: FocusEvent) => void;\n /** Consumer blur handler — composed with the internal focus-state toggle. */\n onBlur?: (e: BlurEvent) => void;\n}\n\nexport interface ThemedInput {\n /** The themed input style for the current focus/hover state (memoised). Merge AFTER your box style. */\n style: TextStyle;\n /** A readable mid-grey placeholder colour from the theme. */\n placeholderTextColor: string;\n isFocused: boolean;\n isHovered: boolean;\n /** Spread/attach onto the `<TextInput>` to drive the focus treatment. */\n focusBind: {\n onFocus: (e: FocusEvent) => void;\n onBlur: (e: BlurEvent) => void;\n };\n /** Web-only mouse-hover handlers, pre-typed for `<TextInput>` (an empty object on native). */\n hoverBind: TextInputProps;\n}\n\nexport function useThemedInput(options: UseThemedInputOptions = {}): ThemedInput {\n const { hasError = false, onFocus, onBlur } = options;\n const { theme } = useUi();\n const { colors, palette, semantic } = theme;\n\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n\n const handleFocus = useCallback(\n (e: FocusEvent) => {\n setIsFocused(true);\n onFocus?.(e);\n },\n [onFocus],\n );\n const handleBlur = useCallback(\n (e: BlurEvent) => {\n setIsFocused(false);\n onBlur?.(e);\n },\n [onBlur],\n );\n const handleHoverIn = useCallback(() => setIsHovered(true), []);\n const handleHoverOut = useCallback(() => setIsHovered(false), []);\n\n const primary = palette.primary['500'];\n const errorColor = semantic.error['500'];\n\n const style = useMemo<TextStyle>(() => {\n const restBorder = hasError ? errorColor : colors.border;\n const focusBorder = hasError ? errorColor : primary;\n const borderColor = isFocused ? focusBorder : isHovered ? withAlpha(colors.text, HOVER_BORDER_ALPHA) : restBorder;\n const backgroundColor = isFocused ? colors.surface : colors.surfaceElevated;\n const base: TextStyle = { color: colors.text, borderColor, backgroundColor };\n if (!IS_WEB) return base;\n // A focused field ALWAYS gets a ring — an errored one just changes its colour to the error\n // tint (v1: `input.invalid:focus { box-shadow: 0 0 0 3px var(--danger-tint) }`). Suppressing\n // the ring while errored, as this did, removed the focus indicator (WCAG 2.4.7) from precisely\n // the field the user was sent back to fix, at the moment they are most likely on a keyboard.\n const ringColor = hasError ? errorColor : primary;\n const ring = isFocused ? `0 0 0 ${FOCUS_RING_WIDTH}px ${withAlpha(ringColor, FOCUS_RING_ALPHA)}` : 'none';\n const webStyle = {\n transitionProperty: TRANSITION_PROPERTY,\n // Collapse the eased transition to instant when the user prefers reduced motion.\n transitionDuration: prefersReducedMotion() ? '0s' : TRANSITION_DURATION,\n transitionTimingFunction: TRANSITION_TIMING,\n boxShadow: ring,\n outlineStyle: 'none',\n };\n return { ...base, ...webStyle } as TextStyle;\n }, [\n isFocused,\n isHovered,\n hasError,\n colors.text,\n colors.border,\n colors.surface,\n colors.surfaceElevated,\n primary,\n errorColor,\n ]);\n\n const focusBind = useMemo(() => ({ onFocus: handleFocus, onBlur: handleBlur }), [handleFocus, handleBlur]);\n\n const hoverBind = useMemo<TextInputProps>(\n () =>\n IS_WEB ? ({ onMouseEnter: handleHoverIn, onMouseLeave: handleHoverOut } as unknown as TextInputProps) : {},\n [handleHoverIn, handleHoverOut],\n );\n\n return {\n style,\n placeholderTextColor: colors.textSecondary,\n isFocused,\n isHovered,\n focusBind,\n hoverBind,\n };\n}\n","/**\n * `ThemedTextInput` — the shared, readable + lively text-input primitive. A thin `<TextInput>`\n * wrapper that applies the `useThemedInput` treatment (dark readable text, subtle off-white rest\n * background, and the brand focus animation: indigo border + white background + soft 3px ring,\n * eased over .14s via a GPU-cheap CSS transition on web; instant, native-safe off web).\n *\n * It is the ONE source of truth for the input look: `FormField` renders it, and raw filter inputs\n * (search / country / year / date fallbacks) use it directly instead of forking the styles.\n *\n * Every existing `TextInputProps` (value, placeholder, onChangeText, testID, accessibility…) is\n * forwarded untouched; `onFocus`/`onBlur` you pass are composed with the internal focus state.\n */\nimport React from 'react';\n\nimport { Platform, TextInput, type TextInputProps } from 'react-native';\n\nimport { useThemedInput } from '../useThemedInput/useThemedInput';\n\nconst IS_WEB = Platform.OS === 'web';\n\n/**\n * Web-only ARIA attributes react-native-web forwards to the underlying `<input>` but that RN's\n * `TextInputProps` type does not enumerate. Cast through the TextInput props at the call site\n * (never `any`) so error/label semantics reach a screen reader without a type escape hatch.\n */\ninterface WebInputA11y {\n 'aria-invalid'?: boolean;\n 'aria-describedby'?: string;\n 'aria-required'?: boolean;\n}\n\nexport interface ThemedTextInputProps extends TextInputProps {\n /** Render with the error border colour (matches `FormField`'s error treatment). */\n hasError?: boolean;\n /**\n * id of an element describing this input (e.g. an error/hint line). Linked via\n * `aria-describedby` on web so a screen reader reads it after the field's name. No-op native.\n */\n describedById?: string;\n /** Marks the field required for assistive tech (`aria-required` on web). No-op on native. */\n requiredField?: boolean;\n}\n\nexport const ThemedTextInput = React.forwardRef<TextInput, ThemedTextInputProps>(function ThemedTextInput(\n { hasError = false, describedById, requiredField = false, onFocus, onBlur, style, placeholderTextColor, ...rest },\n ref,\n): React.ReactElement {\n const {\n style: themedStyle,\n placeholderTextColor: themedPlaceholder,\n focusBind,\n hoverBind,\n } = useThemedInput({ hasError, onFocus, onBlur });\n\n // aria-invalid announces the error state; aria-describedby ties the error/hint text to the\n // field; aria-required marks it mandatory. Web-only (RN-web → DOM); omitted on native.\n const webA11y: WebInputA11y = IS_WEB\n ? {\n 'aria-invalid': hasError ? true : undefined,\n 'aria-describedby': describedById,\n 'aria-required': requiredField ? true : undefined,\n }\n : {};\n\n return (\n <TextInput\n ref={ref}\n placeholderTextColor={placeholderTextColor ?? themedPlaceholder}\n {...rest}\n {...(webA11y as TextInputProps)}\n {...hoverBind}\n onFocus={focusBind.onFocus}\n onBlur={focusBind.onBlur}\n style={[style, themedStyle]}\n />\n );\n});\n","/**\n * Reusable form field — labelled text input with optional required mark + error.\n *\n * The label row, the required mark, the error line and the container spacing all come from the\n * generic `Field` wrapper, so a `FormField` and a `Field`-wrapped dropdown sitting next to each\n * other line up exactly and can never drift apart. FormField only adds the control itself.\n *\n * The input is the shared `ThemedTextInput` primitive, so every FormField gets the readable +\n * lively treatment (dark text, subtle off-white rest background, brand focus animation with a\n * soft ring) for free, driven by the active theme.\n */\nimport React from 'react';\n\nimport { StyleSheet, type TextInputProps, type ViewStyle } from 'react-native';\n\nimport { Field } from '../Field/Field';\nimport { ThemedTextInput } from '../ThemedTextInput/ThemedTextInput';\n\nconst INPUT_PADDING_V = 10;\nconst INPUT_PADDING_H = 12;\nconst INPUT_BORDER_RADIUS = 8;\nconst INPUT_BORDER_WIDTH = 1;\n\nconst styles = StyleSheet.create({\n input: {\n paddingVertical: INPUT_PADDING_V,\n paddingHorizontal: INPUT_PADDING_H,\n borderRadius: INPUT_BORDER_RADIUS,\n borderWidth: INPUT_BORDER_WIDTH,\n },\n});\n\nexport interface FormFieldProps extends Omit<TextInputProps, 'style'> {\n label: string;\n required?: boolean;\n error?: string;\n containerStyle?: ViewStyle;\n}\n\nexport const FormField = ({\n label,\n required = false,\n error,\n containerStyle,\n ...textInputProps\n}: FormFieldProps): React.ReactElement => (\n <Field containerStyle={containerStyle} error={error} label={label} required={required}>\n {({ describedById, hasError }) => (\n <ThemedTextInput\n accessibilityHint={`Enter ${label}`}\n accessibilityLabel={label}\n describedById={describedById}\n hasError={hasError}\n requiredField={required}\n style={styles.input}\n testID=\"form-field-input\"\n {...textInputProps}\n />\n )}\n </Field>\n);\n\nexport default FormField;\n","/**\n * Chip/pill selector for selecting one or multiple options.\n *\n * Two visual variants (both fully theme-driven):\n * - `solid` (default) — the original filled-pill look: selected = solid primary fill with\n * white ink. Unchanged, so existing consumers (erevna / katalogos / kefi) render identically.\n * - `outline` — the AML v1 console look: an outlined pill on a muted fill; selected = a subtle\n * tinted-outline (primary border + primary ink + a low-alpha primary wash), NOT a solid fill.\n * Hover (web) lifts the border/ink to the primary colour.\n *\n * The label row, the error line and the container spacing come from the shared `Field` wrapper —\n * NOT from a local `<Text>`. Its own label used to drift from `Field` on three of four axes\n * (`marginBottom: 8` vs 4, no `fontSize` at all so ~14 vs 13, `colors.text` vs `textSecondary`),\n * so a `ChipSelector` next to a `FormField` in a row/grid started a different distance down the\n * column and read as a different weight of text. Now there is exactly one label implementation.\n */\nimport React from 'react';\n\nimport {\n Platform,\n StyleSheet,\n View,\n Text,\n Pressable,\n TouchableOpacity,\n type ViewProps,\n type ViewStyle,\n} from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { Field } from '../Field/Field';\n\nconst TRANSPARENT_COLOR = 'transparent';\nconst WHITE_COLOR = '#fff';\nconst SOLID_RADIUS = 20;\nconst OUTLINE_RADIUS = 999;\nconst OUTLINE_PAD_H = 12;\nconst OUTLINE_PAD_V = 5;\nconst OUTLINE_FONT_SIZE = 13;\nconst OUTLINE_TINT_ALPHA = 0.1;\nconst HEX_SHORT_LENGTH = 3;\nconst HEX_RADIX = 16;\nconst RGB_R_START = 0;\nconst RGB_R_END = 2;\nconst RGB_G_END = 4;\nconst RGB_B_END = 6;\n/**\n * Chips are visually compact (≈24–26px tall). `hitSlop` expands the pressable's TOUCH area\n * toward the WCAG ≥44px target WITHOUT changing the rendered pill size, so existing layouts are\n * byte-identical while taps/clicks get an easier target.\n */\nconst CHIP_HIT_SLOP = { top: 10, bottom: 10, left: 4, right: 4 } as const;\n/** Gap between adjacent chips, horizontally and between wrapped rows. */\nconst CHIP_GUTTER = 8;\n\n/** Visual variant. `solid` = filled selected pill (default); `outline` = v1 tinted-outline. */\nexport type ChipVariant = 'solid' | 'outline';\n\n/**\n * Default chip testID stem. NOT derived from the `testID` prop, because aml-v2's unit +\n * Playwright specs and erevna/katalogos's `Accessibility.test.tsx` already select on\n * `chip-selector-chip-<value>`. `chipTestIDPrefix` is the opt-in override for consumers\n * (kefi) that need their own stem; the default is frozen.\n */\nconst DEFAULT_CHIP_TESTID_PREFIX = 'chip-selector-chip';\n\n/** Palette scale carrying the ink for content sitting ON the brand colour. */\nconst ON_BRAND_SCALE = 'onBrand';\n/** The one step every theme scale is guaranteed to define. */\nconst MAIN_STEP = '500';\n\n/**\n * Read the on-brand ink out of a theme palette.\n *\n * Deliberately typed as OPTIONAL rather than read through `palette.onBrand`. Two reasons:\n * this package's declared peer floor is `ui-feedback >= 1.1.0`, whose palette type has no\n * index signature at all; and even on current versions the index signature types every\n * scale as present, which is a lie — only `primary` is guaranteed, and most apps in the\n * fleet publish no `onBrand` scale today. Modelling it as absent-able is what makes the\n * `WHITE_COLOR` fallback honest instead of dead code.\n */\nfunction onBrandInk(palette: object): string {\n const scales = palette as Record<string, Record<string, string> | undefined>;\n return scales[ON_BRAND_SCALE]?.[MAIN_STEP] ?? WHITE_COLOR;\n}\n\n/** Composite a hex colour over the background at a given alpha (theme-driven tint). */\nfunction withAlpha(hex: string, alpha: number): string {\n const normalized = hex.replace('#', '');\n const isShort = normalized.length === HEX_SHORT_LENGTH;\n const full = isShort ? normalized.split('').map((c) => c + c).join('') : normalized;\n const r = parseInt(full.slice(RGB_R_START, RGB_R_END), HEX_RADIX);\n const g = parseInt(full.slice(RGB_R_END, RGB_G_END), HEX_RADIX);\n const b = parseInt(full.slice(RGB_G_END, RGB_B_END), HEX_RADIX);\n const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);\n return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;\n}\n\nconst styles = StyleSheet.create({\n chipContainer: {\n flexDirection: 'row',\n flexWrap: 'wrap',\n // Each chip's bottom gutter also hangs off the LAST row, stacking on `Field`'s container\n // margin (8 + 16 = 24) and dropping the block below the `FormField` beside it. Cancelling it\n // is standard gutter compensation: inner rows keep their 8px, the block ends at Field's 16.\n marginBottom: -CHIP_GUTTER,\n },\n chipWrapper: {\n marginRight: CHIP_GUTTER,\n marginBottom: CHIP_GUTTER,\n },\n chip: {\n paddingHorizontal: 12,\n paddingVertical: 6,\n borderRadius: SOLID_RADIUS,\n backgroundColor: TRANSPARENT_COLOR,\n borderWidth: 1,\n },\n chipOutline: {\n paddingHorizontal: OUTLINE_PAD_H,\n paddingVertical: OUTLINE_PAD_V,\n borderRadius: OUTLINE_RADIUS,\n borderWidth: 1,\n },\n chipText: {},\n chipTextOutline: { fontSize: OUTLINE_FONT_SIZE },\n});\n\n/** Resolved, theme-derived colours for the two variants. */\ninterface ChipColors {\n border: string;\n /** Strong ink for the solid variant's rest text (unchanged from the original). */\n textStrong: string;\n /** Muted ink for the outline variant's rest text (v1 ink-soft). */\n textMuted: string;\n primary: string;\n /**\n * Ink on a primary-filled chip. Reads the theme's `onBrand` scale when the app publishes one,\n * falling back to white. It used to be a hardcoded `#fff`, which meant a tenant whose primary\n * is light got white-on-light and failed contrast — the token slot is the fix, and the\n * fallback keeps every app that has no `onBrand` scale rendering exactly as before.\n */\n onPrimary: string;\n muted: string;\n tint: string;\n}\n\nexport interface ChipOption<T> {\n value: T;\n label: string;\n}\n\nexport interface ChipSelectorProps<T> {\n /** Optional — with no label, no label row is rendered (no phantom gap above the chips). */\n label?: string;\n options: Array<ChipOption<T>>;\n value: T | T[];\n onChange: (value: T) => void;\n multiple?: boolean;\n disabled?: boolean;\n /** Visual variant. `solid` (default) = filled selected pill; `outline` = v1 tinted-outline. */\n variant?: ChipVariant;\n containerStyle?: ViewStyle;\n /** Marks the selection mandatory — renders `Field`'s decorative `*` next to the label. */\n required?: boolean;\n /** Validation message under the chips, wired to the chip group via `aria-describedby`. */\n error?: string;\n testID?: string;\n /**\n * Stem for each chip's testID — a chip becomes `${chipTestIDPrefix}-${value}`. Defaults to\n * `chip-selector-chip`, which existing specs select on; supply your own when a screen has\n * several chip groups that must be addressed independently.\n */\n chipTestIDPrefix?: string;\n /**\n * Accessibility hint applied to every chip in the group. Supply a LOCALIZED string — the\n * built-in default (`Selects <label>`) is English-only and exists solely so pre-existing\n * consumers keep their current announcement.\n */\n optionAccessibilityHint?: string;\n}\n\n/**\n * Web-only ARIA attributes react-native-web forwards to the underlying element but that RN's\n * `ViewProps` type does not enumerate — same escape-hatch-free pattern `ThemedTextInput` uses.\n */\ninterface WebGroupA11y {\n 'aria-invalid'?: boolean;\n 'aria-describedby'?: string;\n}\n\ninterface ChipProps<T> {\n option: ChipOption<T>;\n selected: boolean;\n disabled: boolean;\n colors: ChipColors;\n /** Resolved `${prefix}-${value}` for this chip. */\n testID: string;\n /** Resolved hint for this chip — localized by the consumer, or the built-in English default. */\n accessibilityHint: string;\n /**\n * Web-only toggle state for a MULTI-select chip; `undefined` for single-select.\n *\n * Why `aria-pressed` on a button and not `role=\"checkbox\"`: react-native-web renders\n * `accessibilityRole=\"button\"` as a real `<button>`, but ANY other role as a plain `<div>`.\n * Switching a multi chip to `checkbox` therefore trades native keyboard activation for a\n * div that only looks right — the same RN-web trap that produced the held-Enter defect\n * elsewhere in this fleet. A toggle button (`role=button` + `aria-pressed`) conveys the\n * on/off state to assistive tech AND keeps Space/Enter working for free.\n *\n * It is passed as a literal web prop because RNW 0.21 emits NOTHING from\n * `accessibilityState` on web — verified, not assumed — so the `accessibilityState` below\n * is carrying native only.\n */\n ariaPressed?: boolean;\n}\n\n/**\n * The a11y + testID triple a chip needs, resolved once for both variants.\n *\n * Exported for direct unit testing. It has to be tested as a pure function rather than\n * through the DOM because react-native-web DROPS `accessibilityHint` entirely — it reaches\n * native, but no web attribute carries it, so no rendering assertion can tell a correctly\n * threaded hint from one that was never passed. Testing the resolver is the only honest way\n * to pin the behaviour.\n */\nexport function chipIdentity<T>(\n option: ChipOption<T>,\n selected: boolean,\n config: { prefix: string; hint?: string; multiple: boolean },\n): Pick<ChipProps<T>, 'testID' | 'accessibilityHint' | 'ariaPressed'> {\n return {\n testID: `${config.prefix}-${String(option.value)}`,\n // The English default is retained verbatim: erevna/katalogos assert the exact string\n // `Selects Red`. Consumers that localize pass `optionAccessibilityHint`.\n accessibilityHint: config.hint ?? `Selects ${option.label}`,\n ariaPressed: config.multiple ? selected : undefined,\n };\n}\n\n/** A single outline chip — owns its own hover state (web) for the border/ink lift. */\nfunction OutlineChip<T extends string | number>({\n option,\n selected,\n disabled,\n colors,\n testID,\n accessibilityHint,\n ariaPressed,\n onPress,\n}: ChipProps<T> & { onPress: () => void }): React.ReactElement {\n const [hovered, setHovered] = React.useState(false);\n const active = selected || hovered;\n\n const borderColor = active ? colors.primary : colors.border;\n const backgroundColor = selected ? colors.tint : colors.muted;\n // Selected AND hovered both lift the ink to the primary colour (v1's indigo / indigo-dark);\n // the theme surface only guarantees the 500 step, so both use it — border + fill carry the state.\n const textColor = active ? colors.primary : colors.textMuted;\n\n return (\n <Pressable\n accessibilityHint={accessibilityHint}\n accessibilityLabel={option.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected, disabled }}\n aria-pressed={ariaPressed}\n disabled={disabled}\n hitSlop={CHIP_HIT_SLOP}\n style={styles.chipWrapper}\n testID={testID}\n onHoverIn={() => setHovered(true)}\n onHoverOut={() => setHovered(false)}\n onPress={onPress}\n >\n <View style={[styles.chipOutline, { borderColor, backgroundColor }]}>\n <Text style={[styles.chipText, styles.chipTextOutline, { color: textColor }]}>{option.label}</Text>\n </View>\n </Pressable>\n );\n}\n\n/** A single solid chip — the original filled-pill look (unchanged for existing consumers). */\nfunction SolidChip<T extends string | number>({\n option,\n selected,\n disabled,\n colors,\n testID,\n accessibilityHint,\n ariaPressed,\n onPress,\n}: ChipProps<T> & { onPress: () => void }): React.ReactElement {\n const backgroundColor = selected ? colors.primary : TRANSPARENT_COLOR;\n const textColor = selected ? colors.onPrimary : colors.textStrong;\n return (\n <TouchableOpacity\n accessibilityHint={accessibilityHint}\n accessibilityLabel={option.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected, disabled }}\n aria-pressed={ariaPressed}\n disabled={disabled}\n hitSlop={CHIP_HIT_SLOP}\n style={styles.chipWrapper}\n testID={testID}\n onPress={onPress}\n >\n <View style={[styles.chip, { borderColor: colors.border, backgroundColor }]}>\n <Text style={[styles.chipText, { color: textColor }]}>{option.label}</Text>\n </View>\n </TouchableOpacity>\n );\n}\n\nconst IS_WEB = Platform.OS === 'web';\n\n/** Ties the chip group to `Field`'s error line for assistive tech (web only; no-op on native). */\nfunction groupA11yProps(describedById: string | undefined, hasError: boolean): WebGroupA11y {\n if (!IS_WEB) return {};\n return { 'aria-invalid': hasError ? true : undefined, 'aria-describedby': describedById };\n}\n\nexport const ChipSelector = <T extends string | number>({\n label,\n options,\n value,\n onChange,\n multiple = false,\n disabled = false,\n variant = 'solid',\n containerStyle,\n required = false,\n error,\n testID,\n chipTestIDPrefix = DEFAULT_CHIP_TESTID_PREFIX,\n optionAccessibilityHint,\n}: ChipSelectorProps<T>): React.ReactElement => {\n const { theme } = useUi();\n const { colors, palette } = theme;\n\n const chipColors = React.useMemo<ChipColors>(() => {\n const primary = palette.primary['500'];\n return {\n border: colors.border,\n textStrong: colors.text,\n textMuted: colors.textSecondary,\n primary,\n onPrimary: onBrandInk(palette),\n muted: colors.background,\n tint: withAlpha(primary, OUTLINE_TINT_ALPHA),\n };\n }, [colors.border, colors.text, colors.textSecondary, colors.background, palette]);\n\n function isSelected(optionValue: T): boolean {\n if (multiple && Array.isArray(value))\n return value.includes(optionValue);\n\n return value === optionValue;\n }\n\n function renderChip(option: ChipOption<T>): React.ReactElement {\n const selected = isSelected(option.value);\n const chipProps = {\n colors: chipColors,\n disabled,\n option,\n selected,\n ...chipIdentity(option, selected, {\n prefix: chipTestIDPrefix,\n hint: optionAccessibilityHint,\n multiple,\n }),\n onPress: (): void => onChange(option.value),\n };\n const key = String(option.value);\n return variant === 'outline' ? <OutlineChip key={key} {...chipProps} /> : <SolidChip key={key} {...chipProps} />;\n }\n\n return (\n <Field containerStyle={containerStyle} error={error} label={label} required={required} testID={testID}>\n {({ describedById, hasError }) => (\n <View style={styles.chipContainer} {...(groupA11yProps(describedById, hasError) as ViewProps)}>\n {options.map(renderChip)}\n </View>\n )}\n </Field>\n );\n};\n\nexport default ChipSelector;\n","/**\n * Reusable form switch/toggle with an optional description.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, Switch, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nconst DESCRIPTION_FONT_SIZE = 12;\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n justifyContent: 'space-between',\n alignItems: 'center',\n marginBottom: 12,\n },\n textColumn: {\n flex: 1,\n },\n label: {\n fontWeight: '600',\n },\n description: {\n fontSize: DESCRIPTION_FONT_SIZE,\n marginTop: 2,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n description: TextStyle;\n}\n\nexport interface FormSwitchProps {\n label: string;\n value: boolean;\n onValueChange: (value: boolean) => void;\n disabled?: boolean;\n description?: string;\n containerStyle?: ViewStyle;\n testID?: string;\n accessibilityHint?: string;\n}\n\nexport const FormSwitch = ({\n label,\n value,\n onValueChange,\n disabled = false,\n description,\n containerStyle,\n testID = 'form-switch',\n accessibilityHint,\n}: FormSwitchProps): React.ReactElement => {\n const { theme } = useUi();\n const { colors } = theme;\n const hasDescription = typeof description === 'string' && description !== '';\n\n const themeStyles = React.useMemo<ThemeStyles>(() => {\n const labelStyle: TextStyle = { color: colors.text };\n const descriptionStyle: TextStyle = { color: colors.textSecondary };\n return { label: labelStyle, description: descriptionStyle };\n }, [colors.text, colors.textSecondary]);\n\n return (\n <View\n style={[\n styles.container,\n containerStyle,\n ]}\n >\n <View style={styles.textColumn}>\n <Text style={[styles.label, themeStyles.label]}>{label}</Text>\n {hasDescription ? (\n <Text style={[styles.description, themeStyles.description]}>{description}</Text>\n ) : null}\n </View>\n <Switch\n accessibilityHint={accessibilityHint ?? label}\n accessibilityLabel={label}\n accessibilityRole=\"switch\"\n accessibilityState={{ checked: value }}\n disabled={disabled}\n testID={testID}\n value={value}\n onValueChange={onValueChange}\n />\n </View>\n );\n};\n\nexport default FormSwitch;\n","/**\n * Reusable, native-safe checkbox — a themed `Pressable` (works on RN-web AND native, where RN has\n * no built-in checkbox). A small rounded square that fills with the brand colour and shows a check\n * glyph when on, with a label and an optional hint. Mirrors `FormSwitch`'s prop shape so it is a\n * drop-in replacement for the boolean toggles v1 renders as checkboxes.\n */\nimport React from 'react';\n\nimport { Platform, StyleSheet, View, Text, Pressable, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\n/**\n * Web-only keydown prop react-native-web's `Pressable` forwards but RN's types omit. A\n * `role=\"checkbox\"` Pressable renders a `<div>` (not a native `<button>`), so — unlike a\n * button-role Pressable — it gets NO free Enter/Space activation. We add it explicitly so the\n * checkbox is keyboard-operable (WCAG 2.1.1). `preventDefault()` stops Space from scrolling.\n */\ninterface WebKeyboardProps {\n onKeyDown?: (event: { key?: string; preventDefault?: () => void }) => void;\n}\n\nconst ACTIVATION_KEYS = ['Enter', ' ', 'Spacebar'];\n\nconst HINT_FONT_SIZE = 12;\nconst BOX_SIZE = 20;\nconst BOX_RADIUS = 5;\nconst CHECK_FONT_SIZE = 14;\nconst DISABLED_OPACITY = 0.5;\n\nconst styles = StyleSheet.create({\n container: {\n flexDirection: 'row',\n alignItems: 'flex-start',\n gap: 10,\n marginBottom: 12,\n },\n box: {\n width: BOX_SIZE,\n height: BOX_SIZE,\n borderRadius: BOX_RADIUS,\n borderWidth: 2,\n alignItems: 'center',\n justifyContent: 'center',\n // Nudge the box to sit on the label's first text line.\n marginTop: 1,\n },\n check: {\n fontSize: CHECK_FONT_SIZE,\n fontWeight: '700',\n lineHeight: CHECK_FONT_SIZE,\n },\n textColumn: {\n flex: 1,\n },\n label: {\n fontWeight: '600',\n },\n hint: {\n fontSize: HINT_FONT_SIZE,\n marginTop: 2,\n },\n});\n\nexport interface FormCheckboxProps {\n label: string;\n value: boolean;\n /** Primary change handler (mirrors `FormSwitch`). `onChange` is accepted as an alias. */\n onValueChange?: (value: boolean) => void;\n /** Alias for `onValueChange` so either name works as a drop-in. */\n onChange?: (value: boolean) => void;\n /** Optional secondary description shown under the label. `description` is accepted as an alias. */\n hint?: string;\n description?: string;\n disabled?: boolean;\n containerStyle?: ViewStyle;\n testID?: string;\n accessibilityLabel?: string;\n accessibilityHint?: string;\n}\n\nexport const FormCheckbox = ({\n label,\n value,\n onValueChange,\n onChange,\n hint,\n description,\n disabled = false,\n containerStyle,\n testID = 'form-checkbox',\n accessibilityLabel,\n accessibilityHint,\n}: FormCheckboxProps): React.ReactElement => {\n const { theme } = useUi();\n const { colors, palette } = theme;\n const brand = palette.primary['500'];\n const hintText = typeof hint === 'string' && hint !== '' ? hint : description;\n const hasHint = typeof hintText === 'string' && hintText !== '';\n\n const themeStyles = React.useMemo(() => {\n const boxOn: ViewStyle = { backgroundColor: brand, borderColor: brand };\n const boxOff: ViewStyle = { backgroundColor: 'transparent', borderColor: colors.border };\n const labelStyle: TextStyle = { color: colors.text };\n const hintStyle: TextStyle = { color: colors.textSecondary };\n return { boxOn, boxOff, label: labelStyle, hint: hintStyle };\n }, [brand, colors.border, colors.text, colors.textSecondary]);\n\n const toggle = (): void => {\n const next = !value;\n if (onValueChange) onValueChange(next);\n if (onChange) onChange(next);\n };\n\n const handleKeyDown = (event: { key?: string; preventDefault?: () => void }): void => {\n if (disabled) return;\n const key = event.key ?? '';\n if (!ACTIVATION_KEYS.includes(key)) return;\n if (typeof event.preventDefault === 'function') event.preventDefault();\n toggle();\n };\n\n const keyboardProps: WebKeyboardProps = Platform.OS === 'web' ? { onKeyDown: handleKeyDown } : {};\n\n return (\n <Pressable\n accessibilityHint={accessibilityHint ?? label}\n accessibilityLabel={accessibilityLabel ?? label}\n accessibilityRole=\"checkbox\"\n accessibilityState={{ checked: value, disabled }}\n // RN-web maps this to the ARIA `role=\"checkbox\"` + `aria-checked` a screen reader announces.\n aria-checked={value}\n disabled={disabled}\n onPress={toggle}\n role=\"checkbox\"\n style={[styles.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null]}\n testID={testID}\n {...keyboardProps}\n >\n <View style={[styles.box, value ? themeStyles.boxOn : themeStyles.boxOff]}>\n {value ? (\n <Text style={[styles.check, { color: colors.surface }]} accessibilityElementsHidden>\n ✓\n </Text>\n ) : null}\n </View>\n <View style={styles.textColumn}>\n <Text style={[styles.label, themeStyles.label]}>{label}</Text>\n {hasHint ? <Text style={[styles.hint, themeStyles.hint]}>{hintText}</Text> : null}\n </View>\n </Pressable>\n );\n};\n\nexport default FormCheckbox;\n"]}
|
package/package.json
CHANGED
|
@@ -1,108 +1,110 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@dloizides/ui-forms",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "Themable, brand-agnostic React Native (RN-web) form components — FormField, ChipSelector, FormSwitch — sharing the @dloizides/ui-feedback UI context. Part of the dloizides.com shared UI kit.",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"react",
|
|
7
|
-
"react-native",
|
|
8
|
-
"react-native-web",
|
|
9
|
-
"ui",
|
|
10
|
-
"forms",
|
|
11
|
-
"form-field",
|
|
12
|
-
"dloizides"
|
|
13
|
-
],
|
|
14
|
-
"author": "dloizides",
|
|
15
|
-
"license": "MIT",
|
|
16
|
-
"repository": {
|
|
17
|
-
"type": "git",
|
|
18
|
-
"url": "https://github.com/openmindednewby/ui-forms.git"
|
|
19
|
-
},
|
|
20
|
-
"homepage": "https://github.com/openmindednewby/ui-forms#readme",
|
|
21
|
-
"bugs": {
|
|
22
|
-
"url": "https://github.com/openmindednewby/ui-forms/issues"
|
|
23
|
-
},
|
|
24
|
-
"main": "./dist/index.js",
|
|
25
|
-
"module": "./dist/index.mjs",
|
|
26
|
-
"types": "./dist/index.d.ts",
|
|
27
|
-
"exports": {
|
|
28
|
-
".": {
|
|
29
|
-
"react-native": {
|
|
30
|
-
"types": "./dist/index.d.ts",
|
|
31
|
-
"default": "./dist/index.js"
|
|
32
|
-
},
|
|
33
|
-
"browser": {
|
|
34
|
-
"types": "./dist/index.d.ts",
|
|
35
|
-
"default": "./dist/index.js"
|
|
36
|
-
},
|
|
37
|
-
"require": {
|
|
38
|
-
"types": "./dist/index.d.ts",
|
|
39
|
-
"default": "./dist/index.js"
|
|
40
|
-
},
|
|
41
|
-
"import": {
|
|
42
|
-
"types": "./dist/index.d.mts",
|
|
43
|
-
"default": "./dist/index.mjs"
|
|
44
|
-
},
|
|
45
|
-
"default": {
|
|
46
|
-
"types": "./dist/index.d.ts",
|
|
47
|
-
"default": "./dist/index.js"
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
},
|
|
51
|
-
"files": [
|
|
52
|
-
"dist",
|
|
53
|
-
"README.md",
|
|
54
|
-
"CHANGELOG.md"
|
|
55
|
-
],
|
|
56
|
-
"sideEffects": false,
|
|
57
|
-
"engines": {
|
|
58
|
-
"node": ">=18.0.0"
|
|
59
|
-
},
|
|
60
|
-
"scripts": {
|
|
61
|
-
"build": "rimraf dist && tsup",
|
|
62
|
-
"build:watch": "tsup --watch",
|
|
63
|
-
"test": "jest",
|
|
64
|
-
"test:watch": "jest --watch",
|
|
65
|
-
"test:coverage": "jest --coverage",
|
|
66
|
-
"lint": "eslint src --ext .ts,.tsx",
|
|
67
|
-
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
68
|
-
"typecheck": "tsc --noEmit",
|
|
69
|
-
"clean": "rimraf dist",
|
|
70
|
-
"security:audit": "npm audit --audit-level=high",
|
|
71
|
-
"deps:outdated": "npm outdated || exit 0",
|
|
72
|
-
"deps:unused": "npx depcheck --ignores \"@types/jest,@types/node,@types/react,@types/react-dom,rimraf,react-native,react-native-web\"",
|
|
73
|
-
"deps:licenses": "npx license-checker --onlyAllow \"MIT;Apache-2.0;ISC;BSD-2-Clause;BSD-3-Clause;0BSD;Unlicense;CC0-1.0\"",
|
|
74
|
-
"deps:health": "npm run deps:outdated && npm run deps:unused",
|
|
75
|
-
"prepublishOnly": "npm run clean && npm run build && npm run test",
|
|
76
|
-
"version": "npm run build"
|
|
77
|
-
},
|
|
78
|
-
"peerDependencies": {
|
|
79
|
-
"@dloizides/ui-
|
|
80
|
-
"
|
|
81
|
-
"react
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
"@
|
|
86
|
-
"@testing-library/
|
|
87
|
-
"@testing-library/
|
|
88
|
-
"@
|
|
89
|
-
"@types/
|
|
90
|
-
"@types/
|
|
91
|
-
"@types/react
|
|
92
|
-
"@
|
|
93
|
-
"@typescript-eslint/
|
|
94
|
-
"eslint": "^
|
|
95
|
-
"eslint
|
|
96
|
-
"eslint-plugin-react
|
|
97
|
-
"
|
|
98
|
-
"jest
|
|
99
|
-
"
|
|
100
|
-
"react
|
|
101
|
-
"react-
|
|
102
|
-
"react-native
|
|
103
|
-
"
|
|
104
|
-
"
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
|
|
108
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@dloizides/ui-forms",
|
|
3
|
+
"version": "1.7.0",
|
|
4
|
+
"description": "Themable, brand-agnostic React Native (RN-web) form components — FormField, ChipSelector, FormSwitch — sharing the @dloizides/ui-feedback UI context. Part of the dloizides.com shared UI kit.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"react",
|
|
7
|
+
"react-native",
|
|
8
|
+
"react-native-web",
|
|
9
|
+
"ui",
|
|
10
|
+
"forms",
|
|
11
|
+
"form-field",
|
|
12
|
+
"dloizides"
|
|
13
|
+
],
|
|
14
|
+
"author": "dloizides",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "https://github.com/openmindednewby/ui-forms.git"
|
|
19
|
+
},
|
|
20
|
+
"homepage": "https://github.com/openmindednewby/ui-forms#readme",
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/openmindednewby/ui-forms/issues"
|
|
23
|
+
},
|
|
24
|
+
"main": "./dist/index.js",
|
|
25
|
+
"module": "./dist/index.mjs",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"react-native": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"default": "./dist/index.js"
|
|
32
|
+
},
|
|
33
|
+
"browser": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"default": "./dist/index.js"
|
|
36
|
+
},
|
|
37
|
+
"require": {
|
|
38
|
+
"types": "./dist/index.d.ts",
|
|
39
|
+
"default": "./dist/index.js"
|
|
40
|
+
},
|
|
41
|
+
"import": {
|
|
42
|
+
"types": "./dist/index.d.mts",
|
|
43
|
+
"default": "./dist/index.mjs"
|
|
44
|
+
},
|
|
45
|
+
"default": {
|
|
46
|
+
"types": "./dist/index.d.ts",
|
|
47
|
+
"default": "./dist/index.js"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"files": [
|
|
52
|
+
"dist",
|
|
53
|
+
"README.md",
|
|
54
|
+
"CHANGELOG.md"
|
|
55
|
+
],
|
|
56
|
+
"sideEffects": false,
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=18.0.0"
|
|
59
|
+
},
|
|
60
|
+
"scripts": {
|
|
61
|
+
"build": "rimraf dist && tsup",
|
|
62
|
+
"build:watch": "tsup --watch",
|
|
63
|
+
"test": "jest",
|
|
64
|
+
"test:watch": "jest --watch",
|
|
65
|
+
"test:coverage": "jest --coverage",
|
|
66
|
+
"lint": "eslint src --ext .ts,.tsx",
|
|
67
|
+
"lint:fix": "eslint src --ext .ts,.tsx --fix",
|
|
68
|
+
"typecheck": "tsc --noEmit",
|
|
69
|
+
"clean": "rimraf dist",
|
|
70
|
+
"security:audit": "npm audit --audit-level=high",
|
|
71
|
+
"deps:outdated": "npm outdated || exit 0",
|
|
72
|
+
"deps:unused": "npx depcheck --ignores \"@types/jest,@types/node,@types/react,@types/react-dom,rimraf,react-native,react-native-web\"",
|
|
73
|
+
"deps:licenses": "npx license-checker --onlyAllow \"MIT;Apache-2.0;ISC;BSD-2-Clause;BSD-3-Clause;0BSD;Unlicense;CC0-1.0\"",
|
|
74
|
+
"deps:health": "npm run deps:outdated && npm run deps:unused",
|
|
75
|
+
"prepublishOnly": "npm run clean && npm run build && npm run test",
|
|
76
|
+
"version": "npm run build"
|
|
77
|
+
},
|
|
78
|
+
"peerDependencies": {
|
|
79
|
+
"@dloizides/ui-buttons": ">=1.4.0",
|
|
80
|
+
"@dloizides/ui-feedback": ">=1.1.0",
|
|
81
|
+
"react": ">=18.0.0",
|
|
82
|
+
"react-native": ">=0.74.0"
|
|
83
|
+
},
|
|
84
|
+
"devDependencies": {
|
|
85
|
+
"@dloizides/ui-feedback": "^1.1.0",
|
|
86
|
+
"@testing-library/dom": "^10.4.0",
|
|
87
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
88
|
+
"@testing-library/react": "^16.1.0",
|
|
89
|
+
"@types/jest": "^29.5.0",
|
|
90
|
+
"@types/node": "^20.19.32",
|
|
91
|
+
"@types/react": "^19.0.0",
|
|
92
|
+
"@types/react-dom": "^19.0.0",
|
|
93
|
+
"@typescript-eslint/eslint-plugin": "^7.0.0",
|
|
94
|
+
"@typescript-eslint/parser": "^7.0.0",
|
|
95
|
+
"eslint": "^8.57.0",
|
|
96
|
+
"eslint-plugin-react": "^7.34.0",
|
|
97
|
+
"eslint-plugin-react-hooks": "^4.6.0",
|
|
98
|
+
"jest": "^29.7.0",
|
|
99
|
+
"jest-environment-jsdom": "^29.7.0",
|
|
100
|
+
"react": "^19.2.4",
|
|
101
|
+
"react-dom": "^19.2.4",
|
|
102
|
+
"react-native": "0.81.5",
|
|
103
|
+
"react-native-web": "^0.21.0",
|
|
104
|
+
"rimraf": "^5.0.0",
|
|
105
|
+
"ts-jest": "^29.1.0",
|
|
106
|
+
"tsup": "^8.0.0",
|
|
107
|
+
"typescript": "^5.4.0",
|
|
108
|
+
"@dloizides/ui-buttons": "^1.4.0"
|
|
109
|
+
}
|
|
110
|
+
}
|