@dloizides/ui-forms 1.2.0 → 1.3.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 +10 -0
- package/dist/index.d.mts +13 -2
- package/dist/index.d.ts +13 -2
- package/dist/index.js +128 -51
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +119 -42
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.3.0
|
|
4
|
+
|
|
5
|
+
- `ChipSelector` gains a `variant` prop (`'solid' | 'outline'`, default `'solid'`). `solid` is the
|
|
6
|
+
original filled-pill look (selected = solid brand fill, white ink) — existing consumers
|
|
7
|
+
(erevna / katalogos / kefi) render **identically**, no change. `outline` is the AML v1 console
|
|
8
|
+
look: an outlined pill on a muted fill where the **selected** state is a subtle tinted-outline
|
|
9
|
+
(brand border + brand ink + a low-alpha brand wash), NOT a solid fill; on web, hover lifts the
|
|
10
|
+
border + ink to the brand colour. Fully theme-driven (brand colour + alpha, border/text from the
|
|
11
|
+
theme), so it re-themes per tenant. Additive + backward-compatible.
|
|
12
|
+
|
|
3
13
|
## 1.2.0
|
|
4
14
|
|
|
5
15
|
- Add `ThemedTextInput` + `useThemedInput` — the shared "readable + lively" text-input treatment,
|
package/dist/index.d.mts
CHANGED
|
@@ -66,8 +66,17 @@ declare function useThemedInput(options?: UseThemedInputOptions): ThemedInput;
|
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Chip/pill selector for selecting one or multiple options.
|
|
69
|
+
*
|
|
70
|
+
* Two visual variants (both fully theme-driven):
|
|
71
|
+
* - `solid` (default) — the original filled-pill look: selected = solid primary fill with
|
|
72
|
+
* white ink. Unchanged, so existing consumers (erevna / katalogos / kefi) render identically.
|
|
73
|
+
* - `outline` — the AML v1 console look: an outlined pill on a muted fill; selected = a subtle
|
|
74
|
+
* tinted-outline (primary border + primary ink + a low-alpha primary wash), NOT a solid fill.
|
|
75
|
+
* Hover (web) lifts the border/ink to the primary colour.
|
|
69
76
|
*/
|
|
70
77
|
|
|
78
|
+
/** Visual variant. `solid` = filled selected pill (default); `outline` = v1 tinted-outline. */
|
|
79
|
+
type ChipVariant = 'solid' | 'outline';
|
|
71
80
|
interface ChipOption<T> {
|
|
72
81
|
value: T;
|
|
73
82
|
label: string;
|
|
@@ -79,9 +88,11 @@ interface ChipSelectorProps<T> {
|
|
|
79
88
|
onChange: (value: T) => void;
|
|
80
89
|
multiple?: boolean;
|
|
81
90
|
disabled?: boolean;
|
|
91
|
+
/** Visual variant. `solid` (default) = filled selected pill; `outline` = v1 tinted-outline. */
|
|
92
|
+
variant?: ChipVariant;
|
|
82
93
|
containerStyle?: ViewStyle;
|
|
83
94
|
}
|
|
84
|
-
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, containerStyle, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
95
|
+
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, variant, containerStyle, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
85
96
|
|
|
86
97
|
/**
|
|
87
98
|
* Reusable form switch/toggle with an optional description.
|
|
@@ -124,4 +135,4 @@ interface FormCheckboxProps {
|
|
|
124
135
|
}
|
|
125
136
|
declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, description, disabled, containerStyle, testID, accessibilityLabel, accessibilityHint, }: FormCheckboxProps) => React.ReactElement;
|
|
126
137
|
|
|
127
|
-
export { type ChipOption, ChipSelector, type ChipSelectorProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormSwitch, type FormSwitchProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, type UseThemedInputOptions, useThemedInput };
|
|
138
|
+
export { type ChipOption, ChipSelector, type ChipSelectorProps, type ChipVariant, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormSwitch, type FormSwitchProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, type UseThemedInputOptions, useThemedInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -66,8 +66,17 @@ declare function useThemedInput(options?: UseThemedInputOptions): ThemedInput;
|
|
|
66
66
|
|
|
67
67
|
/**
|
|
68
68
|
* Chip/pill selector for selecting one or multiple options.
|
|
69
|
+
*
|
|
70
|
+
* Two visual variants (both fully theme-driven):
|
|
71
|
+
* - `solid` (default) — the original filled-pill look: selected = solid primary fill with
|
|
72
|
+
* white ink. Unchanged, so existing consumers (erevna / katalogos / kefi) render identically.
|
|
73
|
+
* - `outline` — the AML v1 console look: an outlined pill on a muted fill; selected = a subtle
|
|
74
|
+
* tinted-outline (primary border + primary ink + a low-alpha primary wash), NOT a solid fill.
|
|
75
|
+
* Hover (web) lifts the border/ink to the primary colour.
|
|
69
76
|
*/
|
|
70
77
|
|
|
78
|
+
/** Visual variant. `solid` = filled selected pill (default); `outline` = v1 tinted-outline. */
|
|
79
|
+
type ChipVariant = 'solid' | 'outline';
|
|
71
80
|
interface ChipOption<T> {
|
|
72
81
|
value: T;
|
|
73
82
|
label: string;
|
|
@@ -79,9 +88,11 @@ interface ChipSelectorProps<T> {
|
|
|
79
88
|
onChange: (value: T) => void;
|
|
80
89
|
multiple?: boolean;
|
|
81
90
|
disabled?: boolean;
|
|
91
|
+
/** Visual variant. `solid` (default) = filled selected pill; `outline` = v1 tinted-outline. */
|
|
92
|
+
variant?: ChipVariant;
|
|
82
93
|
containerStyle?: ViewStyle;
|
|
83
94
|
}
|
|
84
|
-
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, containerStyle, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
95
|
+
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, variant, containerStyle, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
85
96
|
|
|
86
97
|
/**
|
|
87
98
|
* Reusable form switch/toggle with an optional description.
|
|
@@ -124,4 +135,4 @@ interface FormCheckboxProps {
|
|
|
124
135
|
}
|
|
125
136
|
declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, description, disabled, containerStyle, testID, accessibilityLabel, accessibilityHint, }: FormCheckboxProps) => React.ReactElement;
|
|
126
137
|
|
|
127
|
-
export { type ChipOption, ChipSelector, type ChipSelectorProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormSwitch, type FormSwitchProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, type UseThemedInputOptions, useThemedInput };
|
|
138
|
+
export { type ChipOption, ChipSelector, type ChipSelectorProps, type ChipVariant, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormSwitch, type FormSwitchProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, type UseThemedInputOptions, useThemedInput };
|
package/dist/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React3 = require('react');
|
|
4
4
|
var reactNative = require('react-native');
|
|
5
5
|
var uiFeedback = require('@dloizides/ui-feedback');
|
|
6
6
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
7
|
|
|
8
8
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
9
|
|
|
10
|
-
var
|
|
10
|
+
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
11
11
|
|
|
12
12
|
// src/FormField/FormField.tsx
|
|
13
13
|
var IS_WEB = reactNative.Platform.OS === "web";
|
|
@@ -38,27 +38,27 @@ function useThemedInput(options = {}) {
|
|
|
38
38
|
const { hasError = false, onFocus, onBlur } = options;
|
|
39
39
|
const { theme } = uiFeedback.useUi();
|
|
40
40
|
const { colors, palette, semantic } = theme;
|
|
41
|
-
const [isFocused, setIsFocused] =
|
|
42
|
-
const [isHovered, setIsHovered] =
|
|
43
|
-
const handleFocus =
|
|
41
|
+
const [isFocused, setIsFocused] = React3.useState(false);
|
|
42
|
+
const [isHovered, setIsHovered] = React3.useState(false);
|
|
43
|
+
const handleFocus = React3.useCallback(
|
|
44
44
|
(e) => {
|
|
45
45
|
setIsFocused(true);
|
|
46
46
|
onFocus?.(e);
|
|
47
47
|
},
|
|
48
48
|
[onFocus]
|
|
49
49
|
);
|
|
50
|
-
const handleBlur =
|
|
50
|
+
const handleBlur = React3.useCallback(
|
|
51
51
|
(e) => {
|
|
52
52
|
setIsFocused(false);
|
|
53
53
|
onBlur?.(e);
|
|
54
54
|
},
|
|
55
55
|
[onBlur]
|
|
56
56
|
);
|
|
57
|
-
const handleHoverIn =
|
|
58
|
-
const handleHoverOut =
|
|
57
|
+
const handleHoverIn = React3.useCallback(() => setIsHovered(true), []);
|
|
58
|
+
const handleHoverOut = React3.useCallback(() => setIsHovered(false), []);
|
|
59
59
|
const primary = palette.primary["500"];
|
|
60
60
|
const errorColor = semantic.error["500"];
|
|
61
|
-
const style =
|
|
61
|
+
const style = React3.useMemo(() => {
|
|
62
62
|
const restBorder = hasError ? errorColor : colors.border;
|
|
63
63
|
const focusBorder = hasError ? errorColor : primary;
|
|
64
64
|
const borderColor = isFocused ? focusBorder : isHovered ? withAlpha(colors.text, HOVER_BORDER_ALPHA) : restBorder;
|
|
@@ -85,8 +85,8 @@ function useThemedInput(options = {}) {
|
|
|
85
85
|
primary,
|
|
86
86
|
errorColor
|
|
87
87
|
]);
|
|
88
|
-
const focusBind =
|
|
89
|
-
const hoverBind =
|
|
88
|
+
const focusBind = React3.useMemo(() => ({ onFocus: handleFocus, onBlur: handleBlur }), [handleFocus, handleBlur]);
|
|
89
|
+
const hoverBind = React3.useMemo(
|
|
90
90
|
() => IS_WEB ? { onMouseEnter: handleHoverIn, onMouseLeave: handleHoverOut } : {},
|
|
91
91
|
[handleHoverIn, handleHoverOut]
|
|
92
92
|
);
|
|
@@ -99,7 +99,7 @@ function useThemedInput(options = {}) {
|
|
|
99
99
|
hoverBind
|
|
100
100
|
};
|
|
101
101
|
}
|
|
102
|
-
var ThemedTextInput =
|
|
102
|
+
var ThemedTextInput = React3__default.default.forwardRef(function ThemedTextInput2({ hasError = false, onFocus, onBlur, style, placeholderTextColor, ...rest }, ref) {
|
|
103
103
|
const {
|
|
104
104
|
style: themedStyle,
|
|
105
105
|
placeholderTextColor: themedPlaceholder,
|
|
@@ -156,7 +156,7 @@ var FormField = ({
|
|
|
156
156
|
const { colors, semantic } = theme;
|
|
157
157
|
const errorColor = semantic.error["500"];
|
|
158
158
|
const hasError = typeof error === "string" && error !== "";
|
|
159
|
-
const themeStyles =
|
|
159
|
+
const themeStyles = React3__default.default.useMemo(
|
|
160
160
|
() => ({
|
|
161
161
|
label: { color: colors.textSecondary },
|
|
162
162
|
requiredMark: { color: errorColor },
|
|
@@ -186,6 +186,28 @@ var FormField = ({
|
|
|
186
186
|
};
|
|
187
187
|
var TRANSPARENT_COLOR = "transparent";
|
|
188
188
|
var WHITE_COLOR = "#fff";
|
|
189
|
+
var SOLID_RADIUS = 20;
|
|
190
|
+
var OUTLINE_RADIUS = 999;
|
|
191
|
+
var OUTLINE_PAD_H = 12;
|
|
192
|
+
var OUTLINE_PAD_V = 5;
|
|
193
|
+
var OUTLINE_FONT_SIZE = 13;
|
|
194
|
+
var OUTLINE_TINT_ALPHA = 0.1;
|
|
195
|
+
var HEX_SHORT_LENGTH2 = 3;
|
|
196
|
+
var HEX_RADIX2 = 16;
|
|
197
|
+
var RGB_R_START = 0;
|
|
198
|
+
var RGB_R_END = 2;
|
|
199
|
+
var RGB_G_END = 4;
|
|
200
|
+
var RGB_B_END = 6;
|
|
201
|
+
function withAlpha2(hex, alpha) {
|
|
202
|
+
const normalized = hex.replace("#", "");
|
|
203
|
+
const isShort = normalized.length === HEX_SHORT_LENGTH2;
|
|
204
|
+
const full = isShort ? normalized.split("").map((c) => c + c).join("") : normalized;
|
|
205
|
+
const r = parseInt(full.slice(RGB_R_START, RGB_R_END), HEX_RADIX2);
|
|
206
|
+
const g = parseInt(full.slice(RGB_R_END, RGB_G_END), HEX_RADIX2);
|
|
207
|
+
const b = parseInt(full.slice(RGB_G_END, RGB_B_END), HEX_RADIX2);
|
|
208
|
+
const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
|
|
209
|
+
return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
|
|
210
|
+
}
|
|
189
211
|
var styles2 = reactNative.StyleSheet.create({
|
|
190
212
|
label: {
|
|
191
213
|
marginBottom: 8,
|
|
@@ -202,12 +224,72 @@ var styles2 = reactNative.StyleSheet.create({
|
|
|
202
224
|
chip: {
|
|
203
225
|
paddingHorizontal: 12,
|
|
204
226
|
paddingVertical: 6,
|
|
205
|
-
borderRadius:
|
|
227
|
+
borderRadius: SOLID_RADIUS,
|
|
206
228
|
backgroundColor: TRANSPARENT_COLOR,
|
|
207
229
|
borderWidth: 1
|
|
208
230
|
},
|
|
209
|
-
|
|
231
|
+
chipOutline: {
|
|
232
|
+
paddingHorizontal: OUTLINE_PAD_H,
|
|
233
|
+
paddingVertical: OUTLINE_PAD_V,
|
|
234
|
+
borderRadius: OUTLINE_RADIUS,
|
|
235
|
+
borderWidth: 1
|
|
236
|
+
},
|
|
237
|
+
chipText: {},
|
|
238
|
+
chipTextOutline: { fontSize: OUTLINE_FONT_SIZE }
|
|
210
239
|
});
|
|
240
|
+
function OutlineChip({
|
|
241
|
+
option,
|
|
242
|
+
selected,
|
|
243
|
+
disabled,
|
|
244
|
+
colors,
|
|
245
|
+
onPress
|
|
246
|
+
}) {
|
|
247
|
+
const [hovered, setHovered] = React3__default.default.useState(false);
|
|
248
|
+
const active = selected || hovered;
|
|
249
|
+
const borderColor = active ? colors.primary : colors.border;
|
|
250
|
+
const backgroundColor = selected ? colors.tint : colors.muted;
|
|
251
|
+
const textColor = active ? colors.primary : colors.textMuted;
|
|
252
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
253
|
+
reactNative.Pressable,
|
|
254
|
+
{
|
|
255
|
+
accessibilityHint: `Selects ${option.label}`,
|
|
256
|
+
accessibilityLabel: option.label,
|
|
257
|
+
accessibilityRole: "button",
|
|
258
|
+
accessibilityState: { selected },
|
|
259
|
+
disabled,
|
|
260
|
+
style: styles2.chipWrapper,
|
|
261
|
+
testID: `chip-selector-chip-${String(option.value)}`,
|
|
262
|
+
onHoverIn: () => setHovered(true),
|
|
263
|
+
onHoverOut: () => setHovered(false),
|
|
264
|
+
onPress,
|
|
265
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.chipText, styles2.chipTextOutline, { color: textColor }], children: option.label }) })
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
function SolidChip({
|
|
270
|
+
option,
|
|
271
|
+
selected,
|
|
272
|
+
disabled,
|
|
273
|
+
colors,
|
|
274
|
+
onPress
|
|
275
|
+
}) {
|
|
276
|
+
const backgroundColor = selected ? colors.primary : TRANSPARENT_COLOR;
|
|
277
|
+
const textColor = selected ? WHITE_COLOR : colors.textStrong;
|
|
278
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
279
|
+
reactNative.TouchableOpacity,
|
|
280
|
+
{
|
|
281
|
+
accessibilityHint: `Selects ${option.label}`,
|
|
282
|
+
accessibilityLabel: option.label,
|
|
283
|
+
accessibilityRole: "button",
|
|
284
|
+
accessibilityState: { selected },
|
|
285
|
+
disabled,
|
|
286
|
+
style: styles2.chipWrapper,
|
|
287
|
+
testID: `chip-selector-chip-${String(option.value)}`,
|
|
288
|
+
onPress,
|
|
289
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles2.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.chipText, { color: textColor }], children: option.label }) })
|
|
290
|
+
}
|
|
291
|
+
);
|
|
292
|
+
}
|
|
211
293
|
var ChipSelector = ({
|
|
212
294
|
label,
|
|
213
295
|
options,
|
|
@@ -215,57 +297,52 @@ var ChipSelector = ({
|
|
|
215
297
|
onChange,
|
|
216
298
|
multiple = false,
|
|
217
299
|
disabled = false,
|
|
300
|
+
variant = "solid",
|
|
218
301
|
containerStyle
|
|
219
302
|
}) => {
|
|
220
303
|
const { theme } = uiFeedback.useUi();
|
|
221
304
|
const { colors, palette } = theme;
|
|
222
|
-
const primaryColor = palette.primary["500"];
|
|
223
305
|
const hasLabel = typeof label === "string" && label !== "";
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
const chipStyle = { borderColor: colors.border };
|
|
227
|
-
const chipSelectedStyle = { backgroundColor: primaryColor };
|
|
228
|
-
const chipTextStyle = { color: colors.text };
|
|
229
|
-
const chipTextSelectedStyle = { color: WHITE_COLOR };
|
|
306
|
+
const chipColors = React3__default.default.useMemo(() => {
|
|
307
|
+
const primary = palette.primary["500"];
|
|
230
308
|
return {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
309
|
+
border: colors.border,
|
|
310
|
+
textStrong: colors.text,
|
|
311
|
+
textMuted: colors.textSecondary,
|
|
312
|
+
primary,
|
|
313
|
+
muted: colors.background,
|
|
314
|
+
tint: withAlpha2(primary, OUTLINE_TINT_ALPHA)
|
|
236
315
|
};
|
|
237
|
-
}, [colors.border, colors.text,
|
|
316
|
+
}, [colors.border, colors.text, colors.textSecondary, colors.background, palette.primary]);
|
|
317
|
+
const labelStyle = React3__default.default.useMemo(() => ({ color: colors.text }), [colors.text]);
|
|
238
318
|
function isSelected(optionValue) {
|
|
239
319
|
if (multiple && Array.isArray(value))
|
|
240
320
|
return value.includes(optionValue);
|
|
241
321
|
return value === optionValue;
|
|
242
322
|
}
|
|
243
323
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: containerStyle, children: [
|
|
244
|
-
hasLabel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.label,
|
|
324
|
+
hasLabel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.label, labelStyle], children: label }) : null,
|
|
245
325
|
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles2.chipContainer, children: options.map((option) => {
|
|
246
326
|
const selected = isSelected(option.value);
|
|
247
|
-
|
|
248
|
-
|
|
327
|
+
const onPress = () => onChange(option.value);
|
|
328
|
+
return variant === "outline" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
329
|
+
OutlineChip,
|
|
330
|
+
{
|
|
331
|
+
colors: chipColors,
|
|
332
|
+
disabled,
|
|
333
|
+
option,
|
|
334
|
+
selected,
|
|
335
|
+
onPress
|
|
336
|
+
},
|
|
337
|
+
String(option.value)
|
|
338
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
339
|
+
SolidChip,
|
|
249
340
|
{
|
|
250
|
-
|
|
251
|
-
accessibilityLabel: option.label,
|
|
252
|
-
accessibilityRole: "button",
|
|
253
|
-
accessibilityState: { selected },
|
|
341
|
+
colors: chipColors,
|
|
254
342
|
disabled,
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
onPress
|
|
258
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
259
|
-
reactNative.View,
|
|
260
|
-
{
|
|
261
|
-
style: [
|
|
262
|
-
styles2.chip,
|
|
263
|
-
themeStyles.chip,
|
|
264
|
-
selected ? themeStyles.chipSelected : null
|
|
265
|
-
],
|
|
266
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles2.chipText, themeStyles.chipText, selected ? themeStyles.chipTextSelected : null], children: option.label })
|
|
267
|
-
}
|
|
268
|
-
)
|
|
343
|
+
option,
|
|
344
|
+
selected,
|
|
345
|
+
onPress
|
|
269
346
|
},
|
|
270
347
|
String(option.value)
|
|
271
348
|
);
|
|
@@ -304,7 +381,7 @@ var FormSwitch = ({
|
|
|
304
381
|
const { theme } = uiFeedback.useUi();
|
|
305
382
|
const { colors } = theme;
|
|
306
383
|
const hasDescription = typeof description === "string" && description !== "";
|
|
307
|
-
const themeStyles =
|
|
384
|
+
const themeStyles = React3__default.default.useMemo(() => {
|
|
308
385
|
const labelStyle = { color: colors.text };
|
|
309
386
|
const descriptionStyle = { color: colors.textSecondary };
|
|
310
387
|
return { label: labelStyle, description: descriptionStyle };
|
|
@@ -394,7 +471,7 @@ var FormCheckbox = ({
|
|
|
394
471
|
const brand = palette.primary["500"];
|
|
395
472
|
const hintText = typeof hint === "string" && hint !== "" ? hint : description;
|
|
396
473
|
const hasHint = typeof hintText === "string" && hintText !== "";
|
|
397
|
-
const themeStyles =
|
|
474
|
+
const themeStyles = React3__default.default.useMemo(() => {
|
|
398
475
|
const boxOn = { backgroundColor: brand, borderColor: brand };
|
|
399
476
|
const boxOff = { backgroundColor: "transparent", borderColor: colors.border };
|
|
400
477
|
const labelStyle = { color: colors.text };
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../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":["Platform","useUi","useState","useCallback","useMemo","React","ThemedTextInput","jsx","TextInput","StyleSheet","View","jsxs","Text","styles","TouchableOpacity","Switch","Pressable"],"mappings":"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","file":"index.js","sourcesContent":["/**\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 */\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 transitionDuration: 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 { TextInput, type TextInputProps } from 'react-native';\n\nimport { useThemedInput } from '../useThemedInput/useThemedInput';\n\nexport interface ThemedTextInputProps extends TextInputProps {\n /** Render with the error border colour (matches `FormField`'s error treatment). */\n hasError?: boolean;\n}\n\nexport const ThemedTextInput = React.forwardRef<TextInput, ThemedTextInputProps>(function ThemedTextInput(\n { hasError = 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 return (\n <TextInput\n ref={ref}\n placeholderTextColor={placeholderTextColor ?? themedPlaceholder}\n {...rest}\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 input itself is the shared `ThemedTextInput` primitive, so every FormField gets the\n * readable + lively treatment (dark text, subtle off-white rest background, brand focus\n * animation with a soft ring) for free, driven by the active theme.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, type TextInputProps, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { ThemedTextInput } from '../ThemedTextInput/ThemedTextInput';\n\nconst CONTAINER_MARGIN_BOTTOM = 16;\nconst INPUT_PADDING_V = 10;\nconst INPUT_PADDING_H = 12;\nconst INPUT_BORDER_RADIUS = 8;\nconst ERROR_FONT_SIZE = 12;\nconst LABEL_FONT_SIZE = 13;\n\nconst styles = StyleSheet.create({\n container: {\n marginBottom: CONTAINER_MARGIN_BOTTOM,\n },\n label: {\n marginBottom: 4,\n fontSize: LABEL_FONT_SIZE,\n fontWeight: '600',\n },\n input: {\n paddingVertical: INPUT_PADDING_V,\n paddingHorizontal: INPUT_PADDING_H,\n borderRadius: INPUT_BORDER_RADIUS,\n borderWidth: 1,\n },\n errorText: {\n fontSize: ERROR_FONT_SIZE,\n marginTop: 4,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n requiredMark: TextStyle;\n errorText: TextStyle;\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 const { theme } = useUi();\n const { colors, semantic } = theme;\n const errorColor = semantic.error['500'];\n const hasError = typeof error === 'string' && error !== '';\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 return (\n <View style={[styles.container, containerStyle]}>\n <Text style={[styles.label, themeStyles.label]}>\n {label} {required ? <Text style={themeStyles.requiredMark}>*</Text> : null}\n </Text>\n <ThemedTextInput\n accessibilityHint={`Enter ${label}`}\n accessibilityLabel={label}\n hasError={hasError}\n style={styles.input}\n testID=\"form-field-input\"\n {...textInputProps}\n />\n {hasError ? <Text style={[styles.errorText, themeStyles.errorText]}>{error}</Text> : null}\n </View>\n );\n};\n\nexport default FormField;\n","/**\n * Chip/pill selector for selecting one or multiple options.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, TouchableOpacity, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nconst TRANSPARENT_COLOR = 'transparent';\nconst WHITE_COLOR = '#fff';\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: 20,\n backgroundColor: TRANSPARENT_COLOR,\n borderWidth: 1,\n },\n chipText: {},\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n chip: ViewStyle;\n chipSelected: ViewStyle;\n chipText: TextStyle;\n chipTextSelected: TextStyle;\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 containerStyle?: ViewStyle;\n}\n\nexport const ChipSelector = <T extends string | number>({\n label,\n options,\n value,\n onChange,\n multiple = false,\n disabled = false,\n containerStyle,\n}: ChipSelectorProps<T>): React.ReactElement => {\n const { theme } = useUi();\n const { colors, palette } = theme;\n const primaryColor = palette.primary['500'];\n const hasLabel = typeof label === 'string' && label !== '';\n\n const themeStyles = React.useMemo<ThemeStyles>(() => {\n const labelStyle: TextStyle = { color: colors.text };\n const chipStyle: ViewStyle = { borderColor: colors.border };\n const chipSelectedStyle: ViewStyle = { backgroundColor: primaryColor };\n const chipTextStyle: TextStyle = { color: colors.text };\n const chipTextSelectedStyle: TextStyle = { color: WHITE_COLOR };\n return {\n label: labelStyle,\n chip: chipStyle,\n chipSelected: chipSelectedStyle,\n chipText: chipTextStyle,\n chipTextSelected: chipTextSelectedStyle,\n };\n }, [colors.border, colors.text, primaryColor]);\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, themeStyles.label]}>{label}</Text> : null}\n <View style={styles.chipContainer}>\n {options.map((option) => {\n const selected = isSelected(option.value);\n return (\n <TouchableOpacity\n key={String(option.value)}\n accessibilityHint={`Selects ${option.label}`}\n accessibilityLabel={option.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected }}\n disabled={disabled}\n style={styles.chipWrapper}\n testID={`chip-selector-chip-${String(option.value)}`}\n onPress={() => onChange(option.value)}\n >\n <View\n style={[\n styles.chip,\n themeStyles.chip,\n selected ? themeStyles.chipSelected : null,\n ]}\n >\n <Text style={[styles.chipText, themeStyles.chipText, selected ? themeStyles.chipTextSelected : null]}>\n {option.label}\n </Text>\n </View>\n </TouchableOpacity>\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 { StyleSheet, View, Text, Pressable, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\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 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 >\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/useThemedInput/useThemedInput.ts","../src/ThemedTextInput/ThemedTextInput.tsx","../src/FormField/FormField.tsx","../src/ChipSelector/ChipSelector.tsx","../src/FormSwitch/FormSwitch.tsx","../src/FormCheckbox/FormCheckbox.tsx"],"names":["Platform","useUi","useState","useCallback","useMemo","React","ThemedTextInput","jsx","TextInput","StyleSheet","View","jsxs","Text","HEX_SHORT_LENGTH","HEX_RADIX","withAlpha","styles","Pressable","TouchableOpacity","Switch"],"mappings":"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","file":"index.js","sourcesContent":["/**\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 */\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 transitionDuration: 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 { TextInput, type TextInputProps } from 'react-native';\n\nimport { useThemedInput } from '../useThemedInput/useThemedInput';\n\nexport interface ThemedTextInputProps extends TextInputProps {\n /** Render with the error border colour (matches `FormField`'s error treatment). */\n hasError?: boolean;\n}\n\nexport const ThemedTextInput = React.forwardRef<TextInput, ThemedTextInputProps>(function ThemedTextInput(\n { hasError = 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 return (\n <TextInput\n ref={ref}\n placeholderTextColor={placeholderTextColor ?? themedPlaceholder}\n {...rest}\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 input itself is the shared `ThemedTextInput` primitive, so every FormField gets the\n * readable + lively treatment (dark text, subtle off-white rest background, brand focus\n * animation with a soft ring) for free, driven by the active theme.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, type TextInputProps, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { ThemedTextInput } from '../ThemedTextInput/ThemedTextInput';\n\nconst CONTAINER_MARGIN_BOTTOM = 16;\nconst INPUT_PADDING_V = 10;\nconst INPUT_PADDING_H = 12;\nconst INPUT_BORDER_RADIUS = 8;\nconst ERROR_FONT_SIZE = 12;\nconst LABEL_FONT_SIZE = 13;\n\nconst styles = StyleSheet.create({\n container: {\n marginBottom: CONTAINER_MARGIN_BOTTOM,\n },\n label: {\n marginBottom: 4,\n fontSize: LABEL_FONT_SIZE,\n fontWeight: '600',\n },\n input: {\n paddingVertical: INPUT_PADDING_V,\n paddingHorizontal: INPUT_PADDING_H,\n borderRadius: INPUT_BORDER_RADIUS,\n borderWidth: 1,\n },\n errorText: {\n fontSize: ERROR_FONT_SIZE,\n marginTop: 4,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n requiredMark: TextStyle;\n errorText: TextStyle;\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 const { theme } = useUi();\n const { colors, semantic } = theme;\n const errorColor = semantic.error['500'];\n const hasError = typeof error === 'string' && error !== '';\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 return (\n <View style={[styles.container, containerStyle]}>\n <Text style={[styles.label, themeStyles.label]}>\n {label} {required ? <Text style={themeStyles.requiredMark}>*</Text> : null}\n </Text>\n <ThemedTextInput\n accessibilityHint={`Enter ${label}`}\n accessibilityLabel={label}\n hasError={hasError}\n style={styles.input}\n testID=\"form-field-input\"\n {...textInputProps}\n />\n {hasError ? <Text style={[styles.errorText, themeStyles.errorText]}>{error}</Text> : null}\n </View>\n );\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/** 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 }}\n disabled={disabled}\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 }}\n disabled={disabled}\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 { StyleSheet, View, Text, Pressable, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\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 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 >\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/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { Platform, TextInput, StyleSheet, View, Text,
|
|
1
|
+
import React3, { useState, useCallback, useMemo } from 'react';
|
|
2
|
+
import { Platform, TextInput, StyleSheet, View, Text, Switch, Pressable, TouchableOpacity } from 'react-native';
|
|
3
3
|
import { useUi } from '@dloizides/ui-feedback';
|
|
4
4
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -93,7 +93,7 @@ function useThemedInput(options = {}) {
|
|
|
93
93
|
hoverBind
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
|
-
var ThemedTextInput =
|
|
96
|
+
var ThemedTextInput = React3.forwardRef(function ThemedTextInput2({ hasError = false, onFocus, onBlur, style, placeholderTextColor, ...rest }, ref) {
|
|
97
97
|
const {
|
|
98
98
|
style: themedStyle,
|
|
99
99
|
placeholderTextColor: themedPlaceholder,
|
|
@@ -150,7 +150,7 @@ var FormField = ({
|
|
|
150
150
|
const { colors, semantic } = theme;
|
|
151
151
|
const errorColor = semantic.error["500"];
|
|
152
152
|
const hasError = typeof error === "string" && error !== "";
|
|
153
|
-
const themeStyles =
|
|
153
|
+
const themeStyles = React3.useMemo(
|
|
154
154
|
() => ({
|
|
155
155
|
label: { color: colors.textSecondary },
|
|
156
156
|
requiredMark: { color: errorColor },
|
|
@@ -180,6 +180,28 @@ var FormField = ({
|
|
|
180
180
|
};
|
|
181
181
|
var TRANSPARENT_COLOR = "transparent";
|
|
182
182
|
var WHITE_COLOR = "#fff";
|
|
183
|
+
var SOLID_RADIUS = 20;
|
|
184
|
+
var OUTLINE_RADIUS = 999;
|
|
185
|
+
var OUTLINE_PAD_H = 12;
|
|
186
|
+
var OUTLINE_PAD_V = 5;
|
|
187
|
+
var OUTLINE_FONT_SIZE = 13;
|
|
188
|
+
var OUTLINE_TINT_ALPHA = 0.1;
|
|
189
|
+
var HEX_SHORT_LENGTH2 = 3;
|
|
190
|
+
var HEX_RADIX2 = 16;
|
|
191
|
+
var RGB_R_START = 0;
|
|
192
|
+
var RGB_R_END = 2;
|
|
193
|
+
var RGB_G_END = 4;
|
|
194
|
+
var RGB_B_END = 6;
|
|
195
|
+
function withAlpha2(hex, alpha) {
|
|
196
|
+
const normalized = hex.replace("#", "");
|
|
197
|
+
const isShort = normalized.length === HEX_SHORT_LENGTH2;
|
|
198
|
+
const full = isShort ? normalized.split("").map((c) => c + c).join("") : normalized;
|
|
199
|
+
const r = parseInt(full.slice(RGB_R_START, RGB_R_END), HEX_RADIX2);
|
|
200
|
+
const g = parseInt(full.slice(RGB_R_END, RGB_G_END), HEX_RADIX2);
|
|
201
|
+
const b = parseInt(full.slice(RGB_G_END, RGB_B_END), HEX_RADIX2);
|
|
202
|
+
const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
|
|
203
|
+
return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
|
|
204
|
+
}
|
|
183
205
|
var styles2 = StyleSheet.create({
|
|
184
206
|
label: {
|
|
185
207
|
marginBottom: 8,
|
|
@@ -196,12 +218,72 @@ var styles2 = StyleSheet.create({
|
|
|
196
218
|
chip: {
|
|
197
219
|
paddingHorizontal: 12,
|
|
198
220
|
paddingVertical: 6,
|
|
199
|
-
borderRadius:
|
|
221
|
+
borderRadius: SOLID_RADIUS,
|
|
200
222
|
backgroundColor: TRANSPARENT_COLOR,
|
|
201
223
|
borderWidth: 1
|
|
202
224
|
},
|
|
203
|
-
|
|
225
|
+
chipOutline: {
|
|
226
|
+
paddingHorizontal: OUTLINE_PAD_H,
|
|
227
|
+
paddingVertical: OUTLINE_PAD_V,
|
|
228
|
+
borderRadius: OUTLINE_RADIUS,
|
|
229
|
+
borderWidth: 1
|
|
230
|
+
},
|
|
231
|
+
chipText: {},
|
|
232
|
+
chipTextOutline: { fontSize: OUTLINE_FONT_SIZE }
|
|
204
233
|
});
|
|
234
|
+
function OutlineChip({
|
|
235
|
+
option,
|
|
236
|
+
selected,
|
|
237
|
+
disabled,
|
|
238
|
+
colors,
|
|
239
|
+
onPress
|
|
240
|
+
}) {
|
|
241
|
+
const [hovered, setHovered] = React3.useState(false);
|
|
242
|
+
const active = selected || hovered;
|
|
243
|
+
const borderColor = active ? colors.primary : colors.border;
|
|
244
|
+
const backgroundColor = selected ? colors.tint : colors.muted;
|
|
245
|
+
const textColor = active ? colors.primary : colors.textMuted;
|
|
246
|
+
return /* @__PURE__ */ jsx(
|
|
247
|
+
Pressable,
|
|
248
|
+
{
|
|
249
|
+
accessibilityHint: `Selects ${option.label}`,
|
|
250
|
+
accessibilityLabel: option.label,
|
|
251
|
+
accessibilityRole: "button",
|
|
252
|
+
accessibilityState: { selected },
|
|
253
|
+
disabled,
|
|
254
|
+
style: styles2.chipWrapper,
|
|
255
|
+
testID: `chip-selector-chip-${String(option.value)}`,
|
|
256
|
+
onHoverIn: () => setHovered(true),
|
|
257
|
+
onHoverOut: () => setHovered(false),
|
|
258
|
+
onPress,
|
|
259
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles2.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsx(Text, { style: [styles2.chipText, styles2.chipTextOutline, { color: textColor }], children: option.label }) })
|
|
260
|
+
}
|
|
261
|
+
);
|
|
262
|
+
}
|
|
263
|
+
function SolidChip({
|
|
264
|
+
option,
|
|
265
|
+
selected,
|
|
266
|
+
disabled,
|
|
267
|
+
colors,
|
|
268
|
+
onPress
|
|
269
|
+
}) {
|
|
270
|
+
const backgroundColor = selected ? colors.primary : TRANSPARENT_COLOR;
|
|
271
|
+
const textColor = selected ? WHITE_COLOR : colors.textStrong;
|
|
272
|
+
return /* @__PURE__ */ jsx(
|
|
273
|
+
TouchableOpacity,
|
|
274
|
+
{
|
|
275
|
+
accessibilityHint: `Selects ${option.label}`,
|
|
276
|
+
accessibilityLabel: option.label,
|
|
277
|
+
accessibilityRole: "button",
|
|
278
|
+
accessibilityState: { selected },
|
|
279
|
+
disabled,
|
|
280
|
+
style: styles2.chipWrapper,
|
|
281
|
+
testID: `chip-selector-chip-${String(option.value)}`,
|
|
282
|
+
onPress,
|
|
283
|
+
children: /* @__PURE__ */ jsx(View, { style: [styles2.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsx(Text, { style: [styles2.chipText, { color: textColor }], children: option.label }) })
|
|
284
|
+
}
|
|
285
|
+
);
|
|
286
|
+
}
|
|
205
287
|
var ChipSelector = ({
|
|
206
288
|
label,
|
|
207
289
|
options,
|
|
@@ -209,57 +291,52 @@ var ChipSelector = ({
|
|
|
209
291
|
onChange,
|
|
210
292
|
multiple = false,
|
|
211
293
|
disabled = false,
|
|
294
|
+
variant = "solid",
|
|
212
295
|
containerStyle
|
|
213
296
|
}) => {
|
|
214
297
|
const { theme } = useUi();
|
|
215
298
|
const { colors, palette } = theme;
|
|
216
|
-
const primaryColor = palette.primary["500"];
|
|
217
299
|
const hasLabel = typeof label === "string" && label !== "";
|
|
218
|
-
const
|
|
219
|
-
const
|
|
220
|
-
const chipStyle = { borderColor: colors.border };
|
|
221
|
-
const chipSelectedStyle = { backgroundColor: primaryColor };
|
|
222
|
-
const chipTextStyle = { color: colors.text };
|
|
223
|
-
const chipTextSelectedStyle = { color: WHITE_COLOR };
|
|
300
|
+
const chipColors = React3.useMemo(() => {
|
|
301
|
+
const primary = palette.primary["500"];
|
|
224
302
|
return {
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
303
|
+
border: colors.border,
|
|
304
|
+
textStrong: colors.text,
|
|
305
|
+
textMuted: colors.textSecondary,
|
|
306
|
+
primary,
|
|
307
|
+
muted: colors.background,
|
|
308
|
+
tint: withAlpha2(primary, OUTLINE_TINT_ALPHA)
|
|
230
309
|
};
|
|
231
|
-
}, [colors.border, colors.text,
|
|
310
|
+
}, [colors.border, colors.text, colors.textSecondary, colors.background, palette.primary]);
|
|
311
|
+
const labelStyle = React3.useMemo(() => ({ color: colors.text }), [colors.text]);
|
|
232
312
|
function isSelected(optionValue) {
|
|
233
313
|
if (multiple && Array.isArray(value))
|
|
234
314
|
return value.includes(optionValue);
|
|
235
315
|
return value === optionValue;
|
|
236
316
|
}
|
|
237
317
|
return /* @__PURE__ */ jsxs(View, { style: containerStyle, children: [
|
|
238
|
-
hasLabel ? /* @__PURE__ */ jsx(Text, { style: [styles2.label,
|
|
318
|
+
hasLabel ? /* @__PURE__ */ jsx(Text, { style: [styles2.label, labelStyle], children: label }) : null,
|
|
239
319
|
/* @__PURE__ */ jsx(View, { style: styles2.chipContainer, children: options.map((option) => {
|
|
240
320
|
const selected = isSelected(option.value);
|
|
241
|
-
|
|
242
|
-
|
|
321
|
+
const onPress = () => onChange(option.value);
|
|
322
|
+
return variant === "outline" ? /* @__PURE__ */ jsx(
|
|
323
|
+
OutlineChip,
|
|
324
|
+
{
|
|
325
|
+
colors: chipColors,
|
|
326
|
+
disabled,
|
|
327
|
+
option,
|
|
328
|
+
selected,
|
|
329
|
+
onPress
|
|
330
|
+
},
|
|
331
|
+
String(option.value)
|
|
332
|
+
) : /* @__PURE__ */ jsx(
|
|
333
|
+
SolidChip,
|
|
243
334
|
{
|
|
244
|
-
|
|
245
|
-
accessibilityLabel: option.label,
|
|
246
|
-
accessibilityRole: "button",
|
|
247
|
-
accessibilityState: { selected },
|
|
335
|
+
colors: chipColors,
|
|
248
336
|
disabled,
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
onPress
|
|
252
|
-
children: /* @__PURE__ */ jsx(
|
|
253
|
-
View,
|
|
254
|
-
{
|
|
255
|
-
style: [
|
|
256
|
-
styles2.chip,
|
|
257
|
-
themeStyles.chip,
|
|
258
|
-
selected ? themeStyles.chipSelected : null
|
|
259
|
-
],
|
|
260
|
-
children: /* @__PURE__ */ jsx(Text, { style: [styles2.chipText, themeStyles.chipText, selected ? themeStyles.chipTextSelected : null], children: option.label })
|
|
261
|
-
}
|
|
262
|
-
)
|
|
337
|
+
option,
|
|
338
|
+
selected,
|
|
339
|
+
onPress
|
|
263
340
|
},
|
|
264
341
|
String(option.value)
|
|
265
342
|
);
|
|
@@ -298,7 +375,7 @@ var FormSwitch = ({
|
|
|
298
375
|
const { theme } = useUi();
|
|
299
376
|
const { colors } = theme;
|
|
300
377
|
const hasDescription = typeof description === "string" && description !== "";
|
|
301
|
-
const themeStyles =
|
|
378
|
+
const themeStyles = React3.useMemo(() => {
|
|
302
379
|
const labelStyle = { color: colors.text };
|
|
303
380
|
const descriptionStyle = { color: colors.textSecondary };
|
|
304
381
|
return { label: labelStyle, description: descriptionStyle };
|
|
@@ -388,7 +465,7 @@ var FormCheckbox = ({
|
|
|
388
465
|
const brand = palette.primary["500"];
|
|
389
466
|
const hintText = typeof hint === "string" && hint !== "" ? hint : description;
|
|
390
467
|
const hasHint = typeof hintText === "string" && hintText !== "";
|
|
391
|
-
const themeStyles =
|
|
468
|
+
const themeStyles = React3.useMemo(() => {
|
|
392
469
|
const boxOn = { backgroundColor: brand, borderColor: brand };
|
|
393
470
|
const boxOff = { backgroundColor: "transparent", borderColor: colors.border };
|
|
394
471
|
const labelStyle = { color: colors.text };
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../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":["ThemedTextInput","useUi","React","jsx","styles","StyleSheet","jsxs","View","Text"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\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 */\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 transitionDuration: 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 { TextInput, type TextInputProps } from 'react-native';\n\nimport { useThemedInput } from '../useThemedInput/useThemedInput';\n\nexport interface ThemedTextInputProps extends TextInputProps {\n /** Render with the error border colour (matches `FormField`'s error treatment). */\n hasError?: boolean;\n}\n\nexport const ThemedTextInput = React.forwardRef<TextInput, ThemedTextInputProps>(function ThemedTextInput(\n { hasError = 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 return (\n <TextInput\n ref={ref}\n placeholderTextColor={placeholderTextColor ?? themedPlaceholder}\n {...rest}\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 input itself is the shared `ThemedTextInput` primitive, so every FormField gets the\n * readable + lively treatment (dark text, subtle off-white rest background, brand focus\n * animation with a soft ring) for free, driven by the active theme.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, type TextInputProps, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { ThemedTextInput } from '../ThemedTextInput/ThemedTextInput';\n\nconst CONTAINER_MARGIN_BOTTOM = 16;\nconst INPUT_PADDING_V = 10;\nconst INPUT_PADDING_H = 12;\nconst INPUT_BORDER_RADIUS = 8;\nconst ERROR_FONT_SIZE = 12;\nconst LABEL_FONT_SIZE = 13;\n\nconst styles = StyleSheet.create({\n container: {\n marginBottom: CONTAINER_MARGIN_BOTTOM,\n },\n label: {\n marginBottom: 4,\n fontSize: LABEL_FONT_SIZE,\n fontWeight: '600',\n },\n input: {\n paddingVertical: INPUT_PADDING_V,\n paddingHorizontal: INPUT_PADDING_H,\n borderRadius: INPUT_BORDER_RADIUS,\n borderWidth: 1,\n },\n errorText: {\n fontSize: ERROR_FONT_SIZE,\n marginTop: 4,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n requiredMark: TextStyle;\n errorText: TextStyle;\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 const { theme } = useUi();\n const { colors, semantic } = theme;\n const errorColor = semantic.error['500'];\n const hasError = typeof error === 'string' && error !== '';\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 return (\n <View style={[styles.container, containerStyle]}>\n <Text style={[styles.label, themeStyles.label]}>\n {label} {required ? <Text style={themeStyles.requiredMark}>*</Text> : null}\n </Text>\n <ThemedTextInput\n accessibilityHint={`Enter ${label}`}\n accessibilityLabel={label}\n hasError={hasError}\n style={styles.input}\n testID=\"form-field-input\"\n {...textInputProps}\n />\n {hasError ? <Text style={[styles.errorText, themeStyles.errorText]}>{error}</Text> : null}\n </View>\n );\n};\n\nexport default FormField;\n","/**\n * Chip/pill selector for selecting one or multiple options.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, TouchableOpacity, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nconst TRANSPARENT_COLOR = 'transparent';\nconst WHITE_COLOR = '#fff';\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: 20,\n backgroundColor: TRANSPARENT_COLOR,\n borderWidth: 1,\n },\n chipText: {},\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n chip: ViewStyle;\n chipSelected: ViewStyle;\n chipText: TextStyle;\n chipTextSelected: TextStyle;\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 containerStyle?: ViewStyle;\n}\n\nexport const ChipSelector = <T extends string | number>({\n label,\n options,\n value,\n onChange,\n multiple = false,\n disabled = false,\n containerStyle,\n}: ChipSelectorProps<T>): React.ReactElement => {\n const { theme } = useUi();\n const { colors, palette } = theme;\n const primaryColor = palette.primary['500'];\n const hasLabel = typeof label === 'string' && label !== '';\n\n const themeStyles = React.useMemo<ThemeStyles>(() => {\n const labelStyle: TextStyle = { color: colors.text };\n const chipStyle: ViewStyle = { borderColor: colors.border };\n const chipSelectedStyle: ViewStyle = { backgroundColor: primaryColor };\n const chipTextStyle: TextStyle = { color: colors.text };\n const chipTextSelectedStyle: TextStyle = { color: WHITE_COLOR };\n return {\n label: labelStyle,\n chip: chipStyle,\n chipSelected: chipSelectedStyle,\n chipText: chipTextStyle,\n chipTextSelected: chipTextSelectedStyle,\n };\n }, [colors.border, colors.text, primaryColor]);\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, themeStyles.label]}>{label}</Text> : null}\n <View style={styles.chipContainer}>\n {options.map((option) => {\n const selected = isSelected(option.value);\n return (\n <TouchableOpacity\n key={String(option.value)}\n accessibilityHint={`Selects ${option.label}`}\n accessibilityLabel={option.label}\n accessibilityRole=\"button\"\n accessibilityState={{ selected }}\n disabled={disabled}\n style={styles.chipWrapper}\n testID={`chip-selector-chip-${String(option.value)}`}\n onPress={() => onChange(option.value)}\n >\n <View\n style={[\n styles.chip,\n themeStyles.chip,\n selected ? themeStyles.chipSelected : null,\n ]}\n >\n <Text style={[styles.chipText, themeStyles.chipText, selected ? themeStyles.chipTextSelected : null]}>\n {option.label}\n </Text>\n </View>\n </TouchableOpacity>\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 { StyleSheet, View, Text, Pressable, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\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 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 >\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/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","ThemedTextInput","useUi","jsx","HEX_SHORT_LENGTH","HEX_RADIX","withAlpha","styles","StyleSheet","View","Text","jsxs","Pressable"],"mappings":"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","file":"index.mjs","sourcesContent":["/**\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 */\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 transitionDuration: 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 { TextInput, type TextInputProps } from 'react-native';\n\nimport { useThemedInput } from '../useThemedInput/useThemedInput';\n\nexport interface ThemedTextInputProps extends TextInputProps {\n /** Render with the error border colour (matches `FormField`'s error treatment). */\n hasError?: boolean;\n}\n\nexport const ThemedTextInput = React.forwardRef<TextInput, ThemedTextInputProps>(function ThemedTextInput(\n { hasError = 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 return (\n <TextInput\n ref={ref}\n placeholderTextColor={placeholderTextColor ?? themedPlaceholder}\n {...rest}\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 input itself is the shared `ThemedTextInput` primitive, so every FormField gets the\n * readable + lively treatment (dark text, subtle off-white rest background, brand focus\n * animation with a soft ring) for free, driven by the active theme.\n */\nimport React from 'react';\n\nimport { StyleSheet, View, Text, type TextInputProps, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\n\nimport { ThemedTextInput } from '../ThemedTextInput/ThemedTextInput';\n\nconst CONTAINER_MARGIN_BOTTOM = 16;\nconst INPUT_PADDING_V = 10;\nconst INPUT_PADDING_H = 12;\nconst INPUT_BORDER_RADIUS = 8;\nconst ERROR_FONT_SIZE = 12;\nconst LABEL_FONT_SIZE = 13;\n\nconst styles = StyleSheet.create({\n container: {\n marginBottom: CONTAINER_MARGIN_BOTTOM,\n },\n label: {\n marginBottom: 4,\n fontSize: LABEL_FONT_SIZE,\n fontWeight: '600',\n },\n input: {\n paddingVertical: INPUT_PADDING_V,\n paddingHorizontal: INPUT_PADDING_H,\n borderRadius: INPUT_BORDER_RADIUS,\n borderWidth: 1,\n },\n errorText: {\n fontSize: ERROR_FONT_SIZE,\n marginTop: 4,\n },\n});\n\ninterface ThemeStyles {\n label: TextStyle;\n requiredMark: TextStyle;\n errorText: TextStyle;\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 const { theme } = useUi();\n const { colors, semantic } = theme;\n const errorColor = semantic.error['500'];\n const hasError = typeof error === 'string' && error !== '';\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 return (\n <View style={[styles.container, containerStyle]}>\n <Text style={[styles.label, themeStyles.label]}>\n {label} {required ? <Text style={themeStyles.requiredMark}>*</Text> : null}\n </Text>\n <ThemedTextInput\n accessibilityHint={`Enter ${label}`}\n accessibilityLabel={label}\n hasError={hasError}\n style={styles.input}\n testID=\"form-field-input\"\n {...textInputProps}\n />\n {hasError ? <Text style={[styles.errorText, themeStyles.errorText]}>{error}</Text> : null}\n </View>\n );\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/** 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 }}\n disabled={disabled}\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 }}\n disabled={disabled}\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 { StyleSheet, View, Text, Pressable, type TextStyle, type ViewStyle } from 'react-native';\n\nimport { useUi } from '@dloizides/ui-feedback';\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 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 >\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,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dloizides/ui-forms",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
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
5
|
"keywords": [
|
|
6
6
|
"react",
|