@agentero/design-system 0.31.5 → 0.31.7
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/mcp/manifests/components.html +65 -9
- package/mcp/manifests/components.json +14 -8
- package/package.json +1 -1
- package/src/combobox/combobox.d.ts +36 -8
- package/src/combobox/combobox.js +83 -49
- package/src/combobox/icons.d.ts +8 -0
- package/src/combobox/icons.js +11 -1
- package/src/combobox/index.d.ts +2 -2
- package/src/field/context.d.ts +7 -0
- package/src/field/field.d.ts +3 -1
- package/src/field/field.js +8 -6
- package/src/field-text/field-text.js +9 -9
- package/src/form-text/form-text.js +7 -7
|
@@ -588,13 +588,13 @@
|
|
|
588
588
|
<header>
|
|
589
589
|
<div class="wrap">
|
|
590
590
|
<h1>Manifest Debugger</h1>
|
|
591
|
-
<div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">33 components ok</span><span class="filter-pill ok" aria-disabled="true">
|
|
591
|
+
<div class="summary"><a class="filter-pill all" data-k="all" href="#filter-all">All</a><span class="filter-pill ok" aria-disabled="true">33 components ok</span><span class="filter-pill ok" aria-disabled="true">266 stories ok</span></div>
|
|
592
592
|
</div>
|
|
593
593
|
</header>
|
|
594
594
|
<main>
|
|
595
595
|
<div class="wrap">
|
|
596
596
|
<div class="note ok" style="margin-bottom: 16px;">
|
|
597
|
-
Using <code>react-component-meta</code>. Generation took <strong>
|
|
597
|
+
Using <code>react-component-meta</code>. Generation took <strong>3.7s</strong>.
|
|
598
598
|
</div>
|
|
599
599
|
<h2 class="section-title">Components</h2>
|
|
600
600
|
<div class="grid" role="list">
|
|
@@ -2857,7 +2857,7 @@ import { CheckList } from '@agentero/design-system/check-list';
|
|
|
2857
2857
|
<div class="badges">
|
|
2858
2858
|
<label for="c-7-components-combobox-props" class="badge ok as-toggle">38 prop types</label>
|
|
2859
2859
|
|
|
2860
|
-
<label for="c-7-components-combobox-stories" class="badge ok as-toggle">
|
|
2860
|
+
<label for="c-7-components-combobox-stories" class="badge ok as-toggle">8 stories</label>
|
|
2861
2861
|
|
|
2862
2862
|
|
|
2863
2863
|
</div>
|
|
@@ -2866,8 +2866,9 @@ import { CheckList } from '@agentero/design-system/check-list';
|
|
|
2866
2866
|
<div>Root provider for an input-triggered filterable list</div>
|
|
2867
2867
|
<div class="hint">Combobox is a text input that filters a list and writes the chosen option back
|
|
2868
2868
|
into itself. Focusing the input or typing opens the list; picking a row fills the
|
|
2869
|
-
input and closes it.
|
|
2870
|
-
|
|
2869
|
+
input and closes it. With `multiple` the rows become checkbox-like toggles and the
|
|
2870
|
+
list stays open between picks. Built on Base UI, whose Combobox primitive owns
|
|
2871
|
+
the filtering, the keyboard navigation and the `role="combobox"` wiring.</div>
|
|
2871
2872
|
<div class="kv"><span class="chip">summary: Root provider for an input-triggered filterable list</span><span class="chip">see: {@link https://base-ui.com/react/components/combobox Base UI Combobox}</span><span class="chip">example: ```tsx
|
|
2872
2873
|
import { Combobox } from '@agentero/design-system/combobox';
|
|
2873
2874
|
|
|
@@ -3148,7 +3149,17 @@ virtualized?: boolean = false</code></pre>
|
|
|
3148
3149
|
<div class="row">
|
|
3149
3150
|
<span class="ex-name">Imports</span>
|
|
3150
3151
|
</div>
|
|
3151
|
-
<pre><code>import {
|
|
3152
|
+
<pre><code>import {
|
|
3153
|
+
Button,
|
|
3154
|
+
Combobox,
|
|
3155
|
+
Field,
|
|
3156
|
+
FieldText,
|
|
3157
|
+
IconSearch,
|
|
3158
|
+
Label,
|
|
3159
|
+
Modal,
|
|
3160
|
+
Skeleton,
|
|
3161
|
+
Tag,
|
|
3162
|
+
} from "@agentero/design-system";
|
|
3152
3163
|
import { Suspense } from "react";</code></pre>
|
|
3153
3164
|
</div>
|
|
3154
3165
|
|
|
@@ -3200,6 +3211,48 @@ children only while nothing matches. It needs `items` on `Root` to know that.</d
|
|
|
3200
3211
|
</Combobox.Content>
|
|
3201
3212
|
</Combobox.Root>
|
|
3202
3213
|
);</code></pre>
|
|
3214
|
+
</div>
|
|
3215
|
+
<div class="note ok">
|
|
3216
|
+
<div class="row">
|
|
3217
|
+
<span class="ex-name">Multiple Selection</span>
|
|
3218
|
+
<span class="badge ok">story ok</span>
|
|
3219
|
+
</div>
|
|
3220
|
+
|
|
3221
|
+
<div class="hint">Several values from one list, the way Lines of Authority or locations are
|
|
3222
|
+
assigned: each row leads with a checkbox-shaped indicator, picking a row toggles
|
|
3223
|
+
it, and the list stays open with the query intact so the next pick is one click
|
|
3224
|
+
away. The input never shows the selection; the field renders it alongside,
|
|
3225
|
+
here as tags.</div>
|
|
3226
|
+
<pre><code>const MultipleSelection = () => {
|
|
3227
|
+
const [selected, setSelected] = useState<string[]>([]);
|
|
3228
|
+
|
|
3229
|
+
return (
|
|
3230
|
+
<div className="flex flex-col gap-4">
|
|
3231
|
+
<Combobox.Root items={STATES} multiple value={selected} onValueChange={setSelected}>
|
|
3232
|
+
<Combobox.Input placeholder="Assign states" aria-label="Assign states" />
|
|
3233
|
+
<Combobox.Content>
|
|
3234
|
+
<Combobox.Empty>No matches found</Combobox.Empty>
|
|
3235
|
+
<Combobox.List aria-label="States">
|
|
3236
|
+
{(state: string) => (
|
|
3237
|
+
<Combobox.Item key={state} value={state}>
|
|
3238
|
+
{state}
|
|
3239
|
+
</Combobox.Item>
|
|
3240
|
+
)}
|
|
3241
|
+
</Combobox.List>
|
|
3242
|
+
</Combobox.Content>
|
|
3243
|
+
</Combobox.Root>
|
|
3244
|
+
{selected.length > 0 && (
|
|
3245
|
+
<ul aria-label="Selected states" className="flex flex-wrap gap-2">
|
|
3246
|
+
{selected.map(state => (
|
|
3247
|
+
<li key={state}>
|
|
3248
|
+
<Tag size="sm">{state}</Tag>
|
|
3249
|
+
</li>
|
|
3250
|
+
))}
|
|
3251
|
+
</ul>
|
|
3252
|
+
)}
|
|
3253
|
+
</div>
|
|
3254
|
+
);
|
|
3255
|
+
};</code></pre>
|
|
3203
3256
|
</div>
|
|
3204
3257
|
<div class="note ok">
|
|
3205
3258
|
<div class="row">
|
|
@@ -3303,7 +3356,10 @@ before each request and a request that is no longer the latest is dropped.</div>
|
|
|
3303
3356
|
|
|
3304
3357
|
<div class="hint">Dropped into a `FieldText`, the input takes the label, the description and
|
|
3305
3358
|
the error from the field with nothing wired by hand: `Combobox.Input` reads the
|
|
3306
|
-
same `InputContext` the plain `Input` does
|
|
3359
|
+
same `InputContext` the plain `Input` does. It also points `aria-labelledby`
|
|
3360
|
+
at the label, so the name survives the list opening: Base UI then hides the
|
|
3361
|
+
rest of the page from assistive technology, label included, and a
|
|
3362
|
+
`<label for>` alone would stop naming the input.</div>
|
|
3307
3363
|
<pre><code>const InsideFieldText = () => (
|
|
3308
3364
|
<FieldText invalid required>
|
|
3309
3365
|
<Label>Agency</Label>
|
|
@@ -5207,7 +5263,7 @@ required?: boolean = false</code></pre>
|
|
|
5207
5263
|
<div class="row">
|
|
5208
5264
|
<span class="ex-name">Imports</span>
|
|
5209
5265
|
</div>
|
|
5210
|
-
<pre><code>import { Field, FieldContext, Label } from "@agentero/design-system";</code></pre>
|
|
5266
|
+
<pre><code>import { Field, FieldContext, Label, Switch } from "@agentero/design-system";</code></pre>
|
|
5211
5267
|
</div>
|
|
5212
5268
|
|
|
5213
5269
|
|
|
@@ -5454,7 +5510,7 @@ gets one here.</div>
|
|
|
5454
5510
|
<Label>Auto-renew</Label>
|
|
5455
5511
|
<Field.Description>Renews the policy automatically before it expires.</Field.Description>
|
|
5456
5512
|
</Field.Content>
|
|
5457
|
-
<
|
|
5513
|
+
<DemoSwitch className="self-center" />
|
|
5458
5514
|
</Field.Root>
|
|
5459
5515
|
|
|
5460
5516
|
<div className="w-[20rem]" data-testid="narrow">
|
|
@@ -2001,13 +2001,13 @@
|
|
|
2001
2001
|
"```tsx\nimport { Combobox } from '@agentero/design-system/combobox';\n\n<Combobox.Root items={states}>\n <Combobox.Input placeholder=\"Search states\" />\n <Combobox.Content>\n <Combobox.Empty>No matches found</Combobox.Empty>\n <Combobox.List>\n {(state: string) => <Combobox.Item key={state} value={state}>{state}</Combobox.Item>}\n </Combobox.List>\n </Combobox.Content>\n</Combobox.Root>\n```"
|
|
2002
2002
|
]
|
|
2003
2003
|
},
|
|
2004
|
-
"description": "Combobox is a text input that filters a list and writes the chosen option back\ninto itself. Focusing the input or typing opens the list; picking a row fills the\ninput and closes it. Built on Base UI, whose Combobox primitive owns
|
|
2004
|
+
"description": "Combobox is a text input that filters a list and writes the chosen option back\ninto itself. Focusing the input or typing opens the list; picking a row fills the\ninput and closes it. With `multiple` the rows become checkbox-like toggles and the\nlist stays open between picks. Built on Base UI, whose Combobox primitive owns\nthe filtering, the keyboard navigation and the `role=\"combobox\"` wiring.",
|
|
2005
2005
|
"summary": "Root provider for an input-triggered filterable list",
|
|
2006
2006
|
"reactComponentMeta": {
|
|
2007
2007
|
"displayName": "Combobox.Root",
|
|
2008
2008
|
"exportName": "Combobox",
|
|
2009
2009
|
"filePath": "/home/runner/work/design-system/design-system/src/combobox/index.ts",
|
|
2010
|
-
"description": "Root of a combobox: a text input that filters a list of options and writes the\nchosen one back into itself. With `Input` as the only trigger, the list opens on\nfocus or on the first keystroke.\n\nPass the options as `items`. For a list that comes from the server, set\n`filter={null}`, hand the already-filtered rows to `filteredItems`, and request\nthem from `onInputValueChange`; `Status` then announces the wait.",
|
|
2010
|
+
"description": "Root of a combobox: a text input that filters a list of options and writes the\nchosen one back into itself. With `Input` as the only trigger, the list opens on\nfocus or on the first keystroke.\n\nPass the options as `items`. For a list that comes from the server, set\n`filter={null}`, hand the already-filtered rows to `filteredItems`, and request\nthem from `onInputValueChange`; `Status` then announces the wait.\n\nWith `multiple`, the value is an array and picking a row toggles it. The list\nstays open and keeps the typed query between picks, so several rows can be\nticked from one search; closing the list (Escape, a click outside) still resets\nthe query. Each row then shows whether it is selected — see `Item`. Nothing is\nwritten back into the input: render the selection next to the field.",
|
|
2011
2011
|
"jsDocTags": {
|
|
2012
2012
|
"summary": [
|
|
2013
2013
|
"Root provider for an input-triggered filterable list"
|
|
@@ -2785,6 +2785,12 @@
|
|
|
2785
2785
|
"snippet": "const NoMatches = () => (\n <Combobox.Root items={STATES}>\n <Combobox.Input placeholder=\"Search states\" aria-label=\"Search states\" />\n <Combobox.Content>\n <Combobox.Empty>No matches found</Combobox.Empty>\n <Combobox.List>\n {(state: string) => (\n <Combobox.Item key={state} value={state}>\n {state}\n </Combobox.Item>\n )}\n </Combobox.List>\n </Combobox.Content>\n </Combobox.Root>\n);",
|
|
2786
2786
|
"description": "`Empty` stays mounted so screen readers announce the change; it renders its\nchildren only while nothing matches. It needs `items` on `Root` to know that."
|
|
2787
2787
|
},
|
|
2788
|
+
{
|
|
2789
|
+
"id": "components-combobox--multiple-selection",
|
|
2790
|
+
"name": "Multiple Selection",
|
|
2791
|
+
"snippet": "const MultipleSelection = () => {\n const [selected, setSelected] = useState<string[]>([]);\n\n return (\n <div className=\"flex flex-col gap-4\">\n <Combobox.Root items={STATES} multiple value={selected} onValueChange={setSelected}>\n <Combobox.Input placeholder=\"Assign states\" aria-label=\"Assign states\" />\n <Combobox.Content>\n <Combobox.Empty>No matches found</Combobox.Empty>\n <Combobox.List aria-label=\"States\">\n {(state: string) => (\n <Combobox.Item key={state} value={state}>\n {state}\n </Combobox.Item>\n )}\n </Combobox.List>\n </Combobox.Content>\n </Combobox.Root>\n {selected.length > 0 && (\n <ul aria-label=\"Selected states\" className=\"flex flex-wrap gap-2\">\n {selected.map(state => (\n <li key={state}>\n <Tag size=\"sm\">{state}</Tag>\n </li>\n ))}\n </ul>\n )}\n </div>\n );\n};",
|
|
2792
|
+
"description": "Several values from one list, the way Lines of Authority or locations are\nassigned: each row leads with a checkbox-shaped indicator, picking a row toggles\nit, and the list stays open with the query intact so the next pick is one click\naway. The input never shows the selection; the field renders it alongside,\nhere as tags."
|
|
2793
|
+
},
|
|
2788
2794
|
{
|
|
2789
2795
|
"id": "components-combobox--async-search",
|
|
2790
2796
|
"name": "Async Search",
|
|
@@ -2801,7 +2807,7 @@
|
|
|
2801
2807
|
"id": "components-combobox--inside-field-text",
|
|
2802
2808
|
"name": "Inside Field Text",
|
|
2803
2809
|
"snippet": "const InsideFieldText = () => (\n <FieldText invalid required>\n <Label>Agency</Label>\n <Combobox.Root items={STATES}>\n <Combobox.Input placeholder=\"Search agencies\" />\n <Combobox.Content>\n <Combobox.Empty>No matches found</Combobox.Empty>\n <Combobox.List>\n {(state: string) => (\n <Combobox.Item key={state} value={state}>\n {state}\n </Combobox.Item>\n )}\n </Combobox.List>\n </Combobox.Content>\n </Combobox.Root>\n <Field.Description>The agency this agent will be added to.</Field.Description>\n <Field.Error errors={[{ message: 'Pick an agency from the list' }]} />\n </FieldText>\n);",
|
|
2804
|
-
"description": "Dropped into a `FieldText`, the input takes the label, the description and\nthe error from the field with nothing wired by hand: `Combobox.Input` reads the\nsame `InputContext` the plain `Input` does."
|
|
2810
|
+
"description": "Dropped into a `FieldText`, the input takes the label, the description and\nthe error from the field with nothing wired by hand: `Combobox.Input` reads the\nsame `InputContext` the plain `Input` does. It also points `aria-labelledby`\nat the label, so the name survives the list opening: Base UI then hides the\nrest of the page from assistive technology, label included, and a\n`<label for>` alone would stop naming the input."
|
|
2805
2811
|
},
|
|
2806
2812
|
{
|
|
2807
2813
|
"id": "components-combobox--with-leading-icon",
|
|
@@ -2816,7 +2822,7 @@
|
|
|
2816
2822
|
"description": "Inside a `Modal`, which is a Radix Dialog. The surface portals to the body, so\nthis checks that the dialog's modal layer neither blocks pointer events on the\nlist nor treats a click in it as a click outside and closes."
|
|
2817
2823
|
}
|
|
2818
2824
|
],
|
|
2819
|
-
"import": "import {
|
|
2825
|
+
"import": "import {\n Button,\n Combobox,\n Field,\n FieldText,\n IconSearch,\n Label,\n Modal,\n Skeleton,\n Tag,\n} from \"@agentero/design-system\";\nimport { Suspense } from \"react\";"
|
|
2820
2826
|
},
|
|
2821
2827
|
"components-command": {
|
|
2822
2828
|
"id": "components-command",
|
|
@@ -5469,7 +5475,7 @@
|
|
|
5469
5475
|
"displayName": "Field.Root",
|
|
5470
5476
|
"exportName": "Field",
|
|
5471
5477
|
"filePath": "/home/runner/work/design-system/design-system/src/field/index.ts",
|
|
5472
|
-
"description": "Wraps one label, control, description and error into a single field and\nwires the accessibility relationships between them. It generates the ids\nand shares them through context: `Label` reads `LabelContext`,\n`Field.Description` and `Field.Error` read `FieldContext` and register\nthemselves so the control's `aria-describedby` lists exactly the messages on\nscreen, and a `Field<X>` such as `FieldText` provides the control's context so\nthe control associates itself too. Nobody passes an `id` by hand.\n\nPresentational and form-library agnostic: pass `invalid` and the error\nmessages from whatever validates the form. Deliberately not a `role=\"group\"`:\none field is not a set of related controls, and an unnamed group only adds\nscreen-reader verbosity. Real groupings belong to a fieldset with a legend.",
|
|
5478
|
+
"description": "Wraps one label, control, description and error into a single field and\nwires the accessibility relationships between them. It generates the ids\nand shares them through context: `Label` reads `LabelContext`,\n`Field.Description` and `Field.Error` read `FieldContext` and register\nthemselves so the control's `aria-describedby` lists exactly the messages on\nscreen, and a `Field<X>` such as `FieldText` provides the control's context so\nthe control associates itself too. Nobody passes an `id` by hand. The label\ngets an id as well (`labelId` in `FieldContext`) for a control that must\nname itself with `aria-labelledby`, as `Combobox.Input` does.\n\nPresentational and form-library agnostic: pass `invalid` and the error\nmessages from whatever validates the form. Deliberately not a `role=\"group\"`:\none field is not a set of related controls, and an unnamed group only adds\nscreen-reader verbosity. Real groupings belong to a fieldset with a legend.",
|
|
5473
5479
|
"jsDocTags": {
|
|
5474
5480
|
"summary": [
|
|
5475
5481
|
"Wraps a label, control, description and error into one field"
|
|
@@ -5691,7 +5697,7 @@
|
|
|
5691
5697
|
{
|
|
5692
5698
|
"id": "components-field--horizontal",
|
|
5693
5699
|
"name": "Horizontal",
|
|
5694
|
-
"snippet": "const Horizontal = () => (\n <Field.Group className=\"w-160\">\n <Field.Root orientation=\"horizontal\" data-testid=\"short\">\n <Label>Full name</Label>\n <DemoInput defaultValue=\"Rafa Moro\" className=\"w-72\" />\n </Field.Root>\n\n <Field.Root orientation=\"horizontal\" data-testid=\"long\">\n <Label>Title</Label>\n <Field.Content className=\"w-72\">\n <DemoInput placeholder=\"Software engineer\" />\n <Field.Description>Shown on your public profile.</Field.Description>\n </Field.Content>\n </Field.Root>\n\n <Field.Root orientation=\"horizontal\" data-testid=\"switch\">\n <Field.Content>\n <Label>Auto-renew</Label>\n <Field.Description>Renews the policy automatically before it expires.</Field.Description>\n </Field.Content>\n <
|
|
5700
|
+
"snippet": "const Horizontal = () => (\n <Field.Group className=\"w-160\">\n <Field.Root orientation=\"horizontal\" data-testid=\"short\">\n <Label>Full name</Label>\n <DemoInput defaultValue=\"Rafa Moro\" className=\"w-72\" />\n </Field.Root>\n\n <Field.Root orientation=\"horizontal\" data-testid=\"long\">\n <Label>Title</Label>\n <Field.Content className=\"w-72\">\n <DemoInput placeholder=\"Software engineer\" />\n <Field.Description>Shown on your public profile.</Field.Description>\n </Field.Content>\n </Field.Root>\n\n <Field.Root orientation=\"horizontal\" data-testid=\"switch\">\n <Field.Content>\n <Label>Auto-renew</Label>\n <Field.Description>Renews the policy automatically before it expires.</Field.Description>\n </Field.Content>\n <DemoSwitch className=\"self-center\" />\n </Field.Root>\n\n <div className=\"w-[20rem]\" data-testid=\"narrow\">\n <Field.Root orientation=\"horizontal\">\n <Label>Email</Label>\n <DemoInput type=\"email\" placeholder=\"you@example.com\" className=\"w-40\" />\n </Field.Root>\n </div>\n </Field.Group>\n);",
|
|
5695
5701
|
"description": "`horizontal` is one row at every width. The first child fills the row and\neverything after it keeps its natural width, aligned to the right edge, so\nthe controls of stacked fields line up whatever their labels measure. Wrap a\nlabel with its description, or a control with its messages, in\n`Field.Content`. A control sets its own width: `Input` is `w-full`, so it\ngets one here.",
|
|
5696
5702
|
"summary": "Horizontal field, one row at every width, controls right-aligned"
|
|
5697
5703
|
},
|
|
@@ -5731,7 +5737,7 @@
|
|
|
5731
5737
|
"summary": "Errors supplied to a bare Field.Error through context"
|
|
5732
5738
|
}
|
|
5733
5739
|
],
|
|
5734
|
-
"import": "import { Field, FieldContext, Label } from \"@agentero/design-system\";"
|
|
5740
|
+
"import": "import { Field, FieldContext, Label, Switch } from \"@agentero/design-system\";"
|
|
5735
5741
|
},
|
|
5736
5742
|
"components-formtext": {
|
|
5737
5743
|
"id": "components-formtext",
|
|
@@ -9420,6 +9426,6 @@
|
|
|
9420
9426
|
},
|
|
9421
9427
|
"meta": {
|
|
9422
9428
|
"docgen": "react-component-meta",
|
|
9423
|
-
"durationMs":
|
|
9429
|
+
"durationMs": 3701
|
|
9424
9430
|
}
|
|
9425
9431
|
}
|
package/package.json
CHANGED
|
@@ -14,8 +14,9 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
14
14
|
list?: import('tailwind-merge').ClassNameValue;
|
|
15
15
|
clear?: import('tailwind-merge').ClassNameValue;
|
|
16
16
|
item?: import('tailwind-merge').ClassNameValue;
|
|
17
|
-
|
|
17
|
+
indicator?: import('tailwind-merge').ClassNameValue;
|
|
18
18
|
message?: import('tailwind-merge').ClassNameValue;
|
|
19
|
+
field?: import('tailwind-merge').ClassNameValue;
|
|
19
20
|
};
|
|
20
21
|
};
|
|
21
22
|
} | {
|
|
@@ -25,8 +26,9 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
25
26
|
list?: import('tailwind-merge').ClassNameValue;
|
|
26
27
|
clear?: import('tailwind-merge').ClassNameValue;
|
|
27
28
|
item?: import('tailwind-merge').ClassNameValue;
|
|
28
|
-
|
|
29
|
+
indicator?: import('tailwind-merge').ClassNameValue;
|
|
29
30
|
message?: import('tailwind-merge').ClassNameValue;
|
|
31
|
+
field?: import('tailwind-merge').ClassNameValue;
|
|
30
32
|
};
|
|
31
33
|
};
|
|
32
34
|
} | {}, {
|
|
@@ -35,6 +37,7 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
35
37
|
content: string[];
|
|
36
38
|
list: string[];
|
|
37
39
|
item: string[];
|
|
40
|
+
indicator: string[];
|
|
38
41
|
message: string[];
|
|
39
42
|
}, undefined, {
|
|
40
43
|
[key: string]: {
|
|
@@ -43,8 +46,9 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
43
46
|
list?: import('tailwind-merge').ClassNameValue;
|
|
44
47
|
clear?: import('tailwind-merge').ClassNameValue;
|
|
45
48
|
item?: import('tailwind-merge').ClassNameValue;
|
|
46
|
-
|
|
49
|
+
indicator?: import('tailwind-merge').ClassNameValue;
|
|
47
50
|
message?: import('tailwind-merge').ClassNameValue;
|
|
51
|
+
field?: import('tailwind-merge').ClassNameValue;
|
|
48
52
|
};
|
|
49
53
|
};
|
|
50
54
|
} | {}, {
|
|
@@ -53,6 +57,7 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
53
57
|
content: string[];
|
|
54
58
|
list: string[];
|
|
55
59
|
item: string[];
|
|
60
|
+
indicator: string[];
|
|
56
61
|
message: string[];
|
|
57
62
|
}, import('tailwind-variants').TVReturnType<unknown, {
|
|
58
63
|
field: string;
|
|
@@ -60,6 +65,7 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
60
65
|
content: string[];
|
|
61
66
|
list: string[];
|
|
62
67
|
item: string[];
|
|
68
|
+
indicator: string[];
|
|
63
69
|
message: string[];
|
|
64
70
|
}, undefined, unknown, unknown, undefined>>;
|
|
65
71
|
/**
|
|
@@ -71,6 +77,12 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
71
77
|
* `filter={null}`, hand the already-filtered rows to `filteredItems`, and request
|
|
72
78
|
* them from `onInputValueChange`; `Status` then announces the wait.
|
|
73
79
|
*
|
|
80
|
+
* With `multiple`, the value is an array and picking a row toggles it. The list
|
|
81
|
+
* stays open and keeps the typed query between picks, so several rows can be
|
|
82
|
+
* ticked from one search; closing the list (Escape, a click outside) still resets
|
|
83
|
+
* the query. Each row then shows whether it is selected — see `Item`. Nothing is
|
|
84
|
+
* written back into the input: render the selection next to the field.
|
|
85
|
+
*
|
|
74
86
|
* @summary Root provider for an input-triggered filterable list
|
|
75
87
|
* @see {@link https://base-ui.com/react/components/combobox|Base UI Combobox}
|
|
76
88
|
*
|
|
@@ -90,7 +102,7 @@ export declare const comboboxRecipe: import('tailwind-variants').TVReturnType<{
|
|
|
90
102
|
* ```
|
|
91
103
|
*/
|
|
92
104
|
export declare const Root: {
|
|
93
|
-
<Value, Multiple extends boolean | undefined = false, Item = Value>(props: ComboboxPrimitive.Root.Props<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
105
|
+
<Value, Multiple extends boolean | undefined = false, Item = Value>({ onOpenChange, ...props }: ComboboxPrimitive.Root.Props<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
94
106
|
displayName: string;
|
|
95
107
|
};
|
|
96
108
|
type InputProps = Omit<ComponentPropsWithRef<typeof ComboboxPrimitive.Input>, 'size'> & {
|
|
@@ -108,9 +120,19 @@ type InputProps = Omit<ComponentPropsWithRef<typeof ComboboxPrimitive.Input>, 's
|
|
|
108
120
|
* `InputContext`, so inside a `FieldText` the label, the hint and the error point
|
|
109
121
|
* at it with nothing passed by hand. Its own props win over the context.
|
|
110
122
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
123
|
+
* Inside a field it also names itself with `aria-labelledby` pointing at the
|
|
124
|
+
* label, on top of the label's own `for`. While the list is open, Base UI hides
|
|
125
|
+
* everything but the input and the list from assistive technology, label
|
|
126
|
+
* included, and a `<label for>` alone then stops naming the input; a direct
|
|
127
|
+
* reference keeps the name. Outside a field, give it `aria-label` or an
|
|
128
|
+
* `aria-labelledby` of your own.
|
|
129
|
+
*
|
|
130
|
+
* It carries a clear button, which Base UI mounts only once there is something
|
|
131
|
+
* to clear, so an untouched field shows nothing. Name it with `clearLabel` when
|
|
132
|
+
* a page has more than one combobox. Under a `multiple` root there is no clear
|
|
133
|
+
* button: Base UI's would drop the whole selection, while a cross inside a search
|
|
134
|
+
* field reads as "clear what I typed" — and the selection is rendered outside
|
|
135
|
+
* the field, with its own way to remove each entry.
|
|
114
136
|
*
|
|
115
137
|
* Pass `render` to swap the element for a richer control — a field with a leading
|
|
116
138
|
* search icon, for instance — and the combobox wiring rides along.
|
|
@@ -163,11 +185,17 @@ type ItemProps = ComponentPropsWithRef<typeof ComboboxPrimitive.Item>;
|
|
|
163
185
|
* A selectable row. `value` is what the combobox stores and what
|
|
164
186
|
* `itemToStringLabel` turns into the text written back into the input.
|
|
165
187
|
*
|
|
188
|
+
* Under a `multiple` root it leads with a checkbox-shaped indicator that fills
|
|
189
|
+
* while the row is selected, and the row announces `aria-selected` to assistive
|
|
190
|
+
* technology. The indicator is decoration, not a control: clicking anywhere on
|
|
191
|
+
* the row, or pressing Enter on it, is what toggles the selection.
|
|
192
|
+
*
|
|
166
193
|
* @summary Selectable row inside the list
|
|
167
194
|
* @dataAttribute {string} data-slot - Always set to "combobox-item"
|
|
195
|
+
* @dataAttribute {string} data-selected - Present while the row is selected
|
|
168
196
|
*/
|
|
169
197
|
export declare const Item: {
|
|
170
|
-
({ className, ...props }: ItemProps): import("react/jsx-runtime").JSX.Element;
|
|
198
|
+
({ className, children, ...props }: ItemProps): import("react/jsx-runtime").JSX.Element;
|
|
171
199
|
displayName: string;
|
|
172
200
|
};
|
|
173
201
|
type EmptyProps = ComponentPropsWithRef<typeof ComboboxPrimitive.Empty>;
|
package/src/combobox/combobox.js
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { cn as e } from "../../lib/utils.js";
|
|
3
3
|
import { useMergeProps as t } from "../../lib/merge-props.js";
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
4
|
+
import { useFieldContext as n } from "../field/context.js";
|
|
5
|
+
import { InputContext as r } from "../input/context.js";
|
|
6
|
+
import { inputRecipe as i } from "../input/input.js";
|
|
7
|
+
import { IconCancel as a, IconCheck as o } from "./icons.js";
|
|
8
|
+
import { tv as s } from "tailwind-variants";
|
|
9
|
+
import { createContext as c, use as l } from "react";
|
|
10
|
+
import { jsx as u, jsxs as d } from "react/jsx-runtime";
|
|
11
|
+
import { Combobox as f } from "@base-ui/react/combobox";
|
|
11
12
|
//#region src/combobox/combobox.tsx
|
|
12
|
-
var
|
|
13
|
+
var p = s({ slots: {
|
|
13
14
|
field: "relative",
|
|
14
15
|
clear: [
|
|
15
16
|
"absolute top-1/2 right-3 flex size-6 -translate-y-1/2 cursor-pointer items-center",
|
|
@@ -28,82 +29,115 @@ var u = a({ slots: {
|
|
|
28
29
|
],
|
|
29
30
|
list: ["max-h-[min(10.25rem,var(--available-height))] overflow-y-auto scroll-py-2 py-2 outline-none", "data-empty:py-0"],
|
|
30
31
|
item: [
|
|
31
|
-
"mx-2 my-px flex cursor-pointer items-center rounded-[calc(var(--radius-md)-2px)]",
|
|
32
|
+
"group/item mx-2 my-px flex cursor-pointer items-center rounded-[calc(var(--radius-md)-2px)]",
|
|
32
33
|
"px-3 py-2 text-sm text-text-default-base-primary select-none",
|
|
33
34
|
"data-highlighted:bg-bg-default-base-primary-hover",
|
|
34
35
|
"data-disabled:cursor-default data-disabled:text-text-default-base-tertiary"
|
|
35
36
|
],
|
|
37
|
+
indicator: [
|
|
38
|
+
"mr-2 flex size-4 shrink-0 items-center justify-center rounded-sm",
|
|
39
|
+
"border border-border-input-default bg-bg-input-normal",
|
|
40
|
+
"text-text-default-base-inverse-primary transition-colors duration-200 ease-in-out",
|
|
41
|
+
"data-selected:border-bg-checkbox-selected data-selected:bg-bg-checkbox-selected",
|
|
42
|
+
"[&>svg]:hidden data-selected:[&>svg]:block",
|
|
43
|
+
"group-data-disabled/item:border-border-checkbox-disabled",
|
|
44
|
+
"group-data-disabled/item:data-selected:border-bg-checkbox-disabled",
|
|
45
|
+
"group-data-disabled/item:data-selected:bg-bg-checkbox-disabled"
|
|
46
|
+
],
|
|
36
47
|
message: ["mx-2 my-px px-3 py-2 text-sm text-text-default-base-tertiary", "empty:m-0 empty:p-0"]
|
|
37
|
-
} }),
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
} }), m = p(), h = c(!1), g = ({ onOpenChange: e, ...t }) => {
|
|
49
|
+
let n = !!t.multiple;
|
|
50
|
+
return /* @__PURE__ */ u(h, {
|
|
51
|
+
value: n,
|
|
52
|
+
children: /* @__PURE__ */ u(f.Root, {
|
|
53
|
+
onOpenChange: (t, r) => {
|
|
54
|
+
e?.(t, r), n && !t && r.reason === "item-press" && r.cancel();
|
|
55
|
+
},
|
|
56
|
+
...t
|
|
57
|
+
})
|
|
58
|
+
});
|
|
59
|
+
};
|
|
60
|
+
g.displayName = "Combobox.Root";
|
|
61
|
+
var _ = /* @__PURE__ */ new Set([
|
|
40
62
|
"value",
|
|
41
63
|
"defaultValue",
|
|
42
64
|
"onChange"
|
|
43
|
-
]),
|
|
44
|
-
let r =
|
|
45
|
-
return t(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
65
|
+
]), v = (e) => {
|
|
66
|
+
let i = l(r), a = n(), o = i ? Object.fromEntries(Object.entries(i).filter(([e]) => !_.has(e))) : null, s = !("aria-label" in e || "aria-labelledby" in e) && a ? { "aria-labelledby": a.labelId } : null;
|
|
67
|
+
return t({
|
|
68
|
+
...o,
|
|
69
|
+
...s
|
|
70
|
+
}, e);
|
|
71
|
+
}, y = ({ clearLabel: t = "Clear", ...n }) => {
|
|
72
|
+
let { className: r, size: o = "md", ...s } = v(n), c = l(h);
|
|
73
|
+
return /* @__PURE__ */ d("div", {
|
|
49
74
|
"data-slot": "combobox-field",
|
|
50
|
-
className:
|
|
51
|
-
children: [/* @__PURE__ */
|
|
75
|
+
className: m.field(),
|
|
76
|
+
children: [/* @__PURE__ */ u(f.Input, {
|
|
52
77
|
"data-slot": "combobox-input",
|
|
53
78
|
"data-size": o,
|
|
54
|
-
className: e(
|
|
55
|
-
...
|
|
56
|
-
}), /* @__PURE__ */
|
|
79
|
+
className: e(i({ size: o }), "pr-11", r),
|
|
80
|
+
...s
|
|
81
|
+
}), !c && /* @__PURE__ */ u(f.Clear, {
|
|
57
82
|
"data-slot": "combobox-clear",
|
|
58
83
|
"aria-label": t,
|
|
59
|
-
className:
|
|
60
|
-
children: /* @__PURE__ */
|
|
84
|
+
className: m.clear(),
|
|
85
|
+
children: /* @__PURE__ */ u(a, {})
|
|
61
86
|
})]
|
|
62
87
|
});
|
|
63
88
|
};
|
|
64
|
-
|
|
65
|
-
var
|
|
89
|
+
y.displayName = "Combobox.Input";
|
|
90
|
+
var b = ({ className: t, side: n = "bottom", align: r = "start", sideOffset: i = 12, alignOffset: a, anchor: o, collisionPadding: s = 8, ...c }) => /* @__PURE__ */ u(f.Portal, { children: /* @__PURE__ */ u(f.Positioner, {
|
|
66
91
|
side: n,
|
|
67
92
|
align: r,
|
|
68
93
|
sideOffset: i,
|
|
69
94
|
alignOffset: a,
|
|
70
95
|
anchor: o,
|
|
71
|
-
collisionPadding:
|
|
96
|
+
collisionPadding: s,
|
|
72
97
|
className: "isolate z-(--z-index-top-layer) pointer-events-auto",
|
|
73
|
-
children: /* @__PURE__ */
|
|
98
|
+
children: /* @__PURE__ */ u(f.Popup, {
|
|
74
99
|
"data-slot": "combobox-content",
|
|
75
|
-
className: e(
|
|
76
|
-
...
|
|
100
|
+
className: e(m.content(), t),
|
|
101
|
+
...c
|
|
77
102
|
})
|
|
78
103
|
}) });
|
|
79
|
-
|
|
80
|
-
var
|
|
104
|
+
b.displayName = "Combobox.Content";
|
|
105
|
+
var x = ({ className: t, ...n }) => {
|
|
81
106
|
let r = "aria-label" in n || "aria-labelledby" in n;
|
|
82
|
-
return /* @__PURE__ */
|
|
107
|
+
return /* @__PURE__ */ u(f.List, {
|
|
83
108
|
"data-slot": "combobox-list",
|
|
84
109
|
"aria-label": r ? void 0 : "Suggestions",
|
|
85
|
-
className: e(
|
|
110
|
+
className: e(m.list(), t),
|
|
86
111
|
...n
|
|
87
112
|
});
|
|
88
113
|
};
|
|
89
|
-
|
|
90
|
-
var
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
114
|
+
x.displayName = "Combobox.List";
|
|
115
|
+
var S = ({ className: t, children: n, ...r }) => {
|
|
116
|
+
let i = l(h);
|
|
117
|
+
return /* @__PURE__ */ d(f.Item, {
|
|
118
|
+
"data-slot": "combobox-item",
|
|
119
|
+
className: e(m.item(), t),
|
|
120
|
+
...r,
|
|
121
|
+
children: [i && /* @__PURE__ */ u(f.ItemIndicator, {
|
|
122
|
+
keepMounted: !0,
|
|
123
|
+
"data-slot": "combobox-item-indicator",
|
|
124
|
+
className: m.indicator(),
|
|
125
|
+
children: /* @__PURE__ */ u(o, { className: "size-3.5" })
|
|
126
|
+
}), n]
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
S.displayName = "Combobox.Item";
|
|
130
|
+
var C = ({ className: t, ...n }) => /* @__PURE__ */ u(f.Empty, {
|
|
97
131
|
"data-slot": "combobox-empty",
|
|
98
|
-
className: e(
|
|
132
|
+
className: e(m.message(), t),
|
|
99
133
|
...n
|
|
100
134
|
});
|
|
101
|
-
|
|
102
|
-
var
|
|
135
|
+
C.displayName = "Combobox.Empty";
|
|
136
|
+
var w = ({ className: t, ...n }) => /* @__PURE__ */ u(f.Status, {
|
|
103
137
|
"data-slot": "combobox-status",
|
|
104
|
-
className: e(
|
|
138
|
+
className: e(m.message(), t),
|
|
105
139
|
...n
|
|
106
140
|
});
|
|
107
|
-
|
|
141
|
+
w.displayName = "Combobox.Status";
|
|
108
142
|
//#endregion
|
|
109
|
-
export {
|
|
143
|
+
export { b as Content, C as Empty, y as Input, S as Item, x as List, g as Root, w as Status, p as comboboxRecipe };
|
package/src/combobox/icons.d.ts
CHANGED
|
@@ -8,3 +8,11 @@ import { SVGProps } from 'react';
|
|
|
8
8
|
* @summary 24px cancel icon used as the Combobox clear affordance
|
|
9
9
|
*/
|
|
10
10
|
export declare const IconCancel: (props: SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
/**
|
|
12
|
+
* Material Sharp check drawn inside a selected row's indicator, the same glyph
|
|
13
|
+
* `Checkbox` uses, so a multi-select row reads as a ticked checkbox. Takes its
|
|
14
|
+
* color from the surrounding text.
|
|
15
|
+
*
|
|
16
|
+
* @summary 24px check used by the Combobox selection indicator
|
|
17
|
+
*/
|
|
18
|
+
export declare const IconCheck: (props: SVGProps<SVGSVGElement>) => import("react/jsx-runtime").JSX.Element;
|
package/src/combobox/icons.js
CHANGED
|
@@ -8,6 +8,16 @@ var t = (t) => /* @__PURE__ */ e("svg", {
|
|
|
8
8
|
xmlns: "http://www.w3.org/2000/svg",
|
|
9
9
|
...t,
|
|
10
10
|
children: /* @__PURE__ */ e("path", { d: "M12 13.0538L15.0731 16.1269C15.2115 16.2654 15.3856 16.3362 15.5952 16.3394C15.8048 16.3426 15.982 16.2718 16.1269 16.1269C16.2718 15.982 16.3442 15.8064 16.3442 15.6C16.3442 15.3936 16.2718 15.218 16.1269 15.0731L13.0538 12L16.1269 8.9269C16.2653 8.78845 16.3362 8.61442 16.3394 8.4048C16.3426 8.1952 16.2718 8.01797 16.1269 7.8731C15.982 7.72822 15.8064 7.65577 15.6 7.65577C15.3936 7.65577 15.2179 7.72822 15.0731 7.8731L12 10.9462L8.92688 7.8731C8.78842 7.73463 8.61439 7.6638 8.40478 7.6606C8.19518 7.65738 8.01794 7.72822 7.87308 7.8731C7.72819 8.01797 7.65575 8.1936 7.65575 8.4C7.65575 8.6064 7.72819 8.78203 7.87308 8.9269L10.9461 12L7.87308 15.0731C7.73461 15.2115 7.66378 15.3856 7.66058 15.5952C7.65736 15.8048 7.72819 15.982 7.87308 16.1269C8.01794 16.2718 8.19358 16.3442 8.39998 16.3442C8.60638 16.3442 8.78201 16.2718 8.92688 16.1269L12 13.0538ZM12.0016 21.5C10.6877 21.5 9.45268 21.2506 8.29655 20.752C7.1404 20.2533 6.13472 19.5766 5.2795 18.7217C4.42427 17.8669 3.74721 16.8616 3.24833 15.706C2.74944 14.5504 2.5 13.3156 2.5 12.0017C2.5 10.6877 2.74933 9.45271 3.248 8.29657C3.74667 7.14042 4.42342 6.13474 5.27825 5.27952C6.1331 4.42429 7.13834 3.74723 8.29398 3.24835C9.44959 2.74947 10.6844 2.50002 11.9983 2.50002C13.3122 2.50002 14.5473 2.74936 15.7034 3.24802C16.8596 3.74669 17.8652 4.42344 18.7205 5.27827C19.5757 6.13312 20.2527 7.13837 20.7516 8.294C21.2505 9.44962 21.5 10.6844 21.5 11.9983C21.5 13.3123 21.2506 14.5473 20.752 15.7034C20.2533 16.8596 19.5765 17.8653 18.7217 18.7205C17.8669 19.5757 16.8616 20.2528 15.706 20.7516C14.5504 21.2505 13.3156 21.5 12.0016 21.5ZM12 20C14.2333 20 16.125 19.225 17.675 17.675C19.225 16.125 20 14.2333 20 12C20 9.76667 19.225 7.875 17.675 6.325C16.125 4.775 14.2333 4 12 4C9.76664 4 7.87498 4.775 6.32498 6.325C4.77498 7.875 3.99998 9.76667 3.99998 12C3.99998 14.2333 4.77498 16.125 6.32498 17.675C7.87498 19.225 9.76664 20 12 20Z" })
|
|
11
|
+
}), n = (t) => /* @__PURE__ */ e("svg", {
|
|
12
|
+
width: "24",
|
|
13
|
+
height: "24",
|
|
14
|
+
viewBox: "0 0 24 24",
|
|
15
|
+
fill: "currentColor",
|
|
16
|
+
stroke: "currentColor",
|
|
17
|
+
"aria-hidden": "true",
|
|
18
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
19
|
+
...t,
|
|
20
|
+
children: /* @__PURE__ */ e("path", { d: "M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" })
|
|
11
21
|
});
|
|
12
22
|
//#endregion
|
|
13
|
-
export { t as IconCancel };
|
|
23
|
+
export { t as IconCancel, n as IconCheck };
|
package/src/combobox/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { comboboxRecipe } from './combobox';
|
|
2
2
|
export declare const Combobox: {
|
|
3
3
|
Root: {
|
|
4
|
-
<Value, Multiple extends boolean | undefined = false, Item = Value>(props: import("@base-ui/react/combobox").ComboboxRoot.Props<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
4
|
+
<Value, Multiple extends boolean | undefined = false, Item = Value>({ onOpenChange, ...props }: import("@base-ui/react/combobox").ComboboxRoot.Props<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
displayName: string;
|
|
6
6
|
};
|
|
7
7
|
Input: {
|
|
@@ -20,7 +20,7 @@ export declare const Combobox: {
|
|
|
20
20
|
displayName: string;
|
|
21
21
|
};
|
|
22
22
|
Item: {
|
|
23
|
-
({ className, ...props }: Omit<import('@base-ui/react/combobox').ComboboxItemProps, "ref"> & import('react').RefAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
23
|
+
({ className, children, ...props }: Omit<import('@base-ui/react/combobox').ComboboxItemProps, "ref"> & import('react').RefAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
24
24
|
displayName: string;
|
|
25
25
|
};
|
|
26
26
|
Empty: {
|
package/src/field/context.d.ts
CHANGED
|
@@ -19,6 +19,13 @@ export type FieldErrorLike = {
|
|
|
19
19
|
export type FieldContextValue = {
|
|
20
20
|
/** `id` the control must carry so the label points at it. */
|
|
21
21
|
controlId: string;
|
|
22
|
+
/**
|
|
23
|
+
* `id` the `Label` carries, for a control that names itself with
|
|
24
|
+
* `aria-labelledby` because a plain `<label for>` is not enough: a floating
|
|
25
|
+
* surface that hides the rest of the page from assistive technology hides
|
|
26
|
+
* the label with it, and only a direct reference survives that.
|
|
27
|
+
*/
|
|
28
|
+
labelId: string;
|
|
22
29
|
/** `id` the `Field.Description` takes by default. One description per field. */
|
|
23
30
|
descriptionId: string;
|
|
24
31
|
/** `id` the `Field.Error` takes by default. One error element per field. */
|
package/src/field/field.d.ts
CHANGED
|
@@ -126,7 +126,9 @@ export type FieldRootProps = ComponentPropsWithRef<'div'> & {
|
|
|
126
126
|
* `Field.Description` and `Field.Error` read `FieldContext` and register
|
|
127
127
|
* themselves so the control's `aria-describedby` lists exactly the messages on
|
|
128
128
|
* screen, and a `Field<X>` such as `FieldText` provides the control's context so
|
|
129
|
-
* the control associates itself too. Nobody passes an `id` by hand.
|
|
129
|
+
* the control associates itself too. Nobody passes an `id` by hand. The label
|
|
130
|
+
* gets an id as well (`labelId` in `FieldContext`) for a control that must
|
|
131
|
+
* name itself with `aria-labelledby`, as `Combobox.Input` does.
|
|
130
132
|
*
|
|
131
133
|
* Presentational and form-library agnostic: pass `invalid` and the error
|
|
132
134
|
* messages from whatever validates the form. Deliberately not a `role="group"`:
|
package/src/field/field.js
CHANGED
|
@@ -45,21 +45,23 @@ var m = s({
|
|
|
45
45
|
});
|
|
46
46
|
g.displayName = "Field.Group";
|
|
47
47
|
var _ = ({ className: n, orientation: r = "vertical", invalid: a = !1, disabled: o = !1, readOnly: s = !1, required: u = !1, controlId: p, ...m }) => {
|
|
48
|
-
let g = l(), _ = p ?? `${g}-control`, v = `${g}-
|
|
48
|
+
let g = l(), _ = p ?? `${g}-control`, v = `${g}-label`, y = `${g}-description`, b = `${g}-error`, [x, S] = d([]), C = c((e) => (S((t) => t.includes(e) ? t : [...t, e]), () => S((t) => t.filter((t) => t !== e))), []), w = {
|
|
49
49
|
controlId: _,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
labelId: v,
|
|
51
|
+
descriptionId: y,
|
|
52
|
+
errorId: b,
|
|
53
|
+
describedBy: [...[y, b].filter((e) => x.includes(e)), ...x.filter((e) => e !== y && e !== b)].join(" ") || void 0,
|
|
54
|
+
registerMessage: C,
|
|
54
55
|
invalid: a,
|
|
55
56
|
disabled: o,
|
|
56
57
|
readOnly: s,
|
|
57
58
|
required: u
|
|
58
59
|
};
|
|
59
60
|
return /* @__PURE__ */ f(i, {
|
|
60
|
-
value:
|
|
61
|
+
value: w,
|
|
61
62
|
children: /* @__PURE__ */ f(t, {
|
|
62
63
|
value: {
|
|
64
|
+
id: v,
|
|
63
65
|
htmlFor: _,
|
|
64
66
|
required: u || void 0
|
|
65
67
|
},
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { useFieldContext as e } from "../field/context.js";
|
|
3
|
+
import { Field as t } from "../field/index.js";
|
|
4
|
+
import { InputContext as n } from "../input/context.js";
|
|
5
5
|
import { jsx as r } from "react/jsx-runtime";
|
|
6
6
|
//#region src/field-text/field-text.tsx
|
|
7
|
-
var i = ({ children:
|
|
8
|
-
let i =
|
|
7
|
+
var i = ({ children: t }) => {
|
|
8
|
+
let i = e(), a = i && {
|
|
9
9
|
id: i.controlId,
|
|
10
10
|
"aria-describedby": i.describedBy,
|
|
11
11
|
"aria-invalid": i.invalid || void 0,
|
|
@@ -13,12 +13,12 @@ var i = ({ children: n }) => {
|
|
|
13
13
|
disabled: i.disabled || void 0,
|
|
14
14
|
readOnly: i.readOnly || void 0
|
|
15
15
|
};
|
|
16
|
-
return /* @__PURE__ */ r(
|
|
16
|
+
return /* @__PURE__ */ r(n, {
|
|
17
17
|
value: a,
|
|
18
|
-
children:
|
|
18
|
+
children: t
|
|
19
19
|
});
|
|
20
|
-
}, a = ({ children: e, ...
|
|
21
|
-
...
|
|
20
|
+
}, a = ({ children: e, ...n }) => /* @__PURE__ */ r(t.Root, {
|
|
21
|
+
...n,
|
|
22
22
|
children: /* @__PURE__ */ r(i, { children: e })
|
|
23
23
|
});
|
|
24
24
|
a.displayName = "FieldText";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { mergeProps as e } from "../../lib/merge-props.js";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
3
|
+
import { Field as t } from "../field/index.js";
|
|
4
|
+
import { Input as n } from "../input/input.js";
|
|
5
5
|
import { FieldText as r } from "../field-text/field-text.js";
|
|
6
6
|
import { jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
7
7
|
import { useController as o } from "react-hook-form";
|
|
@@ -23,15 +23,15 @@ var s = ({ name: s, control: c, rules: l, shouldUnregister: u, disabled: d, labe
|
|
|
23
23
|
invalid: b.invalid,
|
|
24
24
|
disabled: d || y.disabled,
|
|
25
25
|
...v,
|
|
26
|
-
children: [/* @__PURE__ */ i(
|
|
26
|
+
children: [/* @__PURE__ */ i(t.Label, {
|
|
27
27
|
tooltip: m,
|
|
28
28
|
tooltipSide: h,
|
|
29
29
|
optional: g,
|
|
30
30
|
children: f
|
|
31
|
-
}), /* @__PURE__ */ a(
|
|
32
|
-
/* @__PURE__ */ i(
|
|
33
|
-
p && /* @__PURE__ */ i(
|
|
34
|
-
/* @__PURE__ */ i(
|
|
31
|
+
}), /* @__PURE__ */ a(t.Content, { children: [
|
|
32
|
+
/* @__PURE__ */ i(n, { ...e(x, _ ?? {}) }),
|
|
33
|
+
p && /* @__PURE__ */ i(t.Description, { children: p }),
|
|
34
|
+
/* @__PURE__ */ i(t.Error, { errors: b.error ? [b.error] : void 0 })
|
|
35
35
|
] })]
|
|
36
36
|
});
|
|
37
37
|
};
|