@uniflowed/ui 0.0.0-alpha.14 → 0.0.0-alpha.15
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/combobox.js +4 -4
- package/index.js +46 -0
- package/package.json +4 -4
- package/select.js +19 -1
package/combobox.js
CHANGED
|
@@ -618,10 +618,10 @@ export component ComboboxOption(
|
|
|
618
618
|
* a boundary they cannot see, and the heading is never a place the cursor can
|
|
619
619
|
* land, because it is not an option.
|
|
620
620
|
*
|
|
621
|
-
* `children` is
|
|
622
|
-
*
|
|
623
|
-
*
|
|
624
|
-
*
|
|
621
|
+
* `children` is the true statement rather than a `React.Node` that would take
|
|
622
|
+
* anything: a `group` inside a `listbox` may own options and its own heading,
|
|
623
|
+
* and nothing else. `Select.Group` says the same since ubugeeei-prod/uf#562 —
|
|
624
|
+
* it is the same listbox, and it took a second breaking change to get there.
|
|
625
625
|
*/
|
|
626
626
|
export component ComboboxGroup(
|
|
627
627
|
children: renders* (ComboboxOption | ComboboxGroupLabel),
|
package/index.js
CHANGED
|
@@ -39,6 +39,52 @@
|
|
|
39
39
|
// the same components with exactly the same behaviour; the design-system layer
|
|
40
40
|
// that adds uf's default styles is built *on* these, not into them.
|
|
41
41
|
//
|
|
42
|
+
// # What is not here, and where it went instead
|
|
43
|
+
//
|
|
44
|
+
// About twenty of the catalogue this package is measured against have no
|
|
45
|
+
// behaviour at all. Badge, Card, Button, Input, Textarea, Label and Aspect
|
|
46
|
+
// Ratio are, between them, a class list and a `<div>`. For a library whose
|
|
47
|
+
// product *is* the styles that is coherent — you copy them in and you own
|
|
48
|
+
// them. It is not coherent here: a `Badge` with no styles is a `<span>`, a
|
|
49
|
+
// `Card` with no styles is a `<div>`, and shipping them from a package that
|
|
50
|
+
// ships no styles would make this a library of empty elements. Shipping them
|
|
51
|
+
// from `@uniflowed/stylex` would make *that* a component library, which its
|
|
52
|
+
// own header forbids. So for a long time the answer on record was both and
|
|
53
|
+
// neither, which is ubugeeei-prod/uf#298.
|
|
54
|
+
//
|
|
55
|
+
// The line that holds is not "styled versus headless". It is **whether the
|
|
56
|
+
// thing has a decision in it**:
|
|
57
|
+
//
|
|
58
|
+
// - An ARIA decision, a state machine or a keyboard requirement makes it a
|
|
59
|
+
// component here, even when it renders a single element. `Progress` is one
|
|
60
|
+
// `<div>`, and it belongs, because the conditional that omits
|
|
61
|
+
// `aria-valuenow` when the amount is unknown — rather than sending
|
|
62
|
+
// `aria-valuenow={0}`, which says "nothing has happened" — is the whole
|
|
63
|
+
// component. `Toggle` and `Checkbox` are the same shape for the same reason.
|
|
64
|
+
// - Anything that is only a class list belongs in `@uniflowed/stylex/preset`,
|
|
65
|
+
// which already has the right form: `buttonStyles({ tone, size })`,
|
|
66
|
+
// `cardStyles()`, `textStyles({ size, tone })` and `fieldStyles()` return
|
|
67
|
+
// `{ className }` for a caller to spread onto their own element. That is a
|
|
68
|
+
// better answer than a `<Badge>`, not a lesser one — a component wrapping a
|
|
69
|
+
// `<button>` takes away `type="submit"`, `formAction`, the ref and every
|
|
70
|
+
// attribute nobody thought to forward, and gives back a class name the
|
|
71
|
+
// caller could have written.
|
|
72
|
+
//
|
|
73
|
+
// This is stated rather than left as an omission, because an omission reads as
|
|
74
|
+
// an oversight and the next contributor closes it with a `<Badge>`.
|
|
75
|
+
// `crates/uf_lib/src/ui.rs` carries the same decision as data: those entries
|
|
76
|
+
// are `Declined` with the preset functions that replace them named on each,
|
|
77
|
+
// and `cargo test -p uf_lib` fails if a name there stops existing.
|
|
78
|
+
//
|
|
79
|
+
// Five of that twenty are not presentational and are missing rather than
|
|
80
|
+
// declined — Alert, Avatar, Breadcrumb, Separator and Skeleton — each for one
|
|
81
|
+
// specific reason, and the registry entry for each says which. The shortest is
|
|
82
|
+
// Alert: `role="alert"` is a live region, an element already in the document
|
|
83
|
+
// when the page loads announces on insertion or not at all, and a permanently
|
|
84
|
+
// rendered "your trial ends soon" box carrying that role is either an
|
|
85
|
+
// interruption on every page load or silence. `field.js` already makes that
|
|
86
|
+
// call correctly for `Field.Error`.
|
|
87
|
+
//
|
|
42
88
|
// # What these components promise React
|
|
43
89
|
//
|
|
44
90
|
// Nothing here mutates during a render, reads a ref during a render, or depends
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniflowed/ui",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.15",
|
|
4
4
|
"description": "Headless, accessible React components whose composition Flow checks, part of the Unified Toolchain for Flow.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
"internal"
|
|
53
53
|
],
|
|
54
54
|
"dependencies": {
|
|
55
|
-
"@uniflowed/core": "0.0.0-alpha.
|
|
56
|
-
"@uniflowed/hooks": "0.0.0-alpha.
|
|
57
|
-
"@uniflowed/react": "0.0.0-alpha.
|
|
55
|
+
"@uniflowed/core": "0.0.0-alpha.15",
|
|
56
|
+
"@uniflowed/hooks": "0.0.0-alpha.15",
|
|
57
|
+
"@uniflowed/react": "0.0.0-alpha.15"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
60
|
"react": ">=19"
|
package/select.js
CHANGED
|
@@ -822,8 +822,26 @@ export component SelectOption(
|
|
|
822
822
|
* `Select.GroupLabel` is rendered — the same rule, and the same reason, as
|
|
823
823
|
* `Menu.Group`. The arrow keys pass over the label without stopping on it,
|
|
824
824
|
* because they only ever look for `role="option"`.
|
|
825
|
+
*
|
|
826
|
+
* `children` is `renders* (SelectOption | SelectGroupLabel)`, which is what a
|
|
827
|
+
* `group` inside a `listbox` may hold: options, and the heading that names
|
|
828
|
+
* them. It took `React.Node` until ubugeeei-prod/uf#562, so a `<div>` in a
|
|
829
|
+
* group was a runtime surprise — an element with no role between two options,
|
|
830
|
+
* which the arrow keys walk straight past and a screen reader reads as a stray
|
|
831
|
+
* line — rather than a type error. `Combobox.Group` has stated the constraint
|
|
832
|
+
* since #558 and this is the same listbox.
|
|
833
|
+
*
|
|
834
|
+
* No `Select.Separator`, and that is deliberate rather than an omission: a rule
|
|
835
|
+
* separates *groups*, so it belongs between them in `Select.List` — which does
|
|
836
|
+
* admit one. A separator inside a group is a rule with nothing on one side of
|
|
837
|
+
* it.
|
|
838
|
+
*
|
|
839
|
+
* **Breaking.** A caller passing anything else — a `<div>` wrapper, a fragment
|
|
840
|
+
* of their own, a component that returns options — now fails `uf check`. The
|
|
841
|
+
* fix is to hand the options to the group directly; a wrapper had no effect on
|
|
842
|
+
* what this renders, because the group's element is the one below.
|
|
825
843
|
*/
|
|
826
|
-
export component SelectGroup(children:
|
|
844
|
+
export component SelectGroup(children: renders* (SelectOption | SelectGroupLabel), ...rest: Rest) {
|
|
827
845
|
const base = useId();
|
|
828
846
|
const [labelled, setLabelled] = useState(false);
|
|
829
847
|
|