@dloizides/ui-forms 1.4.0 → 1.6.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 +47 -0
- package/README.md +107 -37
- package/dist/index.d.mts +61 -6
- package/dist/index.d.ts +61 -6
- package/dist/index.js +147 -135
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +138 -127
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 1.6.0
|
|
4
|
+
|
|
5
|
+
- **`ChipSelector` now composes `Field` internally — its label was drifting.** It rendered its OWN
|
|
6
|
+
`<Text>` label whose metrics differed from `Field`'s on three of four axes: `marginBottom: 8`
|
|
7
|
+
(vs 4), NO `fontSize` at all so it fell back to RN's ~14 (vs 13), and `colors.text`
|
|
8
|
+
(vs `textSecondary`). A `ChipSelector` next to a `FormField` in a row/grid therefore started a
|
|
9
|
+
different distance down the column and read as a different weight of text. Found at 4 sites in
|
|
10
|
+
aml-v2 (`TenantWatchlistsEditor`, `CoverageSelector`, `CustomCoverageFields`,
|
|
11
|
+
`AdvancedMatching`); fixing it in the package fixes every consumer with zero app churn.
|
|
12
|
+
The local label styles are deleted — there is now exactly one label implementation in the kit.
|
|
13
|
+
- **`ChipSelectorProps` is unchanged and fully backward-compatible** — every existing prop keeps
|
|
14
|
+
its name, type and default, and `label` stays OPTIONAL. With no label (or an empty one) NO label
|
|
15
|
+
row is rendered, so composing `Field` cannot introduce a phantom gap above the chips.
|
|
16
|
+
- **`ChipSelector` gains `required`, `error` and `testID`** (all optional, all additive) now that
|
|
17
|
+
`Field` provides them for free. `error` renders the same `role="alert"` line as `FormField` and
|
|
18
|
+
is tied to the chip group via `aria-describedby` + `aria-invalid` (web only; no-op on native).
|
|
19
|
+
- **Spacing:** a `ChipSelector` now carries `Field`'s `marginBottom: 16` like every other field
|
|
20
|
+
(it previously had none). The chips' own 8px trailing gutter is cancelled on the group so the
|
|
21
|
+
block's total bottom spacing is exactly 16 — the same as a `FormField`, not 24. Pass
|
|
22
|
+
`containerStyle` to override, as before.
|
|
23
|
+
- **`Field`'s `label` is now optional** (widened from `label: string`, so existing callers are
|
|
24
|
+
unaffected). An absent or empty label renders no label row, letting a control whose label lives
|
|
25
|
+
elsewhere still use the shared shell for its error line and spacing.
|
|
26
|
+
- `FormSwitch` / `FormCheckbox` are deliberately NOT changed — see `src/labelRoles.test.tsx`.
|
|
27
|
+
Their labels are INLINE control labels (beside the control in a row, the row's primary text),
|
|
28
|
+
not field headers stacked above a control, so they have no alignment defect to fix and `Field`'s
|
|
29
|
+
smaller/dimmer header treatment would be a regression. They were already identical to each
|
|
30
|
+
other; a new test now enforces that they stay so.
|
|
31
|
+
|
|
32
|
+
## 1.5.0
|
|
33
|
+
|
|
34
|
+
- **Add `Field` — the generic label-over-control wrapper.** `FormField` is hard-wired to a text
|
|
35
|
+
input (`FormFieldProps extends Omit<TextInputProps,'style'>`), so any NON-text control (a
|
|
36
|
+
dropdown, a date picker, a chip selector) had no shared way to get a label — and ended up
|
|
37
|
+
visually misaligned next to its `FormField` siblings: the control's box started ~21px higher
|
|
38
|
+
(no label row) and it missed `FormField`'s `marginBottom: 16`, so wrapped rows lost their
|
|
39
|
+
vertical rhythm. This was hand-rolled in 5 places across zygos-web and aml-v2.
|
|
40
|
+
`Field` takes `{ label, required?, error?, children, containerStyle?, testID? }` and renders the
|
|
41
|
+
same label row / required mark / error line / spacing.
|
|
42
|
+
- **`FormField` now composes `Field` internally**, so the two can never drift apart — the metrics
|
|
43
|
+
live in exactly one place. `FormFieldProps` and every rendered attribute (`form-field-input`
|
|
44
|
+
testID, `aria-invalid` / `aria-describedby` / `aria-required`, the `role="alert"` error line)
|
|
45
|
+
are unchanged: fully backward-compatible.
|
|
46
|
+
- `Field`'s `children` may be a plain node (the common case) or a render function receiving
|
|
47
|
+
`{ describedById, hasError }`, so a custom control can wire the error line into its own
|
|
48
|
+
`aria-describedby` / invalid state exactly the way `FormField` does.
|
|
49
|
+
|
|
3
50
|
## 1.4.0
|
|
4
51
|
|
|
5
52
|
- **Accessibility (WCAG 2.1 AA) hardening — additive + backward-compatible.**
|
package/README.md
CHANGED
|
@@ -1,37 +1,107 @@
|
|
|
1
|
-
# @dloizides/ui-forms
|
|
2
|
-
|
|
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
|
|
5
|
-
`@dloizides/ui-feedback` UI context (`useUi`) — mount one `UiProvider` / `FeedbackUiProvider`
|
|
6
|
-
at your app root and these components pick up your theme automatically.
|
|
7
|
-
|
|
8
|
-
## Install
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
npm install @dloizides/ui-forms @dloizides/ui-feedback
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
Peer dependencies: `@dloizides/ui-feedback >= 1.1.0`, `react >= 18`, `react-native >= 0.74`
|
|
15
|
-
(use `react-native-web` on web).
|
|
16
|
-
|
|
17
|
-
## Usage
|
|
18
|
-
|
|
19
|
-
```tsx
|
|
20
|
-
import { FormField, ChipSelector, FormSwitch } from '@dloizides/ui-forms';
|
|
21
|
-
|
|
22
|
-
<FormField label="Email" required error={errors.email} value={email} onChangeText={setEmail} />
|
|
23
|
-
<ChipSelector label="Plan" options={plans} value={plan} onChange={setPlan} />
|
|
24
|
-
<FormSwitch label="Email notifications" value={notify} onValueChange={setNotify} />
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
1
|
+
# @dloizides/ui-forms
|
|
2
|
+
|
|
3
|
+
Themable, brand-agnostic React Native (RN-web) **form** components for the dloizides.com
|
|
4
|
+
portfolio: `Field`, `FormField`, `ChipSelector`, `FormSwitch`. They read theme colours from the shared
|
|
5
|
+
`@dloizides/ui-feedback` UI context (`useUi`) — mount one `UiProvider` / `FeedbackUiProvider`
|
|
6
|
+
at your app root and these components pick up your theme automatically.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install @dloizides/ui-forms @dloizides/ui-feedback
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Peer dependencies: `@dloizides/ui-feedback >= 1.1.0`, `react >= 18`, `react-native >= 0.74`
|
|
15
|
+
(use `react-native-web` on web).
|
|
16
|
+
|
|
17
|
+
## Usage
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { FormField, ChipSelector, FormSwitch } from '@dloizides/ui-forms';
|
|
21
|
+
|
|
22
|
+
<FormField label="Email" required error={errors.email} value={email} onChangeText={setEmail} />
|
|
23
|
+
<ChipSelector label="Plan" options={plans} value={plan} onChange={setPlan} />
|
|
24
|
+
<FormSwitch label="Email notifications" value={notify} onValueChange={setNotify} />
|
|
25
|
+
```
|
|
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` **and** `ChipSelector` compose `Field` internally, so the label row can never drift
|
|
43
|
+
out of alignment between them — there is exactly one label implementation in the kit.
|
|
44
|
+
|
|
45
|
+
To wire the error line into a custom control's own `aria-describedby` / invalid state, pass a
|
|
46
|
+
**function** child — it receives `{ describedById, hasError }` (`describedById` is `undefined`
|
|
47
|
+
when there is no error):
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
<Field label="Country" error={errors.country}>
|
|
51
|
+
{({ describedById, hasError }) => (
|
|
52
|
+
<CountryPicker aria-describedby={describedById} hasError={hasError} value={country} onChange={setCountry} />
|
|
53
|
+
)}
|
|
54
|
+
</Field>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
| Prop | Type | Notes |
|
|
58
|
+
|------|------|-------|
|
|
59
|
+
| `label` | `string` | optional — an absent or empty label renders NO label row |
|
|
60
|
+
| `children` | `ReactNode \| (ctx) => ReactNode` | the control |
|
|
61
|
+
| `required` | `boolean` | renders a decorative `*` (hidden from assistive tech) |
|
|
62
|
+
| `error` | `string` | renders a `role="alert"` line, linked via the child's `describedById` |
|
|
63
|
+
| `containerStyle` | `ViewStyle` | merged over the container |
|
|
64
|
+
| `testID` | `string` | on the container |
|
|
65
|
+
|
|
66
|
+
The injected theme needs `colors.{surface,text,textSecondary,border}`, `palette.primary['500']`
|
|
67
|
+
and `semantic.error['500']` — supplied via `@dloizides/ui-feedback`'s provider. Without a provider
|
|
68
|
+
the components fall back to a neutral default theme.
|
|
69
|
+
|
|
70
|
+
## `ChipSelector`
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
<ChipSelector
|
|
74
|
+
label="Plan"
|
|
75
|
+
required
|
|
76
|
+
error={errors.plan}
|
|
77
|
+
options={plans}
|
|
78
|
+
value={plan}
|
|
79
|
+
onChange={setPlan}
|
|
80
|
+
variant="outline"
|
|
81
|
+
/>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Its label, required mark, error line and bottom spacing come from `Field`. `label` is optional:
|
|
85
|
+
with no label no label row is rendered, so it drops into a toolbar or filter bar cleanly.
|
|
86
|
+
|
|
87
|
+
| Prop | Type | Notes |
|
|
88
|
+
|------|------|-------|
|
|
89
|
+
| `label` | `string` | optional — no label means no label row |
|
|
90
|
+
| `options` | `Array<{ value, label }>` | `value` is a `string` or `number` |
|
|
91
|
+
| `value` | `T \| T[]` | array when `multiple` |
|
|
92
|
+
| `onChange` | `(value: T) => void` | fires the pressed value; the parent owns toggle logic |
|
|
93
|
+
| `multiple` | `boolean` | selection is an array |
|
|
94
|
+
| `disabled` | `boolean` | disables every chip |
|
|
95
|
+
| `variant` | `'solid' \| 'outline'` | `solid` (default) = filled pill; `outline` = tinted outline |
|
|
96
|
+
| `required` | `boolean` | renders `Field`'s decorative `*` |
|
|
97
|
+
| `error` | `string` | `role="alert"` line, tied to the chip group via `aria-describedby` |
|
|
98
|
+
| `containerStyle` | `ViewStyle` | merged over the container |
|
|
99
|
+
| `testID` | `string` | on the container |
|
|
100
|
+
|
|
101
|
+
## testIDs
|
|
102
|
+
|
|
103
|
+
`form-field-input`, `chip-selector-chip-<value>`, `form-switch` (overridable on FormSwitch).
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|
package/dist/index.d.mts
CHANGED
|
@@ -1,12 +1,55 @@
|
|
|
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
|
+
/**
|
|
29
|
+
* Label shown above the control. Optional so a control whose label is supplied elsewhere (or
|
|
30
|
+
* which genuinely has none) can still use the shared shell for its error line + spacing: an
|
|
31
|
+
* absent or empty label renders NO label row at all, rather than an empty one that would add a
|
|
32
|
+
* phantom gap and misalign the control against its labelled siblings.
|
|
33
|
+
*/
|
|
34
|
+
label?: string;
|
|
35
|
+
children: FieldChildren;
|
|
36
|
+
required?: boolean;
|
|
37
|
+
error?: string;
|
|
38
|
+
containerStyle?: ViewStyle;
|
|
39
|
+
testID?: string;
|
|
40
|
+
}
|
|
41
|
+
declare const Field: ({ label, children, required, error, containerStyle, testID, }: FieldProps) => React.ReactElement;
|
|
3
42
|
|
|
4
43
|
/**
|
|
5
44
|
* Reusable form field — labelled text input with optional required mark + error.
|
|
6
45
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
46
|
+
* The label row, the required mark, the error line and the container spacing all come from the
|
|
47
|
+
* generic `Field` wrapper, so a `FormField` and a `Field`-wrapped dropdown sitting next to each
|
|
48
|
+
* other line up exactly and can never drift apart. FormField only adds the control itself.
|
|
49
|
+
*
|
|
50
|
+
* The input is the shared `ThemedTextInput` primitive, so every FormField gets the readable +
|
|
51
|
+
* lively treatment (dark text, subtle off-white rest background, brand focus animation with a
|
|
52
|
+
* soft ring) for free, driven by the active theme.
|
|
10
53
|
*/
|
|
11
54
|
|
|
12
55
|
interface FormFieldProps extends Omit<TextInputProps, 'style'> {
|
|
@@ -80,6 +123,12 @@ declare function useThemedInput(options?: UseThemedInputOptions): ThemedInput;
|
|
|
80
123
|
* - `outline` — the AML v1 console look: an outlined pill on a muted fill; selected = a subtle
|
|
81
124
|
* tinted-outline (primary border + primary ink + a low-alpha primary wash), NOT a solid fill.
|
|
82
125
|
* Hover (web) lifts the border/ink to the primary colour.
|
|
126
|
+
*
|
|
127
|
+
* The label row, the error line and the container spacing come from the shared `Field` wrapper —
|
|
128
|
+
* NOT from a local `<Text>`. Its own label used to drift from `Field` on three of four axes
|
|
129
|
+
* (`marginBottom: 8` vs 4, no `fontSize` at all so ~14 vs 13, `colors.text` vs `textSecondary`),
|
|
130
|
+
* so a `ChipSelector` next to a `FormField` in a row/grid started a different distance down the
|
|
131
|
+
* column and read as a different weight of text. Now there is exactly one label implementation.
|
|
83
132
|
*/
|
|
84
133
|
|
|
85
134
|
/** Visual variant. `solid` = filled selected pill (default); `outline` = v1 tinted-outline. */
|
|
@@ -89,6 +138,7 @@ interface ChipOption<T> {
|
|
|
89
138
|
label: string;
|
|
90
139
|
}
|
|
91
140
|
interface ChipSelectorProps<T> {
|
|
141
|
+
/** Optional — with no label, no label row is rendered (no phantom gap above the chips). */
|
|
92
142
|
label?: string;
|
|
93
143
|
options: Array<ChipOption<T>>;
|
|
94
144
|
value: T | T[];
|
|
@@ -98,8 +148,13 @@ interface ChipSelectorProps<T> {
|
|
|
98
148
|
/** Visual variant. `solid` (default) = filled selected pill; `outline` = v1 tinted-outline. */
|
|
99
149
|
variant?: ChipVariant;
|
|
100
150
|
containerStyle?: ViewStyle;
|
|
151
|
+
/** Marks the selection mandatory — renders `Field`'s decorative `*` next to the label. */
|
|
152
|
+
required?: boolean;
|
|
153
|
+
/** Validation message under the chips, wired to the chip group via `aria-describedby`. */
|
|
154
|
+
error?: string;
|
|
155
|
+
testID?: string;
|
|
101
156
|
}
|
|
102
|
-
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, variant, containerStyle, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
157
|
+
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, variant, containerStyle, required, error, testID, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
103
158
|
|
|
104
159
|
/**
|
|
105
160
|
* Reusable form switch/toggle with an optional description.
|
|
@@ -142,4 +197,4 @@ interface FormCheckboxProps {
|
|
|
142
197
|
}
|
|
143
198
|
declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, description, disabled, containerStyle, testID, accessibilityLabel, accessibilityHint, }: FormCheckboxProps) => React.ReactElement;
|
|
144
199
|
|
|
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 };
|
|
200
|
+
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,55 @@
|
|
|
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
|
+
/**
|
|
29
|
+
* Label shown above the control. Optional so a control whose label is supplied elsewhere (or
|
|
30
|
+
* which genuinely has none) can still use the shared shell for its error line + spacing: an
|
|
31
|
+
* absent or empty label renders NO label row at all, rather than an empty one that would add a
|
|
32
|
+
* phantom gap and misalign the control against its labelled siblings.
|
|
33
|
+
*/
|
|
34
|
+
label?: string;
|
|
35
|
+
children: FieldChildren;
|
|
36
|
+
required?: boolean;
|
|
37
|
+
error?: string;
|
|
38
|
+
containerStyle?: ViewStyle;
|
|
39
|
+
testID?: string;
|
|
40
|
+
}
|
|
41
|
+
declare const Field: ({ label, children, required, error, containerStyle, testID, }: FieldProps) => React.ReactElement;
|
|
3
42
|
|
|
4
43
|
/**
|
|
5
44
|
* Reusable form field — labelled text input with optional required mark + error.
|
|
6
45
|
*
|
|
7
|
-
* The
|
|
8
|
-
*
|
|
9
|
-
*
|
|
46
|
+
* The label row, the required mark, the error line and the container spacing all come from the
|
|
47
|
+
* generic `Field` wrapper, so a `FormField` and a `Field`-wrapped dropdown sitting next to each
|
|
48
|
+
* other line up exactly and can never drift apart. FormField only adds the control itself.
|
|
49
|
+
*
|
|
50
|
+
* The input is the shared `ThemedTextInput` primitive, so every FormField gets the readable +
|
|
51
|
+
* lively treatment (dark text, subtle off-white rest background, brand focus animation with a
|
|
52
|
+
* soft ring) for free, driven by the active theme.
|
|
10
53
|
*/
|
|
11
54
|
|
|
12
55
|
interface FormFieldProps extends Omit<TextInputProps, 'style'> {
|
|
@@ -80,6 +123,12 @@ declare function useThemedInput(options?: UseThemedInputOptions): ThemedInput;
|
|
|
80
123
|
* - `outline` — the AML v1 console look: an outlined pill on a muted fill; selected = a subtle
|
|
81
124
|
* tinted-outline (primary border + primary ink + a low-alpha primary wash), NOT a solid fill.
|
|
82
125
|
* Hover (web) lifts the border/ink to the primary colour.
|
|
126
|
+
*
|
|
127
|
+
* The label row, the error line and the container spacing come from the shared `Field` wrapper —
|
|
128
|
+
* NOT from a local `<Text>`. Its own label used to drift from `Field` on three of four axes
|
|
129
|
+
* (`marginBottom: 8` vs 4, no `fontSize` at all so ~14 vs 13, `colors.text` vs `textSecondary`),
|
|
130
|
+
* so a `ChipSelector` next to a `FormField` in a row/grid started a different distance down the
|
|
131
|
+
* column and read as a different weight of text. Now there is exactly one label implementation.
|
|
83
132
|
*/
|
|
84
133
|
|
|
85
134
|
/** Visual variant. `solid` = filled selected pill (default); `outline` = v1 tinted-outline. */
|
|
@@ -89,6 +138,7 @@ interface ChipOption<T> {
|
|
|
89
138
|
label: string;
|
|
90
139
|
}
|
|
91
140
|
interface ChipSelectorProps<T> {
|
|
141
|
+
/** Optional — with no label, no label row is rendered (no phantom gap above the chips). */
|
|
92
142
|
label?: string;
|
|
93
143
|
options: Array<ChipOption<T>>;
|
|
94
144
|
value: T | T[];
|
|
@@ -98,8 +148,13 @@ interface ChipSelectorProps<T> {
|
|
|
98
148
|
/** Visual variant. `solid` (default) = filled selected pill; `outline` = v1 tinted-outline. */
|
|
99
149
|
variant?: ChipVariant;
|
|
100
150
|
containerStyle?: ViewStyle;
|
|
151
|
+
/** Marks the selection mandatory — renders `Field`'s decorative `*` next to the label. */
|
|
152
|
+
required?: boolean;
|
|
153
|
+
/** Validation message under the chips, wired to the chip group via `aria-describedby`. */
|
|
154
|
+
error?: string;
|
|
155
|
+
testID?: string;
|
|
101
156
|
}
|
|
102
|
-
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, variant, containerStyle, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
157
|
+
declare const ChipSelector: <T extends string | number>({ label, options, value, onChange, multiple, disabled, variant, containerStyle, required, error, testID, }: ChipSelectorProps<T>) => React.ReactElement;
|
|
103
158
|
|
|
104
159
|
/**
|
|
105
160
|
* Reusable form switch/toggle with an optional description.
|
|
@@ -142,4 +197,4 @@ interface FormCheckboxProps {
|
|
|
142
197
|
}
|
|
143
198
|
declare const FormCheckbox: ({ label, value, onValueChange, onChange, hint, description, disabled, containerStyle, testID, accessibilityLabel, accessibilityHint, }: FormCheckboxProps) => React.ReactElement;
|
|
144
199
|
|
|
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 };
|
|
200
|
+
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 };
|