@dloizides/ui-forms 1.4.0 → 1.5.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 +18 -0
- package/README.md +39 -1
- package/dist/index.d.mts +42 -5
- package/dist/index.d.ts +42 -5
- package/dist/index.js +103 -83
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +104 -85
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.5.0
|
|
4
|
+
|
|
5
|
+
- **Add `Field` — the generic label-over-control wrapper.** `FormField` is hard-wired to a text
|
|
6
|
+
input (`FormFieldProps extends Omit<TextInputProps,'style'>`), so any NON-text control (a
|
|
7
|
+
dropdown, a date picker, a chip selector) had no shared way to get a label — and ended up
|
|
8
|
+
visually misaligned next to its `FormField` siblings: the control's box started ~21px higher
|
|
9
|
+
(no label row) and it missed `FormField`'s `marginBottom: 16`, so wrapped rows lost their
|
|
10
|
+
vertical rhythm. This was hand-rolled in 5 places across zygos-web and aml-v2.
|
|
11
|
+
`Field` takes `{ label, required?, error?, children, containerStyle?, testID? }` and renders the
|
|
12
|
+
same label row / required mark / error line / spacing.
|
|
13
|
+
- **`FormField` now composes `Field` internally**, so the two can never drift apart — the metrics
|
|
14
|
+
live in exactly one place. `FormFieldProps` and every rendered attribute (`form-field-input`
|
|
15
|
+
testID, `aria-invalid` / `aria-describedby` / `aria-required`, the `role="alert"` error line)
|
|
16
|
+
are unchanged: fully backward-compatible.
|
|
17
|
+
- `Field`'s `children` may be a plain node (the common case) or a render function receiving
|
|
18
|
+
`{ describedById, hasError }`, so a custom control can wire the error line into its own
|
|
19
|
+
`aria-describedby` / invalid state exactly the way `FormField` does.
|
|
20
|
+
|
|
3
21
|
## 1.4.0
|
|
4
22
|
|
|
5
23
|
- **Accessibility (WCAG 2.1 AA) hardening — additive + backward-compatible.**
|
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @dloizides/ui-forms
|
|
2
2
|
|
|
3
3
|
Themable, brand-agnostic React Native (RN-web) **form** components for the dloizides.com
|
|
4
|
-
portfolio: `FormField`, `ChipSelector`, `FormSwitch`. They read theme colours from the shared
|
|
4
|
+
portfolio: `Field`, `FormField`, `ChipSelector`, `FormSwitch`. They read theme colours from the shared
|
|
5
5
|
`@dloizides/ui-feedback` UI context (`useUi`) — mount one `UiProvider` / `FeedbackUiProvider`
|
|
6
6
|
at your app root and these components pick up your theme automatically.
|
|
7
7
|
|
|
@@ -24,6 +24,44 @@ import { FormField, ChipSelector, FormSwitch } from '@dloizides/ui-forms';
|
|
|
24
24
|
<FormSwitch label="Email notifications" value={notify} onValueChange={setNotify} />
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
+
## `Field` — label any control, not just a text input
|
|
28
|
+
|
|
29
|
+
`FormField` is hard-wired to a text input. For **any other control** — a dropdown, a date picker,
|
|
30
|
+
a chip selector — wrap it in `Field` to get the identical label row, required mark, error line and
|
|
31
|
+
bottom spacing. This is what keeps a dropdown aligned with the `FormField` next to it: without it
|
|
32
|
+
the dropdown's box starts a label-row higher and the row loses its vertical rhythm.
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { Field } from '@dloizides/ui-forms';
|
|
36
|
+
|
|
37
|
+
<Field label="Currency" required error={errors.currency}>
|
|
38
|
+
<ModalDropdown options={currencies} value={currency} onChange={setCurrency} />
|
|
39
|
+
</Field>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
`FormField` composes `Field` internally, so the two can never drift out of alignment.
|
|
43
|
+
|
|
44
|
+
To wire the error line into a custom control's own `aria-describedby` / invalid state, pass a
|
|
45
|
+
**function** child — it receives `{ describedById, hasError }` (`describedById` is `undefined`
|
|
46
|
+
when there is no error):
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
<Field label="Country" error={errors.country}>
|
|
50
|
+
{({ describedById, hasError }) => (
|
|
51
|
+
<CountryPicker aria-describedby={describedById} hasError={hasError} value={country} onChange={setCountry} />
|
|
52
|
+
)}
|
|
53
|
+
</Field>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
| Prop | Type | Notes |
|
|
57
|
+
|------|------|-------|
|
|
58
|
+
| `label` | `string` | required |
|
|
59
|
+
| `children` | `ReactNode \| (ctx) => ReactNode` | the control |
|
|
60
|
+
| `required` | `boolean` | renders a decorative `*` (hidden from assistive tech) |
|
|
61
|
+
| `error` | `string` | renders a `role="alert"` line, linked via the child's `describedById` |
|
|
62
|
+
| `containerStyle` | `ViewStyle` | merged over the container |
|
|
63
|
+
| `testID` | `string` | on the container |
|
|
64
|
+
|
|
27
65
|
The injected theme needs `colors.{surface,text,textSecondary,border}`, `palette.primary['500']`
|
|
28
66
|
and `semantic.error['500']` — supplied via `@dloizides/ui-feedback`'s provider. Without a provider
|
|
29
67
|
the components fall back to a neutral default theme.
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,49 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ViewStyle, TextInputProps, TextInput, TextStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Field — the generic "label over a control, error under it" wrapper.
|
|
6
|
+
*
|
|
7
|
+
* `FormField` is hard-wired to a text input, so any NON-text control (a dropdown, a date picker,
|
|
8
|
+
* a chip selector) had no shared way to get a label — and ended up visually misaligned next to
|
|
9
|
+
* its `FormField` siblings: its box started a label-row higher, and it missed the container's
|
|
10
|
+
* bottom margin so wrapped rows lost their vertical rhythm.
|
|
11
|
+
*
|
|
12
|
+
* `Field` is that label row + spacing, control-agnostic. Its metrics are the single source of
|
|
13
|
+
* truth: `FormField` composes `Field` internally, so the two can never drift apart.
|
|
14
|
+
*
|
|
15
|
+
* Children may be a plain node (the common case — just wrap your control) or a render function
|
|
16
|
+
* receiving `{ describedById, hasError }`, so a custom control can wire the error line into its
|
|
17
|
+
* own `aria-describedby` / invalid state exactly the way `FormField` does.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** What a render-function child receives, so it can mirror `FormField`'s error wiring. */
|
|
21
|
+
interface FieldChildContext {
|
|
22
|
+
/** id of the rendered error line, or `undefined` when there is no error. */
|
|
23
|
+
describedById?: string;
|
|
24
|
+
hasError: boolean;
|
|
25
|
+
}
|
|
26
|
+
type FieldChildren = React.ReactNode | ((context: FieldChildContext) => React.ReactNode);
|
|
27
|
+
interface FieldProps {
|
|
28
|
+
label: string;
|
|
29
|
+
children: FieldChildren;
|
|
30
|
+
required?: boolean;
|
|
31
|
+
error?: string;
|
|
32
|
+
containerStyle?: ViewStyle;
|
|
33
|
+
testID?: string;
|
|
34
|
+
}
|
|
35
|
+
declare const Field: ({ label, children, required, error, containerStyle, testID, }: FieldProps) => React.ReactElement;
|
|
3
36
|
|
|
4
37
|
/**
|
|
5
38
|
* Reusable form field — labelled text input with optional required mark + error.
|
|
6
39
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
40
|
+
* The label row, the required mark, the error line and the container spacing all come from the
|
|
41
|
+
* generic `Field` wrapper, so a `FormField` and a `Field`-wrapped dropdown sitting next to each
|
|
42
|
+
* other line up exactly and can never drift apart. FormField only adds the control itself.
|
|
43
|
+
*
|
|
44
|
+
* The input is the shared `ThemedTextInput` primitive, so every FormField gets the readable +
|
|
45
|
+
* lively treatment (dark text, subtle off-white rest background, brand focus animation with a
|
|
46
|
+
* soft ring) for free, driven by the active theme.
|
|
10
47
|
*/
|
|
11
48
|
|
|
12
49
|
interface FormFieldProps extends Omit<TextInputProps, 'style'> {
|
|
@@ -142,4 +179,4 @@ interface FormCheckboxProps {
|
|
|
142
179
|
}
|
|
143
180
|
declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, description, disabled, containerStyle, testID, accessibilityLabel, accessibilityHint, }: FormCheckboxProps) => React.ReactElement;
|
|
144
181
|
|
|
145
|
-
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 };
|
|
182
|
+
export { type ChipOption, ChipSelector, type ChipSelectorProps, type ChipVariant, Field, type FieldChildContext, type FieldChildren, type FieldProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormSwitch, type FormSwitchProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, type UseThemedInputOptions, useThemedInput };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,49 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { ViewStyle, TextInputProps, TextInput, TextStyle } from 'react-native';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Field — the generic "label over a control, error under it" wrapper.
|
|
6
|
+
*
|
|
7
|
+
* `FormField` is hard-wired to a text input, so any NON-text control (a dropdown, a date picker,
|
|
8
|
+
* a chip selector) had no shared way to get a label — and ended up visually misaligned next to
|
|
9
|
+
* its `FormField` siblings: its box started a label-row higher, and it missed the container's
|
|
10
|
+
* bottom margin so wrapped rows lost their vertical rhythm.
|
|
11
|
+
*
|
|
12
|
+
* `Field` is that label row + spacing, control-agnostic. Its metrics are the single source of
|
|
13
|
+
* truth: `FormField` composes `Field` internally, so the two can never drift apart.
|
|
14
|
+
*
|
|
15
|
+
* Children may be a plain node (the common case — just wrap your control) or a render function
|
|
16
|
+
* receiving `{ describedById, hasError }`, so a custom control can wire the error line into its
|
|
17
|
+
* own `aria-describedby` / invalid state exactly the way `FormField` does.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/** What a render-function child receives, so it can mirror `FormField`'s error wiring. */
|
|
21
|
+
interface FieldChildContext {
|
|
22
|
+
/** id of the rendered error line, or `undefined` when there is no error. */
|
|
23
|
+
describedById?: string;
|
|
24
|
+
hasError: boolean;
|
|
25
|
+
}
|
|
26
|
+
type FieldChildren = React.ReactNode | ((context: FieldChildContext) => React.ReactNode);
|
|
27
|
+
interface FieldProps {
|
|
28
|
+
label: string;
|
|
29
|
+
children: FieldChildren;
|
|
30
|
+
required?: boolean;
|
|
31
|
+
error?: string;
|
|
32
|
+
containerStyle?: ViewStyle;
|
|
33
|
+
testID?: string;
|
|
34
|
+
}
|
|
35
|
+
declare const Field: ({ label, children, required, error, containerStyle, testID, }: FieldProps) => React.ReactElement;
|
|
3
36
|
|
|
4
37
|
/**
|
|
5
38
|
* Reusable form field — labelled text input with optional required mark + error.
|
|
6
39
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
40
|
+
* The label row, the required mark, the error line and the container spacing all come from the
|
|
41
|
+
* generic `Field` wrapper, so a `FormField` and a `Field`-wrapped dropdown sitting next to each
|
|
42
|
+
* other line up exactly and can never drift apart. FormField only adds the control itself.
|
|
43
|
+
*
|
|
44
|
+
* The input is the shared `ThemedTextInput` primitive, so every FormField gets the readable +
|
|
45
|
+
* lively treatment (dark text, subtle off-white rest background, brand focus animation with a
|
|
46
|
+
* soft ring) for free, driven by the active theme.
|
|
10
47
|
*/
|
|
11
48
|
|
|
12
49
|
interface FormFieldProps extends Omit<TextInputProps, 'style'> {
|
|
@@ -142,4 +179,4 @@ interface FormCheckboxProps {
|
|
|
142
179
|
}
|
|
143
180
|
declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, description, disabled, containerStyle, testID, accessibilityLabel, accessibilityHint, }: FormCheckboxProps) => React.ReactElement;
|
|
144
181
|
|
|
145
|
-
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 };
|
|
182
|
+
export { type ChipOption, ChipSelector, type ChipSelectorProps, type ChipVariant, Field, type FieldChildContext, type FieldChildren, type FieldProps, FormCheckbox, type FormCheckboxProps, FormField, type FormFieldProps, FormSwitch, type FormSwitchProps, type ThemedInput, ThemedTextInput, type ThemedTextInputProps, type UseThemedInputOptions, useThemedInput };
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,74 @@ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
|
9
9
|
|
|
10
10
|
var React3__default = /*#__PURE__*/_interopDefault(React3);
|
|
11
11
|
|
|
12
|
-
// src/
|
|
12
|
+
// src/Field/Field.tsx
|
|
13
|
+
var CONTAINER_MARGIN_BOTTOM = 16;
|
|
14
|
+
var LABEL_FONT_SIZE = 13;
|
|
15
|
+
var LABEL_FONT_WEIGHT = "600";
|
|
16
|
+
var LABEL_MARGIN_BOTTOM = 4;
|
|
17
|
+
var ERROR_FONT_SIZE = 12;
|
|
18
|
+
var ERROR_MARGIN_TOP = 4;
|
|
19
|
+
var styles = reactNative.StyleSheet.create({
|
|
20
|
+
container: {
|
|
21
|
+
marginBottom: CONTAINER_MARGIN_BOTTOM
|
|
22
|
+
},
|
|
23
|
+
label: {
|
|
24
|
+
marginBottom: LABEL_MARGIN_BOTTOM,
|
|
25
|
+
fontSize: LABEL_FONT_SIZE,
|
|
26
|
+
fontWeight: LABEL_FONT_WEIGHT
|
|
27
|
+
},
|
|
28
|
+
errorText: {
|
|
29
|
+
fontSize: ERROR_FONT_SIZE,
|
|
30
|
+
marginTop: ERROR_MARGIN_TOP
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
var fieldSeq = 0;
|
|
34
|
+
function useFieldErrorId() {
|
|
35
|
+
const [id] = React3__default.default.useState(() => {
|
|
36
|
+
fieldSeq += 1;
|
|
37
|
+
return `field-error-${String(fieldSeq)}`;
|
|
38
|
+
});
|
|
39
|
+
return id;
|
|
40
|
+
}
|
|
41
|
+
function hasFieldError(error) {
|
|
42
|
+
return typeof error === "string" && error !== "";
|
|
43
|
+
}
|
|
44
|
+
var Field = ({
|
|
45
|
+
label,
|
|
46
|
+
children,
|
|
47
|
+
required = false,
|
|
48
|
+
error,
|
|
49
|
+
containerStyle,
|
|
50
|
+
testID
|
|
51
|
+
}) => {
|
|
52
|
+
const { theme } = uiFeedback.useUi();
|
|
53
|
+
const { colors, semantic } = theme;
|
|
54
|
+
const errorColor = semantic.error["500"];
|
|
55
|
+
const hasError = hasFieldError(error);
|
|
56
|
+
const errorId = useFieldErrorId();
|
|
57
|
+
const themeStyles = React3__default.default.useMemo(
|
|
58
|
+
() => ({
|
|
59
|
+
label: { color: colors.textSecondary },
|
|
60
|
+
requiredMark: { color: errorColor },
|
|
61
|
+
errorText: { color: errorColor }
|
|
62
|
+
}),
|
|
63
|
+
[colors.textSecondary, errorColor]
|
|
64
|
+
);
|
|
65
|
+
const control = typeof children === "function" ? children({ describedById: hasError ? errorId : void 0, hasError }) : children;
|
|
66
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.container, containerStyle], testID, children: [
|
|
67
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles.label, themeStyles.label], children: [
|
|
68
|
+
label,
|
|
69
|
+
" ",
|
|
70
|
+
required ? (
|
|
71
|
+
// The asterisk is decorative — the control's `aria-required` conveys "required" to
|
|
72
|
+
// assistive tech, so a screen reader says "required" instead of "star".
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { "aria-hidden": true, accessibilityElementsHidden: true, importantForAccessibility: "no", style: themeStyles.requiredMark, children: "*" })
|
|
74
|
+
) : null
|
|
75
|
+
] }),
|
|
76
|
+
control,
|
|
77
|
+
hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: errorId, role: "alert", style: [styles.errorText, themeStyles.errorText], children: error }) : null
|
|
78
|
+
] });
|
|
79
|
+
};
|
|
13
80
|
var IS_WEB = reactNative.Platform.OS === "web";
|
|
14
81
|
var TRANSITION_PROPERTY = "border-color, background-color, box-shadow";
|
|
15
82
|
var TRANSITION_DURATION = "0.14s";
|
|
@@ -131,85 +198,37 @@ var ThemedTextInput = React3__default.default.forwardRef(function ThemedTextInpu
|
|
|
131
198
|
}
|
|
132
199
|
);
|
|
133
200
|
});
|
|
134
|
-
var CONTAINER_MARGIN_BOTTOM = 16;
|
|
135
201
|
var INPUT_PADDING_V = 10;
|
|
136
202
|
var INPUT_PADDING_H = 12;
|
|
137
203
|
var INPUT_BORDER_RADIUS = 8;
|
|
138
|
-
var
|
|
139
|
-
var
|
|
140
|
-
var styles = reactNative.StyleSheet.create({
|
|
141
|
-
container: {
|
|
142
|
-
marginBottom: CONTAINER_MARGIN_BOTTOM
|
|
143
|
-
},
|
|
144
|
-
label: {
|
|
145
|
-
marginBottom: 4,
|
|
146
|
-
fontSize: LABEL_FONT_SIZE,
|
|
147
|
-
fontWeight: "600"
|
|
148
|
-
},
|
|
204
|
+
var INPUT_BORDER_WIDTH = 1;
|
|
205
|
+
var styles2 = reactNative.StyleSheet.create({
|
|
149
206
|
input: {
|
|
150
207
|
paddingVertical: INPUT_PADDING_V,
|
|
151
208
|
paddingHorizontal: INPUT_PADDING_H,
|
|
152
209
|
borderRadius: INPUT_BORDER_RADIUS,
|
|
153
|
-
borderWidth:
|
|
154
|
-
},
|
|
155
|
-
errorText: {
|
|
156
|
-
fontSize: ERROR_FONT_SIZE,
|
|
157
|
-
marginTop: 4
|
|
210
|
+
borderWidth: INPUT_BORDER_WIDTH
|
|
158
211
|
}
|
|
159
212
|
});
|
|
160
|
-
var formFieldSeq = 0;
|
|
161
|
-
function useErrorId() {
|
|
162
|
-
const [id] = React3__default.default.useState(() => {
|
|
163
|
-
formFieldSeq += 1;
|
|
164
|
-
return `form-field-error-${String(formFieldSeq)}`;
|
|
165
|
-
});
|
|
166
|
-
return id;
|
|
167
|
-
}
|
|
168
213
|
var FormField = ({
|
|
169
214
|
label,
|
|
170
215
|
required = false,
|
|
171
216
|
error,
|
|
172
217
|
containerStyle,
|
|
173
218
|
...textInputProps
|
|
174
|
-
}) => {
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
);
|
|
188
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: [styles.container, containerStyle], children: [
|
|
189
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.Text, { style: [styles.label, themeStyles.label], children: [
|
|
190
|
-
label,
|
|
191
|
-
" ",
|
|
192
|
-
required ? (
|
|
193
|
-
// The asterisk is decorative — `requiredField` conveys "required" to assistive tech.
|
|
194
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { "aria-hidden": true, accessibilityElementsHidden: true, importantForAccessibility: "no", style: themeStyles.requiredMark, children: "*" })
|
|
195
|
-
) : null
|
|
196
|
-
] }),
|
|
197
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
198
|
-
ThemedTextInput,
|
|
199
|
-
{
|
|
200
|
-
accessibilityHint: `Enter ${label}`,
|
|
201
|
-
accessibilityLabel: label,
|
|
202
|
-
describedById: hasError ? errorId : void 0,
|
|
203
|
-
hasError,
|
|
204
|
-
requiredField: required,
|
|
205
|
-
style: styles.input,
|
|
206
|
-
testID: "form-field-input",
|
|
207
|
-
...textInputProps
|
|
208
|
-
}
|
|
209
|
-
),
|
|
210
|
-
hasError ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { nativeID: errorId, role: "alert", style: [styles.errorText, themeStyles.errorText], children: error }) : null
|
|
211
|
-
] });
|
|
212
|
-
};
|
|
219
|
+
}) => /* @__PURE__ */ jsxRuntime.jsx(Field, { containerStyle, error, label, required, children: ({ describedById, hasError }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
220
|
+
ThemedTextInput,
|
|
221
|
+
{
|
|
222
|
+
accessibilityHint: `Enter ${label}`,
|
|
223
|
+
accessibilityLabel: label,
|
|
224
|
+
describedById,
|
|
225
|
+
hasError,
|
|
226
|
+
requiredField: required,
|
|
227
|
+
style: styles2.input,
|
|
228
|
+
testID: "form-field-input",
|
|
229
|
+
...textInputProps
|
|
230
|
+
}
|
|
231
|
+
) });
|
|
213
232
|
var TRANSPARENT_COLOR = "transparent";
|
|
214
233
|
var WHITE_COLOR = "#fff";
|
|
215
234
|
var SOLID_RADIUS = 20;
|
|
@@ -235,7 +254,7 @@ function withAlpha2(hex, alpha) {
|
|
|
235
254
|
const isValid = !Number.isNaN(r) && !Number.isNaN(g) && !Number.isNaN(b);
|
|
236
255
|
return isValid ? `rgba(${r}, ${g}, ${b}, ${alpha})` : hex;
|
|
237
256
|
}
|
|
238
|
-
var
|
|
257
|
+
var styles3 = reactNative.StyleSheet.create({
|
|
239
258
|
label: {
|
|
240
259
|
marginBottom: 8,
|
|
241
260
|
fontWeight: "600"
|
|
@@ -285,12 +304,12 @@ function OutlineChip({
|
|
|
285
304
|
accessibilityState: { selected, disabled },
|
|
286
305
|
disabled,
|
|
287
306
|
hitSlop: CHIP_HIT_SLOP,
|
|
288
|
-
style:
|
|
307
|
+
style: styles3.chipWrapper,
|
|
289
308
|
testID: `chip-selector-chip-${String(option.value)}`,
|
|
290
309
|
onHoverIn: () => setHovered(true),
|
|
291
310
|
onHoverOut: () => setHovered(false),
|
|
292
311
|
onPress,
|
|
293
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
312
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.chipOutline, { borderColor, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.chipText, styles3.chipTextOutline, { color: textColor }], children: option.label }) })
|
|
294
313
|
}
|
|
295
314
|
);
|
|
296
315
|
}
|
|
@@ -312,10 +331,10 @@ function SolidChip({
|
|
|
312
331
|
accessibilityState: { selected, disabled },
|
|
313
332
|
disabled,
|
|
314
333
|
hitSlop: CHIP_HIT_SLOP,
|
|
315
|
-
style:
|
|
334
|
+
style: styles3.chipWrapper,
|
|
316
335
|
testID: `chip-selector-chip-${String(option.value)}`,
|
|
317
336
|
onPress,
|
|
318
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
337
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles3.chip, { borderColor: colors.border, backgroundColor }], children: /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.chipText, { color: textColor }], children: option.label }) })
|
|
319
338
|
}
|
|
320
339
|
);
|
|
321
340
|
}
|
|
@@ -350,8 +369,8 @@ var ChipSelector = ({
|
|
|
350
369
|
return value === optionValue;
|
|
351
370
|
}
|
|
352
371
|
return /* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: containerStyle, children: [
|
|
353
|
-
hasLabel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
354
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style:
|
|
372
|
+
hasLabel ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles3.label, labelStyle], children: label }) : null,
|
|
373
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: styles3.chipContainer, children: options.map((option) => {
|
|
355
374
|
const selected = isSelected(option.value);
|
|
356
375
|
const onPress = () => onChange(option.value);
|
|
357
376
|
return variant === "outline" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -379,7 +398,7 @@ var ChipSelector = ({
|
|
|
379
398
|
] });
|
|
380
399
|
};
|
|
381
400
|
var DESCRIPTION_FONT_SIZE = 12;
|
|
382
|
-
var
|
|
401
|
+
var styles4 = reactNative.StyleSheet.create({
|
|
383
402
|
container: {
|
|
384
403
|
flexDirection: "row",
|
|
385
404
|
justifyContent: "space-between",
|
|
@@ -419,13 +438,13 @@ var FormSwitch = ({
|
|
|
419
438
|
reactNative.View,
|
|
420
439
|
{
|
|
421
440
|
style: [
|
|
422
|
-
|
|
441
|
+
styles4.container,
|
|
423
442
|
containerStyle
|
|
424
443
|
],
|
|
425
444
|
children: [
|
|
426
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
427
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
428
|
-
hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
445
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles4.textColumn, children: [
|
|
446
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.label, themeStyles.label], children: label }),
|
|
447
|
+
hasDescription ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles4.description, themeStyles.description], children: description }) : null
|
|
429
448
|
] }),
|
|
430
449
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
431
450
|
reactNative.Switch,
|
|
@@ -450,7 +469,7 @@ var BOX_SIZE = 20;
|
|
|
450
469
|
var BOX_RADIUS = 5;
|
|
451
470
|
var CHECK_FONT_SIZE = 14;
|
|
452
471
|
var DISABLED_OPACITY = 0.5;
|
|
453
|
-
var
|
|
472
|
+
var styles5 = reactNative.StyleSheet.create({
|
|
454
473
|
container: {
|
|
455
474
|
flexDirection: "row",
|
|
456
475
|
alignItems: "flex-start",
|
|
@@ -532,14 +551,14 @@ var FormCheckbox = ({
|
|
|
532
551
|
disabled,
|
|
533
552
|
onPress: toggle,
|
|
534
553
|
role: "checkbox",
|
|
535
|
-
style: [
|
|
554
|
+
style: [styles5.container, containerStyle, disabled ? { opacity: DISABLED_OPACITY } : null],
|
|
536
555
|
testID,
|
|
537
556
|
...keyboardProps,
|
|
538
557
|
children: [
|
|
539
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [
|
|
540
|
-
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style:
|
|
541
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
542
|
-
hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [
|
|
558
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.View, { style: [styles5.box, value ? themeStyles.boxOn : themeStyles.boxOff], children: value ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.check, { color: colors.surface }], accessibilityElementsHidden: true, children: "\u2713" }) : null }),
|
|
559
|
+
/* @__PURE__ */ jsxRuntime.jsxs(reactNative.View, { style: styles5.textColumn, children: [
|
|
560
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.label, themeStyles.label], children: label }),
|
|
561
|
+
hasHint ? /* @__PURE__ */ jsxRuntime.jsx(reactNative.Text, { style: [styles5.hint, themeStyles.hint], children: hintText }) : null
|
|
543
562
|
] })
|
|
544
563
|
]
|
|
545
564
|
}
|
|
@@ -547,6 +566,7 @@ var FormCheckbox = ({
|
|
|
547
566
|
};
|
|
548
567
|
|
|
549
568
|
exports.ChipSelector = ChipSelector;
|
|
569
|
+
exports.Field = Field;
|
|
550
570
|
exports.FormCheckbox = FormCheckbox;
|
|
551
571
|
exports.FormField = FormField;
|
|
552
572
|
exports.FormSwitch = FormSwitch;
|