@agentero/design-system 0.34.0 → 0.34.2
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 +52 -22
- package/mcp/manifests/components.json +51 -11
- package/package.json +1 -1
- package/src/combobox/combobox.d.ts +39 -10
- package/src/combobox/combobox.js +113 -87
- package/src/combobox/index.d.ts +3 -3
- package/src/label/label.d.ts +28 -16
- package/src/label/label.js +22 -22
|
@@ -594,7 +594,7 @@
|
|
|
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>3.
|
|
597
|
+
Using <code>react-component-meta</code>. Generation took <strong>3.1s</strong>.
|
|
598
598
|
</div>
|
|
599
599
|
<h2 class="section-title">Components</h2>
|
|
600
600
|
<div class="grid" role="list">
|
|
@@ -2855,7 +2855,7 @@ import { CheckList } from '@agentero/design-system/check-list';
|
|
|
2855
2855
|
<div class="title">
|
|
2856
2856
|
<h2><span class="status-dot dot-ok"></span> Combobox.Root</h2>
|
|
2857
2857
|
<div class="badges">
|
|
2858
|
-
<label for="c-7-components-combobox-props" class="badge ok as-toggle">
|
|
2858
|
+
<label for="c-7-components-combobox-props" class="badge ok as-toggle">41 prop types</label>
|
|
2859
2859
|
|
|
2860
2860
|
<label for="c-7-components-combobox-stories" class="badge ok as-toggle">10 stories</label>
|
|
2861
2861
|
|
|
@@ -2900,7 +2900,7 @@ import { Combobox } from '@agentero/design-system/combobox';
|
|
|
2900
2900
|
<div class="note ok">
|
|
2901
2901
|
<div class="row">
|
|
2902
2902
|
<span class="ex-name">Prop types <small>(react-component-meta)</small></span>
|
|
2903
|
-
<span class="badge ok">
|
|
2903
|
+
<span class="badge ok">41 prop types</span>
|
|
2904
2904
|
</div>
|
|
2905
2905
|
<pre><code>Component: src/combobox/index.ts::Combobox</code></pre>
|
|
2906
2906
|
<pre><code>Props:</code></pre>
|
|
@@ -3047,6 +3047,28 @@ itemToStringValue?: (itemValue: unknown) => string
|
|
|
3047
3047
|
*/
|
|
3048
3048
|
limit?: number = -1
|
|
3049
3049
|
|
|
3050
|
+
/**
|
|
3051
|
+
* Whether the options are being fetched. Once the list has been open and
|
|
3052
|
+
* loading for half a second, `loadingLabel` is announced once: sooner, a
|
|
3053
|
+
* screen reader would cut it off to echo the key just typed, and a faster
|
|
3054
|
+
* answer has no wait to announce. `Content` is marked `aria-busy`, and
|
|
3055
|
+
* `Empty` shows nothing, so "no results" is not read out before the results
|
|
3056
|
+
* arrive. The announcement comes from a visually hidden live region the root
|
|
3057
|
+
* renders next to the field, so it is in place before the list opens. On a search
|
|
3058
|
+
* against an API, pass it from the first render, as `false` while idle: a root
|
|
3059
|
+
* that leaves it out gets no live region. A list filtered in memory never
|
|
3060
|
+
* waits and leaves it out. While loading with no rows yet, the surface shows
|
|
3061
|
+
* whatever placeholder `Content` holds — `Empty` stays quiet.
|
|
3062
|
+
*/
|
|
3063
|
+
loading?: boolean
|
|
3064
|
+
|
|
3065
|
+
/**
|
|
3066
|
+
* What a screen reader hears when `loading` turns `true`. Announced only; any
|
|
3067
|
+
* loading visuals — placeholder rows, a spinner — are yours to render inside
|
|
3068
|
+
* `Content`, hidden from assistive technology. Defaults to `'Loading…'`.
|
|
3069
|
+
*/
|
|
3070
|
+
loadingLabel?: string = 'Loading…'
|
|
3071
|
+
|
|
3050
3072
|
/**
|
|
3051
3073
|
* The locale to use for string comparison.
|
|
3052
3074
|
* Defaults to the user's runtime locale.
|
|
@@ -3340,9 +3362,10 @@ here as tags.</div>
|
|
|
3340
3362
|
<div class="hint">Options fetched as you type, the way the apps load data: the rows are a component
|
|
3341
3363
|
that suspends on the request, so a `Suspense` boundary inside `Content` shows
|
|
3342
3364
|
placeholder rows until the first results land. The rows read a deferred copy of
|
|
3343
|
-
the query, so a new search keeps the previous rows on screen while it loads and
|
|
3344
|
-
|
|
3345
|
-
|
|
3365
|
+
the query, so a new search keeps the previous rows on screen while it loads, and
|
|
3366
|
+
passing that staleness as `loading` announces the wait and marks `Content` busy
|
|
3367
|
+
until they are replaced; the placeholders never come back. Nothing tracks a
|
|
3368
|
+
request by hand, and reading the data by query is what
|
|
3346
3369
|
makes out-of-order responses harmless. With react-query, drop a
|
|
3347
3370
|
`useSuspenseQuery` where `use()` is, or use `placeholderData: keepPreviousData`
|
|
3348
3371
|
with a plain `useQuery` for the same behaviour.</div>
|
|
@@ -3360,12 +3383,14 @@ with a plain `useQuery` for the same behaviour.</div>
|
|
|
3360
3383
|
filter={null}
|
|
3361
3384
|
itemToStringLabel={(agency: Agency) => agency.name}
|
|
3362
3385
|
isItemEqualToValue={(a: Agency, b: Agency) => a.id === b.id}
|
|
3386
|
+
loading={isStale}
|
|
3387
|
+
loadingLabel="Searching agencies…"
|
|
3363
3388
|
onInputValueChange={(value, { reason }) => {
|
|
3364
3389
|
// Picking a row writes its label into the input; that is not a new search.
|
|
3365
3390
|
if (reason !== 'item-press') setQuery(value);
|
|
3366
3391
|
}}>
|
|
3367
3392
|
<Combobox.Input placeholder="Search agencies" aria-label="Search agencies" />
|
|
3368
|
-
<Combobox.Content
|
|
3393
|
+
<Combobox.Content>
|
|
3369
3394
|
<Suspense fallback={<SkeletonRows />}>
|
|
3370
3395
|
<AgencyItems query={deferredQuery} />
|
|
3371
3396
|
</Suspense>
|
|
@@ -3376,21 +3401,24 @@ with a plain `useQuery` for the same behaviour.</div>
|
|
|
3376
3401
|
</div>
|
|
3377
3402
|
<div class="note ok">
|
|
3378
3403
|
<div class="row">
|
|
3379
|
-
<span class="ex-name">Async Search With
|
|
3404
|
+
<span class="ex-name">Async Search With Loading</span>
|
|
3380
3405
|
<span class="badge ok">story ok</span>
|
|
3381
3406
|
</div>
|
|
3382
|
-
<div>API search that waits for two characters
|
|
3407
|
+
<div>API search that waits for two characters and announces its loading state</div>
|
|
3383
3408
|
<div class="hint">The same search without Suspense, for a consumer that gets a `loading` flag from
|
|
3384
3409
|
its data layer instead: `filter={null}`, the rows arrive through `filteredItems`,
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3410
|
+
and the flag goes to `Root` as `loading`. That is all the wiring the wait needs:
|
|
3411
|
+
`Content` is marked busy, `loadingLabel` is announced once when the request
|
|
3412
|
+
starts, and `Empty` holds back "no results" until the answer is in. Placeholder
|
|
3413
|
+
rows show only while there is nothing to show yet, hidden from assistive
|
|
3414
|
+
technology since the label already speaks for them; after that, the previous
|
|
3415
|
+
rows stay until the new ones replace them. A request that is no longer the
|
|
3416
|
+
latest is dropped.
|
|
3389
3417
|
|
|
3390
3418
|
`minInputLength` keeps the list shut until two characters are typed — focusing
|
|
3391
3419
|
the field opens nothing, and deleting back under the minimum closes it — and
|
|
3392
3420
|
no request goes out for a shorter query either.</div>
|
|
3393
|
-
<pre><code>const
|
|
3421
|
+
<pre><code>const AsyncSearchWithLoading = () => {
|
|
3394
3422
|
const [results, setResults] = useState<Agency[]>([]);
|
|
3395
3423
|
const [isLoading, setIsLoading] = useState(false);
|
|
3396
3424
|
// Only the latest request may land; fast typing returns responses out of order.
|
|
@@ -3420,17 +3448,15 @@ no request goes out for a shorter query either.</div>
|
|
|
3420
3448
|
filteredItems={results}
|
|
3421
3449
|
filter={null}
|
|
3422
3450
|
minInputLength={MIN_QUERY_LENGTH}
|
|
3451
|
+
loading={isLoading}
|
|
3452
|
+
loadingLabel="Searching agencies…"
|
|
3423
3453
|
itemToStringLabel={(agency: Agency) => agency.name}
|
|
3424
3454
|
isItemEqualToValue={(a: Agency, b: Agency) => a.id === b.id}
|
|
3425
3455
|
onInputValueChange={onInputValueChange}>
|
|
3426
3456
|
<Combobox.Input placeholder="Search agencies" aria-label="Search agencies" />
|
|
3427
|
-
<Combobox.Content
|
|
3428
|
-
{/* The rows show the wait; `Status` only announces it. */}
|
|
3429
|
-
<Combobox.Status className="sr-only">
|
|
3430
|
-
{isLoading ? 'Searching…' : undefined}
|
|
3431
|
-
</Combobox.Status>
|
|
3457
|
+
<Combobox.Content>
|
|
3432
3458
|
{isLoading && results.length === 0 && <SkeletonRows />}
|
|
3433
|
-
<Combobox.Empty>
|
|
3459
|
+
<Combobox.Empty>No agencies found</Combobox.Empty>
|
|
3434
3460
|
<Combobox.List>
|
|
3435
3461
|
{(agency: Agency) => (
|
|
3436
3462
|
<Combobox.Item key={agency.id} value={agency}>
|
|
@@ -7972,8 +7998,12 @@ required?: boolean = false</code></pre>
|
|
|
7972
7998
|
<span class="badge ok">story ok</span>
|
|
7973
7999
|
</div>
|
|
7974
8000
|
<div>Optional field with a muted suffix</div>
|
|
7975
|
-
<div class="hint">Appends a muted " (optional)" suffix for fields that can be left blank
|
|
7976
|
-
|
|
8001
|
+
<div class="hint">Appends a muted " (optional)" suffix for fields that can be left blank. The
|
|
8002
|
+
suffix is real text, so it is part of the control's accessible name.</div>
|
|
8003
|
+
<pre><code>const Optional = () => <>
|
|
8004
|
+
<Label optional htmlFor="phone">Phone number</Label>
|
|
8005
|
+
<input id="phone" type="tel" className={inputRecipe()} />
|
|
8006
|
+
</>;</code></pre>
|
|
7977
8007
|
</div>
|
|
7978
8008
|
<div class="note ok">
|
|
7979
8009
|
<div class="row">
|
|
@@ -2007,7 +2007,7 @@
|
|
|
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. The list opens on focus, on the first keystroke\nor from the chevron of `Input`'s `select` variant.\n\nFor a search against an API, set `minInputLength` so the list stays shut until\nthe query is worth sending: a field that opens an empty list on focus reads as\nbroken. For a pick from a short fixed list with no typing at all, prefer a\nselect.\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`,
|
|
2010
|
+
"description": "Root of a combobox: a text input that filters a list of options and writes the\nchosen one back into itself. The list opens on focus, on the first keystroke\nor from the chevron of `Input`'s `select` variant.\n\nFor a search against an API, set `minInputLength` so the list stays shut until\nthe query is worth sending: a field that opens an empty list on focus reads as\nbroken. For a pick from a short fixed list with no typing at all, prefer a\nselect.\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`, request\nthem from `onInputValueChange`, and pass the request's state as `loading`:\nthe combobox announces the wait and marks the list busy on its own.\n\nEvery Base UI root prop is accepted and forwarded — `items`, `filter`,\n`value`, `onValueChange` and so on. `open` stays the consumer's to control;\n`minInputLength` only refuses to open below the minimum.\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"
|
|
@@ -2790,6 +2790,46 @@
|
|
|
2790
2790
|
"fileName": "src/combobox/combobox.tsx"
|
|
2791
2791
|
}
|
|
2792
2792
|
]
|
|
2793
|
+
},
|
|
2794
|
+
"loading": {
|
|
2795
|
+
"name": "loading",
|
|
2796
|
+
"required": false,
|
|
2797
|
+
"type": {
|
|
2798
|
+
"name": "boolean"
|
|
2799
|
+
},
|
|
2800
|
+
"description": "Whether the options are being fetched. Once the list has been open and\nloading for half a second, `loadingLabel` is announced once: sooner, a\nscreen reader would cut it off to echo the key just typed, and a faster\nanswer has no wait to announce. `Content` is marked `aria-busy`, and\n`Empty` shows nothing, so \"no results\" is not read out before the results\narrive. The announcement comes from a visually hidden live region the root\nrenders next to the field, so it is in place before the list opens. On a search\nagainst an API, pass it from the first render, as `false` while idle: a root\nthat leaves it out gets no live region. A list filtered in memory never\nwaits and leaves it out. While loading with no rows yet, the surface shows\nwhatever placeholder `Content` holds — `Empty` stays quiet.",
|
|
2801
|
+
"defaultValue": null,
|
|
2802
|
+
"parent": {
|
|
2803
|
+
"name": "ComboboxRootProps",
|
|
2804
|
+
"fileName": "src/combobox/combobox.tsx"
|
|
2805
|
+
},
|
|
2806
|
+
"declarations": [
|
|
2807
|
+
{
|
|
2808
|
+
"name": "TypeLiteral",
|
|
2809
|
+
"fileName": "src/combobox/combobox.tsx"
|
|
2810
|
+
}
|
|
2811
|
+
]
|
|
2812
|
+
},
|
|
2813
|
+
"loadingLabel": {
|
|
2814
|
+
"name": "loadingLabel",
|
|
2815
|
+
"required": false,
|
|
2816
|
+
"type": {
|
|
2817
|
+
"name": "string"
|
|
2818
|
+
},
|
|
2819
|
+
"description": "What a screen reader hears when `loading` turns `true`. Announced only; any\nloading visuals — placeholder rows, a spinner — are yours to render inside\n`Content`, hidden from assistive technology. Defaults to `'Loading…'`.",
|
|
2820
|
+
"defaultValue": {
|
|
2821
|
+
"value": "'Loading…'"
|
|
2822
|
+
},
|
|
2823
|
+
"parent": {
|
|
2824
|
+
"name": "ComboboxRootProps",
|
|
2825
|
+
"fileName": "src/combobox/combobox.tsx"
|
|
2826
|
+
},
|
|
2827
|
+
"declarations": [
|
|
2828
|
+
{
|
|
2829
|
+
"name": "TypeLiteral",
|
|
2830
|
+
"fileName": "src/combobox/combobox.tsx"
|
|
2831
|
+
}
|
|
2832
|
+
]
|
|
2793
2833
|
}
|
|
2794
2834
|
}
|
|
2795
2835
|
},
|
|
@@ -2837,15 +2877,15 @@
|
|
|
2837
2877
|
{
|
|
2838
2878
|
"id": "components-combobox--async-search",
|
|
2839
2879
|
"name": "Async Search",
|
|
2840
|
-
"snippet": "const AsyncSearch = () => {\n const [query, setQuery] = useState('');\n // The rows read the deferred query: while the new one suspends, React keeps rendering the\n // old rows instead of falling back to the placeholders.\n const deferredQuery = useDeferredValue(query);\n const isStale = query !== deferredQuery;\n\n return (\n // No `items` and `filter={null}`: the server did the filtering, the child renders what came\n // back, and `isItemEqualToValue` keeps a re-fetched copy counting as the selected one.\n <Combobox.Root\n filter={null}\n itemToStringLabel={(agency: Agency) => agency.name}\n isItemEqualToValue={(a: Agency, b: Agency) => a.id === b.id}\n onInputValueChange={(value, { reason }) => {\n // Picking a row writes its label into the input; that is not a new search.\n if (reason !== 'item-press') setQuery(value);\n }}>\n <Combobox.Input placeholder=\"Search agencies\" aria-label=\"Search agencies\" />\n <Combobox.Content
|
|
2841
|
-
"description": "Options fetched as you type, the way the apps load data: the rows are a component\nthat suspends on the request, so a `Suspense` boundary inside `Content` shows\nplaceholder rows until the first results land. The rows read a deferred copy of\nthe query, so a new search keeps the previous rows on screen while it loads and\
|
|
2880
|
+
"snippet": "const AsyncSearch = () => {\n const [query, setQuery] = useState('');\n // The rows read the deferred query: while the new one suspends, React keeps rendering the\n // old rows instead of falling back to the placeholders.\n const deferredQuery = useDeferredValue(query);\n const isStale = query !== deferredQuery;\n\n return (\n // No `items` and `filter={null}`: the server did the filtering, the child renders what came\n // back, and `isItemEqualToValue` keeps a re-fetched copy counting as the selected one.\n <Combobox.Root\n filter={null}\n itemToStringLabel={(agency: Agency) => agency.name}\n isItemEqualToValue={(a: Agency, b: Agency) => a.id === b.id}\n loading={isStale}\n loadingLabel=\"Searching agencies…\"\n onInputValueChange={(value, { reason }) => {\n // Picking a row writes its label into the input; that is not a new search.\n if (reason !== 'item-press') setQuery(value);\n }}>\n <Combobox.Input placeholder=\"Search agencies\" aria-label=\"Search agencies\" />\n <Combobox.Content>\n <Suspense fallback={<SkeletonRows />}>\n <AgencyItems query={deferredQuery} />\n </Suspense>\n </Combobox.Content>\n </Combobox.Root>\n );\n};",
|
|
2881
|
+
"description": "Options fetched as you type, the way the apps load data: the rows are a component\nthat suspends on the request, so a `Suspense` boundary inside `Content` shows\nplaceholder rows until the first results land. The rows read a deferred copy of\nthe query, so a new search keeps the previous rows on screen while it loads, and\npassing that staleness as `loading` announces the wait and marks `Content` busy\nuntil they are replaced; the placeholders never come back. Nothing tracks a\nrequest by hand, and reading the data by query is what\nmakes out-of-order responses harmless. With react-query, drop a\n`useSuspenseQuery` where `use()` is, or use `placeholderData: keepPreviousData`\nwith a plain `useQuery` for the same behaviour."
|
|
2842
2882
|
},
|
|
2843
2883
|
{
|
|
2844
|
-
"id": "components-combobox--async-search-with-
|
|
2845
|
-
"name": "Async Search With
|
|
2846
|
-
"snippet": "const
|
|
2847
|
-
"description": "The same search without Suspense, for a consumer that gets a `loading` flag from\nits data layer instead: `filter={null}`, the rows arrive through `filteredItems`,\n`Content` is marked busy and `
|
|
2848
|
-
"summary": "API search that waits for two characters
|
|
2884
|
+
"id": "components-combobox--async-search-with-loading",
|
|
2885
|
+
"name": "Async Search With Loading",
|
|
2886
|
+
"snippet": "const AsyncSearchWithLoading = () => {\n const [results, setResults] = useState<Agency[]>([]);\n const [isLoading, setIsLoading] = useState(false);\n // Only the latest request may land; fast typing returns responses out of order.\n const latestRequest = useRef(0);\n\n const onInputValueChange = async (query: string) => {\n const request = ++latestRequest.current;\n if (query.trim().length < MIN_QUERY_LENGTH) {\n setResults([]);\n setIsLoading(false);\n return;\n }\n\n // The previous rows stay through the wait, marked busy, rather than blinking out and back.\n setIsLoading(true);\n const agencies = await searchAgencies(query);\n if (request !== latestRequest.current) return;\n\n setResults(agencies);\n setIsLoading(false);\n };\n\n return (\n // `filter={null}` hands filtering to the server; `filteredItems` is what came back.\n <Combobox.Root\n items={results}\n filteredItems={results}\n filter={null}\n minInputLength={MIN_QUERY_LENGTH}\n loading={isLoading}\n loadingLabel=\"Searching agencies…\"\n itemToStringLabel={(agency: Agency) => agency.name}\n isItemEqualToValue={(a: Agency, b: Agency) => a.id === b.id}\n onInputValueChange={onInputValueChange}>\n <Combobox.Input placeholder=\"Search agencies\" aria-label=\"Search agencies\" />\n <Combobox.Content>\n {isLoading && results.length === 0 && <SkeletonRows />}\n <Combobox.Empty>No agencies found</Combobox.Empty>\n <Combobox.List>\n {(agency: Agency) => (\n <Combobox.Item key={agency.id} value={agency}>\n {agency.name}\n </Combobox.Item>\n )}\n </Combobox.List>\n </Combobox.Content>\n </Combobox.Root>\n );\n};",
|
|
2887
|
+
"description": "The same search without Suspense, for a consumer that gets a `loading` flag from\nits data layer instead: `filter={null}`, the rows arrive through `filteredItems`,\nand the flag goes to `Root` as `loading`. That is all the wiring the wait needs:\n`Content` is marked busy, `loadingLabel` is announced once when the request\nstarts, and `Empty` holds back \"no results\" until the answer is in. Placeholder\nrows show only while there is nothing to show yet, hidden from assistive\ntechnology since the label already speaks for them; after that, the previous\nrows stay until the new ones replace them. A request that is no longer the\nlatest is dropped.\n\n`minInputLength` keeps the list shut until two characters are typed — focusing\nthe field opens nothing, and deleting back under the minimum closes it — and\nno request goes out for a shorter query either.",
|
|
2888
|
+
"summary": "API search that waits for two characters and announces its loading state"
|
|
2849
2889
|
},
|
|
2850
2890
|
{
|
|
2851
2891
|
"id": "components-combobox--inside-field-text",
|
|
@@ -7133,8 +7173,8 @@
|
|
|
7133
7173
|
{
|
|
7134
7174
|
"id": "components-label--optional",
|
|
7135
7175
|
"name": "Optional",
|
|
7136
|
-
"snippet": "const Optional = () => <Label optional>Phone number</Label
|
|
7137
|
-
"description": "Appends a muted \" (optional)\" suffix for fields that can be left blank.",
|
|
7176
|
+
"snippet": "const Optional = () => <>\n <Label optional htmlFor=\"phone\">Phone number</Label>\n <input id=\"phone\" type=\"tel\" className={inputRecipe()} />\n</>;",
|
|
7177
|
+
"description": "Appends a muted \" (optional)\" suffix for fields that can be left blank. The\nsuffix is real text, so it is part of the control's accessible name.",
|
|
7138
7178
|
"summary": "Optional field with a muted suffix"
|
|
7139
7179
|
},
|
|
7140
7180
|
{
|
|
@@ -9867,6 +9907,6 @@
|
|
|
9867
9907
|
},
|
|
9868
9908
|
"meta": {
|
|
9869
9909
|
"docgen": "react-component-meta",
|
|
9870
|
-
"durationMs":
|
|
9910
|
+
"durationMs": 3150
|
|
9871
9911
|
}
|
|
9872
9912
|
}
|
package/package.json
CHANGED
|
@@ -87,6 +87,26 @@ export type ComboboxRootProps<Value, Multiple extends boolean | undefined, Item>
|
|
|
87
87
|
* focus.
|
|
88
88
|
*/
|
|
89
89
|
minInputLength?: number;
|
|
90
|
+
/**
|
|
91
|
+
* Whether the options are being fetched. Once the list has been open and
|
|
92
|
+
* loading for half a second, `loadingLabel` is announced once: sooner, a
|
|
93
|
+
* screen reader would cut it off to echo the key just typed, and a faster
|
|
94
|
+
* answer has no wait to announce. `Content` is marked `aria-busy`, and
|
|
95
|
+
* `Empty` shows nothing, so "no results" is not read out before the results
|
|
96
|
+
* arrive. The announcement comes from a visually hidden live region the root
|
|
97
|
+
* renders next to the field, so it is in place before the list opens. On a search
|
|
98
|
+
* against an API, pass it from the first render, as `false` while idle: a root
|
|
99
|
+
* that leaves it out gets no live region. A list filtered in memory never
|
|
100
|
+
* waits and leaves it out. While loading with no rows yet, the surface shows
|
|
101
|
+
* whatever placeholder `Content` holds — `Empty` stays quiet.
|
|
102
|
+
*/
|
|
103
|
+
loading?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* What a screen reader hears when `loading` turns `true`. Announced only; any
|
|
106
|
+
* loading visuals — placeholder rows, a spinner — are yours to render inside
|
|
107
|
+
* `Content`, hidden from assistive technology. Defaults to `'Loading…'`.
|
|
108
|
+
*/
|
|
109
|
+
loadingLabel?: string;
|
|
90
110
|
};
|
|
91
111
|
/**
|
|
92
112
|
* Root of a combobox: a text input that filters a list of options and writes the
|
|
@@ -99,8 +119,9 @@ export type ComboboxRootProps<Value, Multiple extends boolean | undefined, Item>
|
|
|
99
119
|
* select.
|
|
100
120
|
*
|
|
101
121
|
* Pass the options as `items`. For a list that comes from the server, set
|
|
102
|
-
* `filter={null}`, hand the already-filtered rows to `filteredItems`,
|
|
103
|
-
* them from `onInputValueChange
|
|
122
|
+
* `filter={null}`, hand the already-filtered rows to `filteredItems`, request
|
|
123
|
+
* them from `onInputValueChange`, and pass the request's state as `loading`:
|
|
124
|
+
* the combobox announces the wait and marks the list busy on its own.
|
|
104
125
|
*
|
|
105
126
|
* Every Base UI root prop is accepted and forwarded — `items`, `filter`,
|
|
106
127
|
* `value`, `onValueChange` and so on. `open` stays the consumer's to control;
|
|
@@ -131,7 +152,7 @@ export type ComboboxRootProps<Value, Multiple extends boolean | undefined, Item>
|
|
|
131
152
|
* ```
|
|
132
153
|
*/
|
|
133
154
|
export declare const Root: {
|
|
134
|
-
<Value, Multiple extends boolean | undefined = false, Item = Value>({ minInputLength, open: openProp, defaultOpen, onOpenChange, onOpenChangeComplete, onInputValueChange, ...props }: ComboboxRootProps<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
155
|
+
<Value, Multiple extends boolean | undefined = false, Item = Value>({ minInputLength, loading, loadingLabel, open: openProp, defaultOpen, onOpenChange, onOpenChangeComplete, onInputValueChange, children, ...props }: ComboboxRootProps<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
135
156
|
displayName: string;
|
|
136
157
|
};
|
|
137
158
|
type InputProps = Omit<ComponentPropsWithRef<typeof ComboboxPrimitive.Input>, 'size'> & {
|
|
@@ -223,11 +244,14 @@ type ContentProps = ComponentPropsWithRef<typeof ComboboxPrimitive.Popup> & Pick
|
|
|
223
244
|
* one sits under a focused input whose ring is already two near-black pixels, and
|
|
224
245
|
* at 8 the two borders fight.
|
|
225
246
|
*
|
|
247
|
+
* Under a root that passes `loading`, the surface is `aria-busy` while `loading`
|
|
248
|
+
* is `true`; the root announces the wait. An `aria-busy` passed here wins.
|
|
249
|
+
*
|
|
226
250
|
* @summary Floating surface anchored to the input, holding the list
|
|
227
251
|
* @dataAttribute {string} data-slot - Always set to "combobox-content"
|
|
228
252
|
*/
|
|
229
253
|
export declare const Content: {
|
|
230
|
-
({ className, side, align, sideOffset, alignOffset, anchor, collisionPadding, ...props }: ContentProps): import("react/jsx-runtime").JSX.Element;
|
|
254
|
+
({ className, side, align, sideOffset, alignOffset, anchor, collisionPadding, children, ...props }: ContentProps): import("react/jsx-runtime").JSX.Element;
|
|
231
255
|
displayName: string;
|
|
232
256
|
};
|
|
233
257
|
type ListProps = ComponentPropsWithRef<typeof ComboboxPrimitive.List>;
|
|
@@ -270,21 +294,26 @@ type EmptyProps = ComponentPropsWithRef<typeof ComboboxPrimitive.Empty>;
|
|
|
270
294
|
/**
|
|
271
295
|
* Shown in place of the list when nothing matches, and announced politely. It
|
|
272
296
|
* needs `items` on `Root` to know the list is empty, and it must stay mounted —
|
|
273
|
-
* change its children rather than rendering it conditionally.
|
|
297
|
+
* change its children rather than rendering it conditionally. While the root is
|
|
298
|
+
* `loading` it shows nothing: the list is empty because the results have not
|
|
299
|
+
* arrived yet, not because there are none. With no rows to show either, the
|
|
300
|
+
* surface would open as an empty frame, so render placeholder rows inside
|
|
301
|
+
* `Content` for the wait.
|
|
274
302
|
*
|
|
275
303
|
* @summary Message shown when no item matches the query
|
|
276
304
|
* @dataAttribute {string} data-slot - Always set to "combobox-empty"
|
|
277
305
|
*/
|
|
278
306
|
export declare const Empty: {
|
|
279
|
-
({ className, ...props }: EmptyProps): import("react/jsx-runtime").JSX.Element;
|
|
307
|
+
({ className, children, ...props }: EmptyProps): import("react/jsx-runtime").JSX.Element;
|
|
280
308
|
displayName: string;
|
|
281
309
|
};
|
|
282
310
|
type StatusProps = ComponentPropsWithRef<typeof ComboboxPrimitive.Status>;
|
|
283
311
|
/**
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
312
|
+
* A politely announced message about the list. For the wait on a remote search,
|
|
313
|
+
* pass `loading` to `Root` instead: it announces and marks the surface busy with
|
|
314
|
+
* nothing else wired. Reach for `Status` for any other message — a count of
|
|
315
|
+
* results, an error from the request — and keep it mounted, swapping its
|
|
316
|
+
* children: a live region that appears already filled in is often skipped.
|
|
288
317
|
*
|
|
289
318
|
* @summary Politely announced status message for an async list
|
|
290
319
|
* @dataAttribute {string} data-slot - Always set to "combobox-status"
|
package/src/combobox/combobox.js
CHANGED
|
@@ -8,11 +8,11 @@ import { InputGroup as a } from "../input-group/index.js";
|
|
|
8
8
|
import { InputSearch as o } from "../input-search/input-search.js";
|
|
9
9
|
import { IconCancel as s, IconCheck as c, IconKeyboardArrowDown as l, IconSearch as u } from "./icons.js";
|
|
10
10
|
import { tv as d } from "tailwind-variants";
|
|
11
|
-
import { createContext as f, use as p,
|
|
12
|
-
import { jsx as
|
|
13
|
-
import { Combobox as
|
|
11
|
+
import { createContext as f, use as p, useEffect as m, useRef as h, useState as g } from "react";
|
|
12
|
+
import { jsx as _, jsxs as v } from "react/jsx-runtime";
|
|
13
|
+
import { Combobox as y } from "@base-ui/react/combobox";
|
|
14
14
|
//#region src/combobox/combobox.tsx
|
|
15
|
-
var
|
|
15
|
+
var b = d({ slots: {
|
|
16
16
|
action: [
|
|
17
17
|
"flex size-6 shrink-0 cursor-pointer items-center justify-center self-center rounded-sm",
|
|
18
18
|
"[&>svg>path]:fill-icon-input-default hover:[&>svg>path]:fill-icon-default-base-primary",
|
|
@@ -48,144 +48,170 @@ var y = d({ slots: {
|
|
|
48
48
|
"group-data-disabled/item:data-selected:bg-bg-checkbox-disabled"
|
|
49
49
|
],
|
|
50
50
|
message: ["mx-2 my-px px-3 py-2 text-sm text-text-default-base-tertiary", "empty:m-0 empty:p-0"]
|
|
51
|
-
} }),
|
|
52
|
-
let
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
} }), x = b(), S = f(!1), C = f(void 0), w = 500, T = (e, t) => {
|
|
52
|
+
let [n, r] = g(!1);
|
|
53
|
+
return m(() => {
|
|
54
|
+
if (!e) return;
|
|
55
|
+
let t = setTimeout(() => r(!0), w);
|
|
56
|
+
return () => {
|
|
57
|
+
clearTimeout(t), r(!1);
|
|
58
|
+
};
|
|
59
|
+
}, [e]), e && n ? t : null;
|
|
60
|
+
}, E = ({ minInputLength: e = 0, loading: t, loadingLabel: n = "Loading…", open: r, defaultOpen: i = !1, onOpenChange: a, onOpenChangeComplete: o, onInputValueChange: s, children: c, ...l }) => {
|
|
61
|
+
let u = !!l.multiple, [d, f] = g(i), p = h(String(l.inputValue ?? l.defaultInputValue ?? ""));
|
|
62
|
+
l.inputValue !== void 0 && (p.current = String(l.inputValue));
|
|
63
|
+
let m = (t) => t.trim().length < e, b = h(!1), x = h(!1), w = (e, t) => {
|
|
64
|
+
if (e && m(p.current)) {
|
|
56
65
|
t.cancel();
|
|
57
66
|
return;
|
|
58
67
|
}
|
|
59
|
-
|
|
60
|
-
},
|
|
61
|
-
|
|
62
|
-
},
|
|
63
|
-
if (
|
|
64
|
-
|
|
68
|
+
b.current = !1, a?.(e, t), u && !e && t.reason === "item-press" && t.cancel(), t.isCanceled || f(e);
|
|
69
|
+
}, E = (e) => {
|
|
70
|
+
o?.(e), !e && b.current && (b.current = !1, x.current = !0, queueMicrotask(() => x.current = !1));
|
|
71
|
+
}, D = (e, t) => {
|
|
72
|
+
if (x.current) {
|
|
73
|
+
x.current = !1, t.cancel();
|
|
65
74
|
return;
|
|
66
75
|
}
|
|
67
|
-
|
|
68
|
-
},
|
|
69
|
-
return /* @__PURE__ */
|
|
70
|
-
value:
|
|
71
|
-
children: /* @__PURE__ */
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
p.current = e, s?.(e, t), m(e) && r === void 0 && d && (b.current = !0, f(!1));
|
|
77
|
+
}, O = r ?? (e > 0 ? d : void 0), k = T(!!t && (r ?? d), n);
|
|
78
|
+
return /* @__PURE__ */ _(S, {
|
|
79
|
+
value: u,
|
|
80
|
+
children: /* @__PURE__ */ _(C, {
|
|
81
|
+
value: t,
|
|
82
|
+
children: /* @__PURE__ */ v(y.Root, {
|
|
83
|
+
open: O,
|
|
84
|
+
defaultOpen: i,
|
|
85
|
+
onOpenChange: w,
|
|
86
|
+
onOpenChangeComplete: E,
|
|
87
|
+
onInputValueChange: D,
|
|
88
|
+
...l,
|
|
89
|
+
children: [c, t !== void 0 && /* @__PURE__ */ _(y.Status, {
|
|
90
|
+
"data-slot": "combobox-loading",
|
|
91
|
+
className: "sr-only",
|
|
92
|
+
children: k
|
|
93
|
+
})]
|
|
94
|
+
})
|
|
78
95
|
})
|
|
79
96
|
});
|
|
80
97
|
};
|
|
81
|
-
|
|
82
|
-
var
|
|
98
|
+
E.displayName = "Combobox.Root";
|
|
99
|
+
var D = /* @__PURE__ */ new Set([
|
|
83
100
|
"value",
|
|
84
101
|
"defaultValue",
|
|
85
102
|
"onChange"
|
|
86
|
-
]),
|
|
87
|
-
let i = p(r), a = n(), o = i ? Object.fromEntries(Object.entries(i).filter(([e]) => !
|
|
103
|
+
]), O = (e) => {
|
|
104
|
+
let i = p(r), a = n(), o = i ? Object.fromEntries(Object.entries(i).filter(([e]) => !D.has(e))) : null, s = !("aria-label" in e || "aria-labelledby" in e) && a ? { "aria-labelledby": a.labelId } : null;
|
|
88
105
|
return t({
|
|
89
106
|
...o,
|
|
90
107
|
...s
|
|
91
108
|
}, e);
|
|
92
|
-
},
|
|
93
|
-
let { className: m, size: h = "md", ...
|
|
94
|
-
return t === "search" && n && !
|
|
95
|
-
render: /* @__PURE__ */
|
|
109
|
+
}, k = ({ variant: t = "search", showClear: n = t === "search", clearLabel: c = "Clear", triggerLabel: d = "Show options", ...f }) => {
|
|
110
|
+
let { className: m, size: h = "md", ...g } = O(f), b = p(S);
|
|
111
|
+
return t === "search" && n && !b ? /* @__PURE__ */ _(y.InputGroup, {
|
|
112
|
+
render: /* @__PURE__ */ _("div", {}),
|
|
96
113
|
"data-slot": "combobox-field",
|
|
97
|
-
children: /* @__PURE__ */
|
|
114
|
+
children: /* @__PURE__ */ _(r, {
|
|
98
115
|
value: null,
|
|
99
|
-
children: /* @__PURE__ */
|
|
116
|
+
children: /* @__PURE__ */ _(y.Input, {
|
|
100
117
|
"data-slot": "combobox-input",
|
|
101
118
|
className: m,
|
|
102
|
-
...
|
|
103
|
-
render: (e) => /* @__PURE__ */
|
|
119
|
+
...g,
|
|
120
|
+
render: (e) => /* @__PURE__ */ _(o, {
|
|
104
121
|
...e,
|
|
105
122
|
size: h,
|
|
106
123
|
clearLabel: c
|
|
107
124
|
})
|
|
108
125
|
})
|
|
109
126
|
})
|
|
110
|
-
}) : /* @__PURE__ */
|
|
111
|
-
render: /* @__PURE__ */
|
|
127
|
+
}) : /* @__PURE__ */ v(y.InputGroup, {
|
|
128
|
+
render: /* @__PURE__ */ _(a.Root, {}),
|
|
112
129
|
"data-slot": "combobox-field",
|
|
113
130
|
className: t === "plain" ? "px-4" : void 0,
|
|
114
131
|
children: [
|
|
115
|
-
t === "search" && /* @__PURE__ */
|
|
116
|
-
/* @__PURE__ */
|
|
132
|
+
t === "search" && /* @__PURE__ */ _(a.Addon, { children: /* @__PURE__ */ _(u, {}) }),
|
|
133
|
+
/* @__PURE__ */ _(y.Input, {
|
|
117
134
|
"data-slot": "combobox-input",
|
|
118
135
|
"data-size": h,
|
|
119
136
|
className: e(i({ size: h }), m),
|
|
120
|
-
...
|
|
137
|
+
...g
|
|
121
138
|
}),
|
|
122
|
-
n && !
|
|
139
|
+
n && !b && /* @__PURE__ */ _(y.Clear, {
|
|
123
140
|
"data-slot": "combobox-clear",
|
|
124
141
|
"aria-label": c,
|
|
125
|
-
className:
|
|
126
|
-
children: /* @__PURE__ */
|
|
142
|
+
className: x.action(),
|
|
143
|
+
children: /* @__PURE__ */ _(s, {})
|
|
127
144
|
}),
|
|
128
|
-
t === "select" && !
|
|
145
|
+
t === "select" && !b && /* @__PURE__ */ _(y.Trigger, {
|
|
129
146
|
"data-slot": "combobox-trigger",
|
|
130
147
|
"aria-label": d,
|
|
131
|
-
className: e(
|
|
132
|
-
children: /* @__PURE__ */
|
|
148
|
+
className: e(x.action(), x.trigger(), n && x.triggerReplaced()),
|
|
149
|
+
children: /* @__PURE__ */ _(l, {})
|
|
133
150
|
})
|
|
134
151
|
]
|
|
135
152
|
});
|
|
136
153
|
};
|
|
137
|
-
|
|
138
|
-
var
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
k.displayName = "Combobox.Input";
|
|
155
|
+
var A = ({ className: t, side: n = "bottom", align: r = "start", sideOffset: i = 12, alignOffset: a, anchor: o, collisionPadding: s = 8, children: c, ...l }) => {
|
|
156
|
+
let u = p(C);
|
|
157
|
+
return /* @__PURE__ */ _(y.Portal, { children: /* @__PURE__ */ _(y.Positioner, {
|
|
158
|
+
side: n,
|
|
159
|
+
align: r,
|
|
160
|
+
sideOffset: i,
|
|
161
|
+
alignOffset: a,
|
|
162
|
+
anchor: o,
|
|
163
|
+
collisionPadding: s,
|
|
164
|
+
className: "isolate z-(--z-index-top-layer) pointer-events-auto",
|
|
165
|
+
children: /* @__PURE__ */ _(y.Popup, {
|
|
166
|
+
"data-slot": "combobox-content",
|
|
167
|
+
"aria-busy": u || void 0,
|
|
168
|
+
className: e(x.content(), t),
|
|
169
|
+
...l,
|
|
170
|
+
children: c
|
|
171
|
+
})
|
|
172
|
+
}) });
|
|
173
|
+
};
|
|
174
|
+
A.displayName = "Combobox.Content";
|
|
175
|
+
var j = ({ className: t, ...n }) => {
|
|
154
176
|
let r = "aria-label" in n || "aria-labelledby" in n;
|
|
155
|
-
return /* @__PURE__ */
|
|
177
|
+
return /* @__PURE__ */ _(y.List, {
|
|
156
178
|
"data-slot": "combobox-list",
|
|
157
179
|
"aria-label": r ? void 0 : "Suggestions",
|
|
158
|
-
className: e(
|
|
180
|
+
className: e(x.list(), t),
|
|
159
181
|
...n
|
|
160
182
|
});
|
|
161
183
|
};
|
|
162
|
-
|
|
163
|
-
var
|
|
164
|
-
let i = p(
|
|
165
|
-
return /* @__PURE__ */
|
|
184
|
+
j.displayName = "Combobox.List";
|
|
185
|
+
var M = ({ className: t, children: n, ...r }) => {
|
|
186
|
+
let i = p(S);
|
|
187
|
+
return /* @__PURE__ */ v(y.Item, {
|
|
166
188
|
"data-slot": "combobox-item",
|
|
167
|
-
className: e(
|
|
189
|
+
className: e(x.item(), t),
|
|
168
190
|
...r,
|
|
169
|
-
children: [i && /* @__PURE__ */
|
|
191
|
+
children: [i && /* @__PURE__ */ _(y.ItemIndicator, {
|
|
170
192
|
keepMounted: !0,
|
|
171
193
|
"data-slot": "combobox-item-indicator",
|
|
172
|
-
className:
|
|
173
|
-
children: /* @__PURE__ */
|
|
194
|
+
className: x.indicator(),
|
|
195
|
+
children: /* @__PURE__ */ _(c, { className: "size-3.5" })
|
|
174
196
|
}), n]
|
|
175
197
|
});
|
|
176
198
|
};
|
|
177
|
-
|
|
178
|
-
var
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
199
|
+
M.displayName = "Combobox.Item";
|
|
200
|
+
var N = ({ className: t, children: n, ...r }) => {
|
|
201
|
+
let i = p(C);
|
|
202
|
+
return /* @__PURE__ */ _(y.Empty, {
|
|
203
|
+
"data-slot": "combobox-empty",
|
|
204
|
+
className: e(x.message(), t),
|
|
205
|
+
...r,
|
|
206
|
+
children: i ? null : n
|
|
207
|
+
});
|
|
208
|
+
};
|
|
209
|
+
N.displayName = "Combobox.Empty";
|
|
210
|
+
var P = ({ className: t, ...n }) => /* @__PURE__ */ _(y.Status, {
|
|
185
211
|
"data-slot": "combobox-status",
|
|
186
|
-
className: e(
|
|
212
|
+
className: e(x.message(), t),
|
|
187
213
|
...n
|
|
188
214
|
});
|
|
189
|
-
|
|
215
|
+
P.displayName = "Combobox.Status";
|
|
190
216
|
//#endregion
|
|
191
|
-
export {
|
|
217
|
+
export { A as Content, N as Empty, k as Input, M as Item, j as List, E as Root, P as Status, b as comboboxRecipe };
|
package/src/combobox/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { comboboxRecipe } from './combobox';
|
|
|
2
2
|
export type { ComboboxRootProps } from './combobox';
|
|
3
3
|
export declare const Combobox: {
|
|
4
4
|
Root: {
|
|
5
|
-
<Value, Multiple extends boolean | undefined = false, Item = Value>({ minInputLength, open: openProp, defaultOpen, onOpenChange, onOpenChangeComplete, onInputValueChange, ...props }: import('./combobox').ComboboxRootProps<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
5
|
+
<Value, Multiple extends boolean | undefined = false, Item = Value>({ minInputLength, loading, loadingLabel, open: openProp, defaultOpen, onOpenChange, onOpenChangeComplete, onInputValueChange, children, ...props }: import('./combobox').ComboboxRootProps<Value, Multiple, Item>): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
displayName: string;
|
|
7
7
|
};
|
|
8
8
|
Input: {
|
|
@@ -16,7 +16,7 @@ export declare const Combobox: {
|
|
|
16
16
|
displayName: string;
|
|
17
17
|
};
|
|
18
18
|
Content: {
|
|
19
|
-
({ className, side, align, sideOffset, alignOffset, anchor, collisionPadding, ...props }: Omit<import('@base-ui/react/combobox').ComboboxPopupProps, "ref"> & import('react').RefAttributes<HTMLDivElement> & Pick<Omit<import('@base-ui/react/combobox').ComboboxPositionerProps, "ref"> & import('react').RefAttributes<HTMLDivElement>, "anchor" | "align" | "side" | "sideOffset" | "alignOffset" | "collisionPadding">): import("react/jsx-runtime").JSX.Element;
|
|
19
|
+
({ className, side, align, sideOffset, alignOffset, anchor, collisionPadding, children, ...props }: Omit<import('@base-ui/react/combobox').ComboboxPopupProps, "ref"> & import('react').RefAttributes<HTMLDivElement> & Pick<Omit<import('@base-ui/react/combobox').ComboboxPositionerProps, "ref"> & import('react').RefAttributes<HTMLDivElement>, "anchor" | "align" | "side" | "sideOffset" | "alignOffset" | "collisionPadding">): import("react/jsx-runtime").JSX.Element;
|
|
20
20
|
displayName: string;
|
|
21
21
|
};
|
|
22
22
|
List: {
|
|
@@ -28,7 +28,7 @@ export declare const Combobox: {
|
|
|
28
28
|
displayName: string;
|
|
29
29
|
};
|
|
30
30
|
Empty: {
|
|
31
|
-
({ className, ...props }: Omit<import('@base-ui/react/combobox').ComboboxEmptyProps, "ref"> & import('react').RefAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
({ className, children, ...props }: Omit<import('@base-ui/react/combobox').ComboboxEmptyProps, "ref"> & import('react').RefAttributes<HTMLDivElement>): import("react/jsx-runtime").JSX.Element;
|
|
32
32
|
displayName: string;
|
|
33
33
|
};
|
|
34
34
|
Status: {
|
package/src/label/label.d.ts
CHANGED
|
@@ -1,36 +1,48 @@
|
|
|
1
1
|
import { ComponentPropsWithRef } from 'react';
|
|
2
2
|
import { VariantProps } from 'tailwind-variants';
|
|
3
3
|
import * as LabelPrimitive from '@radix-ui/react-label';
|
|
4
|
-
/** Style recipe for Label. Slots: `root`, `text`, `required`. */
|
|
4
|
+
/** Style recipe for Label. Slots: `root`, `text`, `optional`, `required`. */
|
|
5
5
|
export declare const labelRecipe: import('tailwind-variants').TVReturnType<{
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
text
|
|
6
|
+
[key: string]: {
|
|
7
|
+
[key: string]: import('tailwind-merge').ClassNameValue | {
|
|
8
|
+
text?: import('tailwind-merge').ClassNameValue;
|
|
9
|
+
root?: import('tailwind-merge').ClassNameValue;
|
|
10
|
+
required?: import('tailwind-merge').ClassNameValue;
|
|
11
|
+
optional?: import('tailwind-merge').ClassNameValue;
|
|
9
12
|
};
|
|
10
13
|
};
|
|
11
|
-
}
|
|
14
|
+
} | {
|
|
15
|
+
[x: string]: {
|
|
16
|
+
[x: string]: import('tailwind-merge').ClassNameValue | {
|
|
17
|
+
text?: import('tailwind-merge').ClassNameValue;
|
|
18
|
+
root?: import('tailwind-merge').ClassNameValue;
|
|
19
|
+
required?: import('tailwind-merge').ClassNameValue;
|
|
20
|
+
optional?: import('tailwind-merge').ClassNameValue;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
} | {}, {
|
|
12
24
|
root: string;
|
|
13
25
|
text: string;
|
|
26
|
+
optional: string;
|
|
14
27
|
required: string;
|
|
15
28
|
}, undefined, {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
text
|
|
29
|
+
[key: string]: {
|
|
30
|
+
[key: string]: import('tailwind-merge').ClassNameValue | {
|
|
31
|
+
text?: import('tailwind-merge').ClassNameValue;
|
|
32
|
+
root?: import('tailwind-merge').ClassNameValue;
|
|
33
|
+
required?: import('tailwind-merge').ClassNameValue;
|
|
34
|
+
optional?: import('tailwind-merge').ClassNameValue;
|
|
19
35
|
};
|
|
20
36
|
};
|
|
21
|
-
}, {
|
|
37
|
+
} | {}, {
|
|
22
38
|
root: string;
|
|
23
39
|
text: string;
|
|
40
|
+
optional: string;
|
|
24
41
|
required: string;
|
|
25
|
-
}, import('tailwind-variants').TVReturnType<{
|
|
26
|
-
optional: {
|
|
27
|
-
true: {
|
|
28
|
-
text: string;
|
|
29
|
-
};
|
|
30
|
-
};
|
|
31
|
-
}, {
|
|
42
|
+
}, import('tailwind-variants').TVReturnType<unknown, {
|
|
32
43
|
root: string;
|
|
33
44
|
text: string;
|
|
45
|
+
optional: string;
|
|
34
46
|
required: string;
|
|
35
47
|
}, undefined, unknown, unknown, undefined>>;
|
|
36
48
|
export type LabelVariants = VariantProps<typeof labelRecipe>;
|
package/src/label/label.js
CHANGED
|
@@ -2,33 +2,33 @@
|
|
|
2
2
|
import { cn as e } from "../../lib/utils.js";
|
|
3
3
|
import { useLabelContext as t } from "./context.js";
|
|
4
4
|
import { tv as n } from "tailwind-variants";
|
|
5
|
-
import {
|
|
6
|
-
import * as
|
|
5
|
+
import { Fragment as r, jsx as i, jsxs as a } from "react/jsx-runtime";
|
|
6
|
+
import * as o from "@radix-ui/react-label";
|
|
7
7
|
//#region src/label/label.tsx
|
|
8
|
-
var
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}), s = (n) => {
|
|
17
|
-
let { className: s, children: c, optional: l = !1, required: u = !1, ...d } = t(n), f = o({ optional: l && !u });
|
|
18
|
-
return /* @__PURE__ */ i(a.Root, {
|
|
8
|
+
var s = n({ slots: {
|
|
9
|
+
root: "flex flex-wrap gap-1 py-0.25 text-sm font-semibold text-text-input-normal",
|
|
10
|
+
text: "align-middle",
|
|
11
|
+
optional: "font-normal text-text-input-placeholder",
|
|
12
|
+
required: "align-middle text-text-input-destructive"
|
|
13
|
+
} }), c = (n) => {
|
|
14
|
+
let { className: c, children: l, optional: u = !1, required: d = !1, ...f } = t(n), p = u && !d, m = s();
|
|
15
|
+
return /* @__PURE__ */ a(o.Root, {
|
|
19
16
|
"data-slot": "label",
|
|
20
|
-
className: e(
|
|
21
|
-
...
|
|
22
|
-
children: [/* @__PURE__ */
|
|
23
|
-
className:
|
|
24
|
-
children:
|
|
25
|
-
|
|
17
|
+
className: e(m.root(), c),
|
|
18
|
+
...f,
|
|
19
|
+
children: [/* @__PURE__ */ a("span", {
|
|
20
|
+
className: m.text(),
|
|
21
|
+
children: [l, p && /* @__PURE__ */ a(r, { children: [" ", /* @__PURE__ */ i("span", {
|
|
22
|
+
className: m.optional(),
|
|
23
|
+
children: "(optional)"
|
|
24
|
+
})] })]
|
|
25
|
+
}), d && /* @__PURE__ */ i("span", {
|
|
26
26
|
"aria-hidden": !0,
|
|
27
|
-
className:
|
|
27
|
+
className: m.required(),
|
|
28
28
|
children: "*"
|
|
29
29
|
})]
|
|
30
30
|
});
|
|
31
31
|
};
|
|
32
|
-
|
|
32
|
+
c.displayName = "Label";
|
|
33
33
|
//#endregion
|
|
34
|
-
export {
|
|
34
|
+
export { c as Label, s as labelRecipe };
|