react-luna-form 0.0.91 → 0.0.93
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/cjs/index.js +1 -1
- package/dist/client/esm/index.js +1 -1
- package/dist/config/cjs/index.js +1 -1
- package/dist/config/esm/index.js +1 -1
- package/dist/schema/cjs/index.js +1 -1
- package/dist/schema/esm/index.js +1 -1
- package/dist/server/cjs/index.js +1 -1
- package/dist/server/esm/index.js +1 -1
- package/dist/types/luna-core/util/attributes.d.ts +1 -0
- package/dist/types/luna-core/util/constant.d.ts +2 -0
- package/dist/types/luna-core/util/schema.d.ts +1 -1
- package/dist/types/luna-core/util/string.d.ts +7 -0
- package/dist/types/luna-core/util/translate.d.ts +1 -1
- package/dist/types/luna-react/src/client/component/field/field-list-preview-item.d.ts +18 -5
- package/dist/types/luna-react/src/client/hook/use-field-list.d.ts +1 -1
- package/dist/types/luna-react/src/component/field/field-list.d.ts +1 -1
- package/dist/types/luna-react/src/component/slot/slot-base.d.ts +4 -2
- package/docs/events/change.md +5 -0
- package/docs/fields/custom-inputs.md +31 -1
- package/docs/fields/list.md +4 -0
- package/package.json +2 -2
|
@@ -46,7 +46,7 @@ Props are applied in this order:
|
|
|
46
46
|
<Component
|
|
47
47
|
{...dataAttributes} // advanced.data, as data-* attributes
|
|
48
48
|
{...commonProps} // id, name, placeholder, disabled, required, and what the field family adds
|
|
49
|
-
{...ariaAttributes} // advanced.aria,
|
|
49
|
+
{...ariaAttributes} // advanced.aria, aria-labelledby, aria-invalid, aria-errormessage
|
|
50
50
|
{...inputProps} // the prepared value or defaultValue
|
|
51
51
|
onBlur={onBlur}
|
|
52
52
|
onChange={onChange}
|
|
@@ -98,6 +98,34 @@ function PeoplePicker({ id, ...props }: React.ComponentProps<'input'>) {
|
|
|
98
98
|
The same applies when you build on a component library: whatever primitive
|
|
99
99
|
renders the focusable element is where the `id` belongs.
|
|
100
100
|
|
|
101
|
+
## A group of controls takes its name from `aria-labelledby`
|
|
102
|
+
|
|
103
|
+
A `<label for>` names only an element a label can name: an `input`, a `select`,
|
|
104
|
+
a `textarea`, a `button`. A component drawn as several controls, such as a row
|
|
105
|
+
of chips, has no one element the label belongs to, and putting the `id` on one
|
|
106
|
+
of its buttons would rename that button after the field.
|
|
107
|
+
|
|
108
|
+
So a field that renders a label also hands its component `aria-labelledby`,
|
|
109
|
+
pointing at that label, whose `id` is the field's `name` followed by `-label`.
|
|
110
|
+
Put it, with the `id`, on the element that holds the controls, and give that
|
|
111
|
+
element a role that can carry a name:
|
|
112
|
+
|
|
113
|
+
```tsx
|
|
114
|
+
function Chips({ id, 'aria-labelledby': labelledBy, ...props }: ChipsProps) {
|
|
115
|
+
return (
|
|
116
|
+
<div aria-labelledby={labelledBy} id={id} role="group">
|
|
117
|
+
{/* one button per option */}
|
|
118
|
+
</div>
|
|
119
|
+
)
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
A component that forwards its props to a single input gets it for free, and the
|
|
124
|
+
input is named exactly as its `for` already named it. A field without a `label`
|
|
125
|
+
or a `name` renders no label, and gets no `aria-labelledby`. An `aria.label` or
|
|
126
|
+
`aria.labelledby` in `advanced` is the author's name for the field, and the form
|
|
127
|
+
then sends that instead.
|
|
128
|
+
|
|
101
129
|
## Clearing a value on a select-family type
|
|
102
130
|
|
|
103
131
|
If you register a custom input under a `select` variant, be aware that an
|
|
@@ -274,6 +302,8 @@ Before shipping a custom input:
|
|
|
274
302
|
|
|
275
303
|
- Its `type` string matches `defineCustomInput` exactly, character for character
|
|
276
304
|
- The `id` it receives reaches the focusable element
|
|
305
|
+
- If it renders several controls, the `aria-labelledby` it receives reaches
|
|
306
|
+
the element that holds them, which has a role such as `group`
|
|
277
307
|
- It forwards or calls the `onChange` and `onBlur` it receives
|
|
278
308
|
- If it is a select variant, it does not rely on `''` to clear
|
|
279
309
|
- If it renders `input/date`, it reads and emits `yyyy-MM-dd`, or `[from, to]`
|
package/docs/fields/list.md
CHANGED
|
@@ -20,6 +20,7 @@ The `advanced` property customizes structural interaction rules and layout rende
|
|
|
20
20
|
|
|
21
21
|
- **`title`** _(string)_: Names one item of the collection. The header of the second row then reads `Contact 2` and its controls announce `Collapse Contact 2` and `Remove Contact 2`.
|
|
22
22
|
It falls back to the list's `label`, and then to its `name`, so a list called `contacts` with neither captions its rows `contacts 1`. A [`preview.label`](#collapsed-previews-preview-object) replaces the caption where it resolves; this stays the fallback for the rows where it does not.
|
|
23
|
+
A row with a `preview.label` is also named after it, so its controls announce `Collapse Ana (Contact 2)` and `Remove Ana (Contact item 2)`: the name holds the text the row shows, and two rows in different lists that share a title stay apart. The name follows the label as the user edits it. A row whose label comes out empty shows the caption instead, and its name repeats it: `Collapse Contact 2 (Contact 2)`.
|
|
23
24
|
Like `action`, it is copy the form declares, so it is translated through the dictionary — see [Localization](#localization).
|
|
24
25
|
- **`action`** _(string)_: A custom label applied strictly to the generic "Add item" button rendering at the end of the collection (e.g. `"Add email address"`).
|
|
25
26
|
A custom label has to be translated by the form; the built-in `Add item` default is already translated by the library — see [Localization](#localization).
|
|
@@ -116,6 +117,7 @@ Every piece of copy a list renders goes through the `translations` dictionary, k
|
|
|
116
117
|
|
|
117
118
|
- `Add item`, the add-button label when no `action` is declared.
|
|
118
119
|
- `Expand {label} {index}`, `Collapse {label} {index}` and `Remove {label} item {index}`, the accessible names of the item controls.
|
|
120
|
+
- `Expand {name} ({label} {index})`, `Collapse {name} ({label} {index})` and `Remove {name} ({label} item {index})`, the same names for a row that has a [`preview.label`](#collapsed-previews-preview-object); `{name}` is the text that label shows.
|
|
119
121
|
|
|
120
122
|
```json
|
|
121
123
|
{
|
|
@@ -176,6 +178,8 @@ The accessible names are single keys carrying `{label}` and `{index}` placeholde
|
|
|
176
178
|
|
|
177
179
|
Left untranslated, the template fills in to the same English text it replaced.
|
|
178
180
|
|
|
181
|
+
`{name}` may sit anywhere in a translation, the same as the other placeholders. A translation of a `{name}` key that leaves `{name}` out is not used: the row is named with the matching key without it, `Expand {label} {index}` and so on, translated as that key is.
|
|
182
|
+
|
|
179
183
|
---
|
|
180
184
|
|
|
181
185
|
## Complete Example Reference
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-luna-form",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.93",
|
|
4
4
|
"description": "A React library for building forms based on JSON",
|
|
5
5
|
"main": "./dist/client/cjs/index.js",
|
|
6
6
|
"module": "./dist/client/esm/index.js",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"zod": "^4.0.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"@luna-form/core": "0.0.
|
|
32
|
+
"@luna-form/core": "0.0.93",
|
|
33
33
|
"@types/react": "19.3.0",
|
|
34
34
|
"@types/react-dom": "19.3.0",
|
|
35
35
|
"eslint-plugin-react": "7.37.5",
|