plass-ui 1.8.1 → 1.8.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/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@
4
4
 
5
5
  ## vNext (2026--)
6
6
 
7
+ ## 1.8.2 (2026-10-09)
8
+
9
+ ### Breaking changes
10
+
11
+ - **Escape no longer empties a `PlCombobox` whose list is closed.** One stray Escape took every chip off a `multiple` field, or the chosen value off a single one, and a caller could not stop it. The value now stays, and the key goes on to whatever the field sits in, so a `PlModal` round the field closes. Escape on an open list still closes it and lets go of the query. Pass `clearOnEscape` to have Escape empty the field as before.
12
+ - **`PlCombobox` calls `onValueChange`, `onInputValueChange` and `onOpenChange` with Base UI's event details as a second argument.** A caller could not tell what had changed the value, so an Escape and a press of the clear button looked the same. The second argument, typed `PlComboboxChangeEventDetails`, carries the `reason` (`'item-press'`, `'chip-remove-press'`, `'clear-press'`, `'escape-key'` and the rest) and the DOM `event`, and its `cancel()` turns the change away, so the field keeps what it held. A handler that takes one argument is unchanged. A test that checks a call with `toHaveBeenCalledWith(value)` now needs `expect.anything()` after the value.
13
+
14
+ ### Added
15
+
16
+ - **`PlCombobox` takes `filter`, so a list a server has already searched is shown as it came.** Base UI filtered every row again by its label, so a row the server matched on another spelling, such as a city found by its English name and labelled in its own language, was hidden. `filter={null}` keeps every row as `items` gives it, and a function decides which rows a query keeps. The row that offers what was typed always stays.
17
+ - **`PlCombobox` takes `autoHighlight`.** The first row lit up only as the query changed and was not a setting. `true` stays the default, and now lights the first of the rows that arrive after the query changed as well, so a list a server fills a moment later is taken from with Enter. `'always'` also lights the first row whenever the open list has rows and none is lit, as when it opens with nothing typed, and `false` lights nothing until an arrow key or the pointer does.
18
+ - **A `multiple` `PlCombobox` takes a readonly array as `value` and `defaultValue`.** A caller holding the chosen values in a readonly array, or one written `as const`, had to copy it before handing it in, since TypeScript refused it for the mutable array the props asked for. The field never writes into it, and Base UI 1.9.0 takes one as it is.
19
+ - **A `PlComboboxOption` takes `content`, which its row draws in place of the label.** A row could only show its label, so a thumbnail or a second line had nowhere to go. The label is still what is filtered, written into the input and put on the chip.
20
+
21
+ ### Changed
22
+
23
+ - **`plass-ui` depends on `@base-ui/react` `^1.9.0`.** The fixes in Base UI 1.9.0 reach these components: a `PlCombobox` lights the first of the rows that arrive after the query changed and leaves no stale focus on a chip once the input has it back, a `PlSlider` ends a drag on `pointercancel` and `touchcancel`, and a `PlToastProvider` keeps a toast's timer paused through overlapping interactions. Base UI 1.9.0 also builds the filtering it adds to its menu into every menu, so a page with a `PlMenu` or a `PlContextMenu` grows by about 9 kB gzipped whether or not anything filters.
24
+ - **Enter on a `PlCombobox` list with no rows keeps the list open and the query in the input.** A list still waiting for its rows, or matching nothing, closed on Enter, which emptied the query in a `multiple` field and put the chosen label back in a single one, so the reader had to type the query again. Enter there now does nothing, and a form round the field is not sent with the list open. A list with rows and none lit still closes on Enter and lets the form be sent.
25
+
26
+ ### Fixed
27
+
28
+ - **A chosen `PlCombobox` value keeps its label once `items` no longer lists it.** A chip, and the text of a single field, read the label off the current `items`, so in a list a server answers, a value the latest query did not find was shown by its value, such as `prague` for Praha. The field now keeps the label each chosen value was last listed with, including one taken from a list that the next query emptied in the same press.
29
+
7
30
  ## 1.8.1 (2026-10-09)
8
31
 
9
32
  ### Breaking changes
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{useDisabled as t,useLabelReference as o}from"../../internal/form.js";import{useDefaults as l}from"../../internal/defaults.js";import{Checkbox as n}from"@base-ui/react/checkbox";import{Field as i}from"@base-ui/react/field";import{controlSlots as s,cx as d,fieldDescriptionClasses as c,focusRingClasses as p,forcedCheckedClasses as h,forcedDisabledCheckedClasses as m,glassClasses as f,hasContent as b,metaTextClasses as u,tickRadiusClasses as k,tickRowTextClasses as g,tickSizeClasses as x,transitionClasses as v}from"../../internal/styles.js";const j=/* @__PURE__ */["relative inline-flex shrink-0 items-center justify-center border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","plass-fill [--p-fill-edge:1px]",v,p].join(" "),y=/* @__PURE__ */["forced-colors:data-[indeterminate]:[background-color:Highlight]","forced-colors:data-[indeterminate]:[border-color:Highlight]","forced-colors:data-[indeterminate]:[color:HighlightText]"].join(" "),N=/* @__PURE__ */[f,"cursor-pointer bg-(--plass-glass) [border-color:var(--plass-border)]","hover:bg-(--plass-glass-hover) hover:[border-color:var(--p-line)]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent] data-[checked]:hover:brightness-105","data-[indeterminate]:[--p-fill-on:1] data-[indeterminate]:text-(--p-on-solid)","data-[indeterminate]:[border-color:transparent]",h,y].join(" "),C=/* @__PURE__ */[f,"cursor-default bg-(--plass-glass) [border-color:var(--plass-border)]","saturate-[0.55]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]","data-[indeterminate]:[--p-fill-on:1] data-[indeterminate]:text-(--p-on-solid)","data-[indeterminate]:[border-color:transparent]",h,y].join(" "),M=/* @__PURE__ */[f,"cursor-not-allowed bg-(--plass-glass) [border-color:var(--plass-border)]","opacity-50 saturate-[0.35]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]","data-[indeterminate]:[--p-fill-on:1] data-[indeterminate]:text-(--p-on-solid)","data-[indeterminate]:[border-color:transparent]",m,"forced-colors:data-[indeterminate]:[background-color:GrayText]","forced-colors:data-[indeterminate]:[color:Canvas]"].join(" "),_=/* @__PURE__ */["flex size-[70%] items-center justify-center","[&_path]:[stroke-dasharray:1] [&_path]:[stroke-dashoffset:0]","[&_path]:[transition:stroke-dashoffset_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[&_path]:[transition-duration:0ms]","data-[unchecked]:[&_path]:[stroke-dashoffset:1]"].join(" ");function CheckMark(){return e("svg",{viewBox:"0 0 12 12",fill:"none","aria-hidden":"true",className:"size-full",children:e("path",{d:"M2 6.2 4.6 8.8 10 3.4",pathLength:1,stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function DashMark(){return e("svg",{viewBox:"0 0 12 12",fill:"none","aria-hidden":"true",className:"size-full",children:e("path",{d:"M2.5 6h7",pathLength:1,stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})}export const PlCheckbox=/* @__PURE__ */r.forwardRef(function PlCheckbox({size:r,color:p,label:h,description:m,error:f,invalid:v,disabled:y=!1,readOnly:w=!1,className:L,classNames:z,style:B,"aria-label":D,"aria-labelledby":H,...R},O){const P=l(),T=t(y),W=o(D,H),E=r??P.size??"md",G=p??P.color??"primary",I=b(f),$=v??I,q=$?"danger":G,A=d(j,x[E],k[E],T?M:w?C:N,z?.control);return a(i.Root,{disabled:T,invalid:$,className:["inline-flex flex-col gap-1 align-top",L??""].filter(Boolean).join(" "),style:{...s(q,0,"solid"),...B},children:[a("div",{className:`flex items-start gap-2 ${g[E]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(n.Root,{ref:O,className:A,disabled:T,readOnly:w,"aria-label":D,"aria-labelledby":W.labelledBy,...R,children:e(n.Indicator,{keepMounted:!0,className:_,children:R.indeterminate?e(DashMark,{}):e(CheckMark,{})})})}),h||m?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[h?e(i.Label,{className:d(T?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",z?.label),children:h}):null,m?e(i.Description,{className:d(c(E),z?.description),children:m}):null]}):null]}),e(i.Error,I?{match:!0,className:d(u[E],"text-(--p-accent)",z?.error),children:f}:{className:d(u[E],"text-(--p-accent)",z?.error)}),W.node]})});
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{useDisabled as t}from"../../internal/form.js";import{useDefaults as o}from"../../internal/defaults.js";import{Checkbox as l}from"@base-ui/react/checkbox";import{Field as n}from"@base-ui/react/field";import{controlSlots as i,cx as s,fieldDescriptionClasses as d,focusRingClasses as c,forcedCheckedClasses as p,forcedDisabledCheckedClasses as h,glassClasses as m,hasContent as f,metaTextClasses as u,tickRadiusClasses as b,tickRowTextClasses as k,tickSizeClasses as g,transitionClasses as x}from"../../internal/styles.js";const v=/* @__PURE__ */["relative inline-flex shrink-0 items-center justify-center border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","plass-fill [--p-fill-edge:1px]",x,c].join(" "),j=/* @__PURE__ */["forced-colors:data-[indeterminate]:[background-color:Highlight]","forced-colors:data-[indeterminate]:[border-color:Highlight]","forced-colors:data-[indeterminate]:[color:HighlightText]"].join(" "),N=/* @__PURE__ */[m,"cursor-pointer bg-(--plass-glass) [border-color:var(--plass-border)]","hover:bg-(--plass-glass-hover) hover:[border-color:var(--p-line)]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent] data-[checked]:hover:brightness-105","data-[indeterminate]:[--p-fill-on:1] data-[indeterminate]:text-(--p-on-solid)","data-[indeterminate]:[border-color:transparent]",p,j].join(" "),y=/* @__PURE__ */[m,"cursor-default bg-(--plass-glass) [border-color:var(--plass-border)]","saturate-[0.55]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]","data-[indeterminate]:[--p-fill-on:1] data-[indeterminate]:text-(--p-on-solid)","data-[indeterminate]:[border-color:transparent]",p,j].join(" "),C=/* @__PURE__ */[m,"cursor-not-allowed bg-(--plass-glass) [border-color:var(--plass-border)]","opacity-50 saturate-[0.35]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]","data-[indeterminate]:[--p-fill-on:1] data-[indeterminate]:text-(--p-on-solid)","data-[indeterminate]:[border-color:transparent]",h,"forced-colors:data-[indeterminate]:[background-color:GrayText]","forced-colors:data-[indeterminate]:[color:Canvas]"].join(" "),M=/* @__PURE__ */["flex size-[70%] items-center justify-center","[&_path]:[stroke-dasharray:1] [&_path]:[stroke-dashoffset:0]","[&_path]:[transition:stroke-dashoffset_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[&_path]:[transition-duration:0ms]","data-[unchecked]:[&_path]:[stroke-dashoffset:1]"].join(" ");function CheckMark(){return e("svg",{viewBox:"0 0 12 12",fill:"none","aria-hidden":"true",className:"size-full",children:e("path",{d:"M2 6.2 4.6 8.8 10 3.4",pathLength:1,stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})}function DashMark(){return e("svg",{viewBox:"0 0 12 12",fill:"none","aria-hidden":"true",className:"size-full",children:e("path",{d:"M2.5 6h7",pathLength:1,stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round"})})}export const PlCheckbox=/* @__PURE__ */r.forwardRef(function PlCheckbox({size:r,color:c,label:p,description:h,error:m,invalid:x,disabled:j=!1,readOnly:_=!1,className:w,classNames:L,style:z,"aria-label":B,"aria-labelledby":D,...H},R){const O=o(),P=t(j),T=r??O.size??"md",W=c??O.color??"primary",E=f(m),G=x??E,I=G?"danger":W,$=s(v,g[T],b[T],P?C:_?y:N,L?.control);return a(n.Root,{disabled:P,invalid:G,className:["inline-flex flex-col gap-1 align-top",w??""].filter(Boolean).join(" "),style:{...i(I,0,"solid"),...z},children:[a("div",{className:`flex items-start gap-2 ${k[T]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(l.Root,{ref:R,className:$,disabled:P,readOnly:_,"aria-label":B,"aria-labelledby":D,...H,children:e(l.Indicator,{keepMounted:!0,className:M,children:H.indeterminate?e(DashMark,{}):e(CheckMark,{})})})}),p||h?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[p?e(n.Label,{className:s(P?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",L?.label),children:p}):null,h?e(n.Description,{className:s(d(T),L?.description),children:h}):null]}):null]}),e(n.Error,E?{match:!0,className:s(u[T],"text-(--p-accent)",L?.error),children:m}:{className:s(u[T],"text-(--p-accent)",L?.error)})]})});
@@ -1,4 +1,5 @@
1
1
  import * as React from 'react';
2
+ import { Combobox as BaseUICombobox } from '@base-ui/react/combobox';
2
3
  import type { PlassElevation, PlassFieldClassNames, PlassHotKeys, PlassFieldLabelPlacement, PlassStyleProps } from '../../types.js';
3
4
  /**
4
5
  * What a combobox's value may be — the same two types a PlSelect submits, and
@@ -16,14 +17,35 @@ export interface PlComboboxOption {
16
17
  *
17
18
  * A `string` rather than a `ReactNode`, which is the one place this differs
18
19
  * from PlSelect: the label is typed against by the filter and written into a
19
- * text input, and neither of those can be done to an element.
20
+ * text input, and neither of those can be done to an element. `content` is
21
+ * where a row draws more than that.
20
22
  */
21
23
  label?: string;
24
+ /**
25
+ * What the row draws in place of its label: a thumbnail, a glyph, a second
26
+ * line. The label is still what is filtered, written into the input and put
27
+ * on the chip, and the content's text is what a screen reader reads for the
28
+ * row, so keep the label's words in it.
29
+ */
30
+ content?: React.ReactNode;
22
31
  /** Unavailable, but still listed — the option exists, it just cannot be picked. */
23
32
  disabled?: boolean;
24
33
  }
25
34
  /** One value, or an array of them, depending on `multiple`. */
26
35
  type Selection<Multiple extends boolean | undefined> = Multiple extends true ? PlComboboxValue[] : PlComboboxValue | null;
36
+ /**
37
+ * What a caller hands in, which with `multiple` may be a readonly array: the
38
+ * field never writes into it, and Base UI takes one as it is.
39
+ */
40
+ type HeldSelection<Multiple extends boolean | undefined> = Multiple extends true ? readonly PlComboboxValue[] : PlComboboxValue | null;
41
+ /**
42
+ * What caused a change, handed to `onValueChange`, `onInputValueChange` and
43
+ * `onOpenChange` as their second argument. It is Base UI's own: `reason` names
44
+ * the cause (`'item-press'`, `'chip-remove-press'`, `'clear-press'`,
45
+ * `'escape-key'` and the rest), `event` is the DOM event behind it, and
46
+ * `cancel()` turns the change away, so the field keeps what it held.
47
+ */
48
+ export type PlComboboxChangeEventDetails = BaseUICombobox.Root.ChangeEventDetails;
27
49
  export interface PlComboboxProps<Multiple extends boolean | undefined = false> extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'children'> {
28
50
  /** @default 'glass' */
29
51
  variant?: PlassStyleProps['variant'];
@@ -52,12 +74,42 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
52
74
  */
53
75
  multiple?: Multiple;
54
76
  /** The chosen value. Use with `onValueChange` for a controlled combobox. */
55
- value?: Selection<Multiple> | null;
77
+ value?: HeldSelection<Multiple> | null;
56
78
  /** The initially chosen value, for an uncontrolled combobox. */
57
- defaultValue?: Selection<Multiple> | null;
58
- onValueChange?: (value: Selection<Multiple>) => void;
79
+ defaultValue?: HeldSelection<Multiple> | null;
80
+ /** Called with the new value, and with what caused the change. */
81
+ onValueChange?: (value: Selection<Multiple>, eventDetails: PlComboboxChangeEventDetails) => void;
59
82
  /** Called as the text in the input changes — the filter query, not the value. */
60
- onInputValueChange?: (inputValue: string) => void;
83
+ onInputValueChange?: (inputValue: string, eventDetails: PlComboboxChangeEventDetails) => void;
84
+ /**
85
+ * Which rows a query keeps. Left out, a row stays while its label contains
86
+ * the query, compared in the runtime's locale. `null` keeps every row as
87
+ * `items` gives it, for a list a server has already searched, which may have
88
+ * matched a row on a spelling its label does not have.
89
+ *
90
+ * Receives the trimmed query, and is not asked about the row that offers
91
+ * what was typed: that row is the query itself, and always stays.
92
+ */
93
+ filter?: ((option: PlComboboxOption, query: string) => boolean) | null;
94
+ /**
95
+ * Whether a row lights up on its own, so Enter takes it without an arrow key
96
+ * first. `true` lights the first row as the query changes, and the first of
97
+ * the rows that arrive after it, for a list filled after the reader stopped
98
+ * typing. `'always'` also lights the first row whenever the open list has
99
+ * rows and none is lit: as it opens with nothing typed, and once the pointer
100
+ * has left it. `false` lights nothing until an arrow key or the pointer
101
+ * does.
102
+ * @default true
103
+ */
104
+ autoHighlight?: boolean | 'always';
105
+ /**
106
+ * Whether Escape with the list closed empties the field. Off by default, so
107
+ * a stray Escape cannot take every chip off, and the key goes on to whatever
108
+ * the field sits in, such as a modal. Escape on an open list closes it
109
+ * either way.
110
+ * @default false
111
+ */
112
+ clearOnEscape?: boolean;
61
113
  /**
62
114
  * Whether a value the list does not contain may be committed.
63
115
  *
@@ -129,7 +181,8 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
129
181
  open?: boolean;
130
182
  /** Whether the popup starts open. */
131
183
  defaultOpen?: boolean;
132
- onOpenChange?: (open: boolean) => void;
184
+ /** Called as the popup opens or closes, and with what caused it. */
185
+ onOpenChange?: (open: boolean, eventDetails: PlComboboxChangeEventDetails) => void;
133
186
  /** Accessible name of the button that opens the list. @default 'Open' */
134
187
  openLabel?: string;
135
188
  /** Accessible name of the clear button. @default 'Clear' */
@@ -154,7 +207,7 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
154
207
  *
155
208
  * With `multiple` the chosen values become PlChips inside the field and the
156
209
  * input goes on filtering after each one. A row taken from a filtered list
157
- * closes the list and empties the text, which is how Base UI 1.8.0 behaves,
210
+ * closes the list and empties the text, which is how Base UI behaves,
158
211
  * and a row taken with nothing typed leaves the list open for the next one.
159
212
  *
160
213
  * Base UI owns everything hard about this: the filtering and its collator, the
@@ -162,5 +215,5 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
162
215
  * navigation across both the list and the chips, and the hidden input that makes
163
216
  * the whole thing submit with a form.
164
217
  */
165
- export declare function PlCombobox<Multiple extends boolean | undefined = false>({ variant, size: sizeProp, color: colorProp, density: densityProp, elevation, items, multiple, value, defaultValue, onValueChange, onInputValueChange, allowCustom, customLabel, clearable, emptyMessage: emptyMessageProp, limit, placeholder, label, labelPlacement: labelPlacementProp, description, error, invalid, startIcon, fullWidth, disabled: disabledProp, readOnly, required, name, open, defaultOpen, onOpenChange, openLabel: openLabelProp, clearLabel: clearLabelProp, removeLabel: removeLabelProp, inputRef, id, className, hotKeys, classNames, style, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }: PlComboboxProps<Multiple>): React.JSX.Element;
218
+ export declare function PlCombobox<Multiple extends boolean | undefined = false>({ variant, size: sizeProp, color: colorProp, density: densityProp, elevation, items, multiple, value, defaultValue, onValueChange, onInputValueChange, filter, autoHighlight, clearOnEscape, allowCustom, customLabel, clearable, emptyMessage: emptyMessageProp, limit, placeholder, label, labelPlacement: labelPlacementProp, description, error, invalid, startIcon, fullWidth, disabled: disabledProp, readOnly, required, name, open, defaultOpen, onOpenChange, openLabel: openLabelProp, clearLabel: clearLabelProp, removeLabel: removeLabelProp, inputRef, id, className, hotKeys, classNames, style, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, ...props }: PlComboboxProps<Multiple>): React.JSX.Element;
166
219
  export {};
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{FadedContext as t,controlNaming as s,useDisabled as r}from"../../internal/form.js";import{useDefaults as n,useRuntimeLocale as i}from"../../internal/defaults.js";import{useLabels as o}from"../../internal/labels.js";import{Combobox as c}from"@base-ui/react/combobox";import{Field as d}from"@base-ui/react/field";import{PlChip as m}from"../chip/PlChip.js";import{CheckIcon as p,ChevronIcon as u,CloseIcon as h,PlusIcon as b}from"../../internal/icons.js";import{hotKeyHandler as f}from"../../internal/keys.js";import{useFieldLight as g}from"../../internal/glow.js";import{FieldNotch as v,floatControlClassName as y,notchShellStyle as x,resolveNotch as w}from"../../internal/notch.js";import{chipRemoveClasses as N,controlHeightClasses as j,controlTextLeadingClasses as C,cx as L,disabledClasses as I,fieldDescriptionClasses as S,fieldReadOnlyClasses as z,fieldRestClasses as _,fieldSlots as O,focusWithinRingClasses as P,forcedHighlightedClasses as V,gapClasses as A,glassClasses as M,hasContent as k,iconClasses as R,metaTextClasses as F,paddingXClasses as T,radiusClasses as $,stackGapClasses as q,surfaceSlots as D,targetClasses as E,transitionClasses as K}from"../../internal/styles.js";const G=/* @__PURE__ */["relative flex w-full cursor-text items-center","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",K,R].join(" "),H=P,W={xs:"min-h-6 py-0",sm:"min-h-8 py-0.5",md:"min-h-10 py-1",lg:"min-h-12 py-1.5",xl:"min-h-14 py-2"},B=/* @__PURE__ */[M,"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain","w-[var(--anchor-width)] border bg-(--plass-glass-press) p-1","[border-color:var(--plass-glass-line)]","[box-shadow:var(--plass-shadow-3),var(--plass-gloss-glass)]","[outline:none]","[transition:opacity_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),J=/* @__PURE__ */["relative flex cursor-pointer items-center gap-2 select-none","rounded-(--plass-radius-xs) py-1.5 pe-2 ps-7",K,"data-[highlighted]:bg-(--p-soft-hover) data-[highlighted]:text-(--p-accent)",V,"data-[selected]:font-semibold data-[selected]:text-(--p-accent)","data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50","[outline:none]"].join(" "),Q=/* @__PURE__ */["inline-flex h-[1lh] shrink-0 cursor-pointer items-center justify-center p-0","rounded-(--plass-radius-xs) text-(--plass-muted-fg)","[transition:color_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","enabled:hover:text-(--p-accent)","focus-visible:[outline:2px_solid_var(--p-ring)] focus-visible:[outline-offset:1px]","disabled:cursor-not-allowed"].join(" "),U=/* @__PURE__ */L(E,Q),X=[];function toArray(e){return null==e?X:Array.isArray(e)?e:[e]}export function PlCombobox({variant:P="glass",size:V,color:M,density:R,elevation:E=0,items:K,multiple:X,value:Y,defaultValue:Z,onValueChange:ee,onInputValueChange:ae,allowCustom:le=!0,customLabel:te,clearable:se=!1,emptyMessage:re,limit:ne,placeholder:ie,label:oe,labelPlacement:ce,description:de,error:me,invalid:pe,startIcon:ue,fullWidth:he=!1,disabled:be=!1,readOnly:fe=!1,required:ge=!1,name:ve,open:ye,defaultOpen:xe,onOpenChange:we,openLabel:Ne,clearLabel:je,removeLabel:Ce,inputRef:Le,id:Ie,className:Se,hotKeys:ze,classNames:_e,style:Oe,"aria-label":Pe,"aria-labelledby":Ve,...Ae}){const Me=n(),ke=i(void 0),Re=r(be),Fe=o(),Te=Ne??Fe.open,$e=je??Fe.clear,qe=re??Fe.empty,De=Ce??Fe.removeItem,Ee=V??Me.size??"md",Ke=M??Me.color??"primary",Ge=R??Me.density??"default",He=ce??Me.labelPlacement??"top",{notched:We,float:Be}=w(He,oe,k(ue)),Je=k(me),Qe=pe??Je,Ue=Qe?"danger":Ke,Xe=!0===X,Ye=l.useMemo(()=>K.map(e=>({value:e.value,label:e.label??String(e.value),disabled:e.disabled})),[K]),[Ze,ea]=l.useState(()=>toArray(Z)),aa=void 0===Y?Ze:toArray(Y),[la,ta]=l.useState(""),sa=l.useMemo(()=>new Map(Ye.map(e=>[e.value,e])),[Ye]),ra=l.useCallback(e=>sa.get(e)??{value:e,label:String(e),custom:!0},[sa]),na=la.trim(),ia=na.toLocaleLowerCase(ke),oa=""===na||Ye.some(e=>e.label.toLocaleLowerCase(ke)===ia||String(e.value).toLocaleLowerCase(ke)===ia)||aa.some(e=>String(e).toLocaleLowerCase(ke)===ia),ca=!le||fe||Re||oa?null:na,da=l.useMemo(()=>null===ca?Ye:[...Ye,{value:ca,label:ca,custom:!0}],[Ye,ca]),ma=l.useMemo(()=>c.createItems(da,{getValue:e=>e.value,getLabel:e=>e.label}),[da]),pa=Xe?aa:aa[0]??null,ua=!Re&&!fe,ha=g(ua),ba=L(G,We?"":H,C[Ee],$[Ee],A[Ee],Xe?W[Ee]:j[Ee],`${T[Ge][Ee]} pe-1.5`,Re?I[P]:fe?z[P]:_[P],ua?"plass-glow":""),fa=/* @__PURE__ */["min-w-0 flex-1 self-stretch bg-transparent p-0 [font:inherit] text-inherit","[outline:none]","placeholder:text-(--plass-muted-fg)","caret-(--p-accent) selection:bg-(--p-soft-press)","disabled:cursor-not-allowed"].join(" "),renderInput=a=>e(c.Input,{ref:Le,placeholder:Be?ie||" ":ie,...s(Pe,Ve),onKeyDown:f(ze,void 0),className:L(fa,Xe&&"min-w-16",Xe&&a&&"ms-1.5",Be&&!a&&y)}),ga=e(d.Label,{className:L(F[Ee],"font-semibold",Re?"text-(--plass-muted-fg)":"text-(--plass-fg)",_e?.label),children:oe});return a(d.Root,{disabled:Re,invalid:Qe,className:L("flex-col align-top",q[Ee],he?"flex w-full":"inline-flex",Se),style:{...O(Ue,E),...Oe},...Ae,children:[k(oe)&&!We?ga:null,a(c.Root,{id:Ie,name:ve,items:ma,multiple:Xe,value:pa,onValueChange:e=>{const a=toArray(e);0===a.length&&0===aa.length||function commit(e){void 0===Y&&ea(e),ee?.(Xe?e:e[0]??null)}(a)},onInputValueChange:e=>{ta(e),ae?.(e)},open:ye,defaultOpen:xe,onOpenChange:e=>we?.(e),autoHighlight:!0,itemToStringLabel:String,itemToStringValue:String,limit:ne,locale:ke,disabled:Re,readOnly:fe,required:ge,children:[e(v,{notched:We,size:Ee,density:Ge,variant:P,disabled:Re,readOnly:fe,float:Be,label:ga,children:a(c.InputGroup,{style:We?x:void 0,...ha,className:L(ba,_e?.control),children:[ue?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)",children:ue}):null,Xe?e(c.Chips,{className:"flex min-w-0 flex-1 flex-wrap items-center gap-1",children:e(t.Provider,{value:Re,children:e(c.Value,{children:t=>a(l.Fragment,{children:[t.map(ra).map(a=>e(c.Chip,{render:e(m,{variant:"glass",size:Ee,color:Ue,density:"compact",disabled:Re,endIcon:fe||Re?null:e(c.ChipRemove,{"aria-label":De(a.label),className:N,children:e(h,{})})}),children:a.label},String(a.value))),renderInput(t.length>0)]})})})}):renderInput(!1),!se||fe||Re?null:e(c.Clear,{"aria-label":$e,className:U,children:e(h,{})}),e(c.Trigger,{"aria-label":Te,"aria-labelledby":void 0,className:Q,children:e(c.Icon,{className:L("flex items-center","[transition:rotate_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","data-[popup-open]:rotate-180"),children:e(u,{})})})]})}),e(c.Portal,{children:e(c.Positioner,{className:"plass-portal z-(--plass-z-portal) [outline:none]",sideOffset:6,children:a(c.Popup,{className:L(B,$[Ee],C[Ee]),style:D(Ue,3),children:[e(c.Empty,{className:"px-2 py-1.5 text-(--plass-muted-fg) empty:hidden",children:qe}),e(c.List,{children:t=>e(c.Item,{value:t.value,disabled:t.disabled,className:J,children:t.custom?a(l.Fragment,{children:[e("span",{className:"absolute start-1.5 flex size-4 items-center justify-center text-(--p-accent) [&_svg]:size-4",children:e(b,{})}),e("span",{className:"truncate",children:te?te(t.label):Fe.addCustom(t.label)})]}):a(l.Fragment,{children:[e(c.ItemIndicator,{className:"absolute start-1.5 flex size-4 items-center justify-center",children:e(p,{})}),e("span",{className:"truncate",children:t.label})]})},`${t.custom?"custom:":""}${String(t.value)}`)})]})})})]}),de?e(d.Description,{className:L(S(Ee),_e?.description),children:de}):null,e(d.Error,Je?{match:!0,className:L(F[Ee],"text-(--p-accent)",_e?.error),children:me}:{className:L(F[Ee],"text-(--p-accent)",_e?.error)})]})}
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{FadedContext as t,controlNaming as n,useDisabled as s}from"../../internal/form.js";import{useDefaults as r,useRuntimeLocale as o}from"../../internal/defaults.js";import{useLabels as i}from"../../internal/labels.js";import{Combobox as c}from"@base-ui/react/combobox";import{Field as d}from"@base-ui/react/field";import{PlChip as m}from"../chip/PlChip.js";import{CheckIcon as u,ChevronIcon as p,CloseIcon as h,PlusIcon as f}from"../../internal/icons.js";import{hotKeyHandler as b}from"../../internal/keys.js";import{useFieldLight as g}from"../../internal/glow.js";import{FieldNotch as v,floatControlClassName as y,notchShellStyle as x,resolveNotch as w}from"../../internal/notch.js";import{chipRemoveClasses as C,controlHeightClasses as N,controlTextLeadingClasses as j,cx as L,disabledClasses as S,fieldDescriptionClasses as I,fieldReadOnlyClasses as O,fieldRestClasses as z,fieldSlots as k,focusWithinRingClasses as M,forcedHighlightedClasses as P,gapClasses as R,glassClasses as _,hasContent as E,iconClasses as V,metaTextClasses as A,paddingXClasses as F,radiusClasses as D,stackGapClasses as T,surfaceSlots as $,targetClasses as q,transitionClasses as H}from"../../internal/styles.js";const K=/* @__PURE__ */["relative flex w-full cursor-text items-center","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",H,V].join(" "),G=M,W={xs:"min-h-6 py-0",sm:"min-h-8 py-0.5",md:"min-h-10 py-1",lg:"min-h-12 py-1.5",xl:"min-h-14 py-2"},B=/* @__PURE__ */[_,"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain","w-[var(--anchor-width)] border bg-(--plass-glass-press) p-1","[border-color:var(--plass-glass-line)]","[box-shadow:var(--plass-shadow-3),var(--plass-gloss-glass)]","[outline:none]","[transition:opacity_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),J=/* @__PURE__ */["relative flex cursor-pointer items-center gap-2 select-none","rounded-(--plass-radius-xs) py-1.5 pe-2 ps-7",H,"data-[highlighted]:bg-(--p-soft-hover) data-[highlighted]:text-(--p-accent)",P,"data-[selected]:font-semibold data-[selected]:text-(--p-accent)","data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50","[outline:none]"].join(" "),Q=/* @__PURE__ */["inline-flex h-[1lh] shrink-0 cursor-pointer items-center justify-center p-0","rounded-(--plass-radius-xs) text-(--plass-muted-fg)","[transition:color_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","enabled:hover:text-(--p-accent)","focus-visible:[outline:2px_solid_var(--p-ring)] focus-visible:[outline-offset:1px]","disabled:cursor-not-allowed"].join(" "),U=/* @__PURE__ */L(q,Q),X=[],Y=new Map;function labelsOf(e,a,l){const t=new Map;for(const n of a){const a=l.get(n)?.label??e.get(n);void 0!==a&&t.set(n,a)}return t.size===e.size&&[...t].every(([a,l])=>e.get(a)===l)?e:0===t.size?Y:t}function ShownRows({countRef:e}){const a=c.useFilteredItems().length;return l.useEffect(()=>{e.current=a},[e,a]),null}function toArray(e){return null==e?X:Array.isArray(e)?e:[e]}export function PlCombobox({variant:M="glass",size:P,color:_,density:V,elevation:q=0,items:H,multiple:X,value:Z,defaultValue:ee,onValueChange:ae,onInputValueChange:le,filter:te,autoHighlight:ne=!0,clearOnEscape:se=!1,allowCustom:re=!0,customLabel:oe,clearable:ie=!1,emptyMessage:ce,limit:de,placeholder:me,label:ue,labelPlacement:pe,description:he,error:fe,invalid:be,startIcon:ge,fullWidth:ve=!1,disabled:ye=!1,readOnly:xe=!1,required:we=!1,name:Ce,open:Ne,defaultOpen:je,onOpenChange:Le,openLabel:Se,clearLabel:Ie,removeLabel:Oe,inputRef:ze,id:ke,className:Me,hotKeys:Pe,classNames:Re,style:_e,"aria-label":Ee,"aria-labelledby":Ve,...Ae}){const Fe=r(),De=o(void 0),Te=s(ye),$e=i(),qe=Se??$e.open,He=Ie??$e.clear,Ke=ce??$e.empty,Ge=Oe??$e.removeItem,We=P??Fe.size??"md",Be=_??Fe.color??"primary",Je=V??Fe.density??"default",Qe=pe??Fe.labelPlacement??"top",{notched:Ue,float:Xe}=w(Qe,ue,E(ge)),Ye=E(fe),Ze=be??Ye,ea=Ze?"danger":Be,aa=!0===X,la=l.useMemo(()=>H.map(e=>({value:e.value,label:e.label??String(e.value),content:e.content,disabled:e.disabled,option:e})),[H]),ta=l.useMemo(()=>te?(e,a)=>void 0===e.option||te(e.option,a):te,[te]),[na,sa]=l.useState(()=>toArray(ee)),ra=void 0===Z?na:toArray(Z),[oa,ia]=l.useState(""),ca=l.useMemo(()=>new Map(la.map(e=>[e.value,e])),[la]),[da,ma]=l.useState(Y),ua=labelsOf(da,ra,ca);ua!==da&&ma(ua);const pa=l.useCallback(e=>ca.get(e)??{value:e,label:ua.get(e)??String(e),custom:!ua.has(e)},[ca,ua]),ha=l.useCallback(e=>ua.get(e)??String(e),[ua]),fa=oa.trim(),ba=fa.toLocaleLowerCase(De),ga=""===fa||la.some(e=>e.label.toLocaleLowerCase(De)===ba||String(e.value).toLocaleLowerCase(De)===ba)||ra.some(e=>String(e).toLocaleLowerCase(De)===ba||ua.get(e)?.toLocaleLowerCase(De)===ba),va=!re||xe||Te||ga?null:fa,ya=l.useMemo(()=>null===va?la:[...la,{value:va,label:va,custom:!0}],[la,va]),xa=l.useMemo(()=>c.createItems(ya,{getValue:e=>e.value,getLabel:e=>e.label}),[ya]),wa=aa?ra:ra[0]??null;function refusesEscape(e){return!se&&"escape-key"===e.reason&&(e.cancel(),e.allowPropagation(),!0)}const Ca=l.useRef(0),Na=!Te&&!xe,ja=g(Na),La=L(K,Ue?"":G,j[We],D[We],R[We],aa?W[We]:N[We],`${F[Je][We]} pe-1.5`,Te?S[M]:xe?O[M]:z[M],Na?"plass-glow":""),Sa=/* @__PURE__ */["min-w-0 flex-1 self-stretch bg-transparent p-0 [font:inherit] text-inherit","[outline:none]","placeholder:text-(--plass-muted-fg)","caret-(--p-accent) selection:bg-(--p-soft-press)","disabled:cursor-not-allowed"].join(" "),renderInput=a=>e(c.Input,{ref:ze,placeholder:Xe?me||" ":me,...n(Ee,Ve),onKeyDown:b(Pe,void 0),className:L(Sa,aa&&"min-w-16",aa&&a&&"ms-1.5",Xe&&!a&&y)}),Ia=e(d.Label,{className:L(A[We],"font-semibold",Te?"text-(--plass-muted-fg)":"text-(--plass-fg)",Re?.label),children:ue});return a(d.Root,{disabled:Te,invalid:Ze,className:L("flex-col align-top",T[We],ve?"flex w-full":"inline-flex",Me),style:{...k(ea,q),..._e},...Ae,children:[E(ue)&&!Ue?Ia:null,a(c.Root,{id:ke,name:Ce,items:xa,multiple:aa,value:wa,filter:ta,onValueChange:(e,a)=>{if(refusesEscape(a))return;const l=toArray(e);0===l.length&&0===ra.length||function commit(e,a){ae?.(aa?e:e[0]??null,a),a.isCanceled||(void 0===Z&&sa(e),ma(labelsOf(ua,[...ra,...e],ca)))}(l,a)},onInputValueChange:(e,a)=>{refusesEscape(a)||(le?.(e,a),a.isCanceled||ia(e))},open:Ne,defaultOpen:je,onOpenChange:(e,a)=>{!e&&function holdsOpen(e){const{event:a}=e;return!("none"!==e.reason||"keydown"!==a.type||"Enter"!==a.key||Ca.current>0||(e.cancel(),a.preventDefault(),0))}(a)||Le?.(e,a)},autoHighlight:ne,itemToStringLabel:ha,itemToStringValue:String,limit:de,locale:De,disabled:Te,readOnly:xe,required:we,children:[e(ShownRows,{countRef:Ca}),e(v,{notched:Ue,size:We,density:Je,variant:M,disabled:Te,readOnly:xe,float:Xe,label:Ia,children:a(c.InputGroup,{style:Ue?x:void 0,...ja,className:L(La,Re?.control),children:[ge?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)",children:ge}):null,aa?e(c.Chips,{className:"flex min-w-0 flex-1 flex-wrap items-center gap-1",children:e(t.Provider,{value:Te,children:e(c.Value,{children:t=>a(l.Fragment,{children:[t.map(pa).map(a=>e(c.Chip,{render:e(m,{variant:"glass",size:We,color:ea,density:"compact",disabled:Te,endIcon:xe||Te?null:e(c.ChipRemove,{"aria-label":Ge(a.label),className:C,children:e(h,{})})}),children:a.label},String(a.value))),renderInput(t.length>0)]})})})}):renderInput(!1),!ie||xe||Te?null:e(c.Clear,{"aria-label":He,className:U,children:e(h,{})}),e(c.Trigger,{"aria-label":qe,"aria-labelledby":void 0,className:Q,children:e(c.Icon,{className:L("flex items-center","[transition:rotate_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]","data-[popup-open]:rotate-180"),children:e(p,{})})})]})}),e(c.Portal,{children:e(c.Positioner,{className:"plass-portal z-(--plass-z-portal) [outline:none]",sideOffset:6,children:a(c.Popup,{className:L(B,D[We],j[We]),style:$(ea,3),children:[e(c.Empty,{className:"px-2 py-1.5 text-(--plass-muted-fg) empty:hidden",children:Ke}),e(c.List,{children:t=>e(c.Item,{value:t.value,disabled:t.disabled,className:J,children:t.custom?a(l.Fragment,{children:[e("span",{className:"absolute start-1.5 flex size-4 items-center justify-center text-(--p-accent) [&_svg]:size-4",children:e(f,{})}),e("span",{className:"truncate",children:oe?oe(t.label):$e.addCustom(t.label)})]}):a(l.Fragment,{children:[e(c.ItemIndicator,{className:"absolute start-1.5 flex size-4 items-center justify-center",children:e(u,{})}),E(t.content)?e("span",{className:"min-w-0 flex-1",children:t.content}):e("span",{className:"truncate",children:t.label})]})},`${t.custom?"custom:":""}${String(t.value)}`)})]})})})]}),he?e(d.Description,{className:L(I(We),Re?.description),children:he}):null,e(d.Error,Ye?{match:!0,className:L(A[We],"text-(--p-accent)",Re?.error),children:fe}:{className:L(A[We],"text-(--p-accent)",Re?.error)})]})}
@@ -1,2 +1,2 @@
1
1
  export { PlCombobox } from './PlCombobox.js';
2
- export type { PlComboboxOption, PlComboboxProps, PlComboboxValue } from './PlCombobox.js';
2
+ export type { PlComboboxChangeEventDetails, PlComboboxOption, PlComboboxProps, PlComboboxValue } from './PlCombobox.js';
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{controlNaming as l,useDisabled as o,useLabelReference as s}from"../../internal/form.js";import{useDefaults as t}from"../../internal/defaults.js";import{Radio as i}from"@base-ui/react/radio";import{RadioGroup as n}from"@base-ui/react/radio-group";import{Field as d}from"@base-ui/react/field";import{controlSlots as c,cx as p,fieldDescriptionClasses as m,focusRingClasses as f,forcedCheckedClasses as b,forcedDisabledCheckedClasses as u,glassClasses as h,hasContent as x,metaTextClasses as g,tickDotClasses as y,tickRowTextClasses as v,tickSizeClasses as N,transitionClasses as j}from"../../internal/styles.js";const k=/* @__PURE__ */r.createContext({size:"md",color:"primary",readOnly:!1,disabled:!1}),R=/* @__PURE__ */["relative inline-flex shrink-0 items-center justify-center rounded-full border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","plass-fill [--p-fill-edge:1px]",j,f].join(" "),z=/* @__PURE__ */[h,"cursor-pointer bg-(--plass-glass) [border-color:var(--plass-border)]","hover:bg-(--plass-glass-hover) hover:[border-color:var(--p-line)]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent] data-[checked]:hover:brightness-105",b].join(" "),w=/* @__PURE__ */[h,"cursor-default bg-(--plass-glass) [border-color:var(--plass-border)]","saturate-[0.55]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]",b].join(" "),O=/* @__PURE__ */[h,"cursor-not-allowed bg-(--plass-glass) [border-color:var(--plass-border)]","opacity-50 saturate-[0.35]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]",u].join(" "),P=/* @__PURE__ */["rounded-full bg-current","[transition-property:width,height]","[transition-duration:var(--plass-duration)]","[transition-timing-function:var(--plass-ease)]","motion-reduce:[transition-duration:0ms]"].join(" ");export const PlRadio=/* @__PURE__ */r.forwardRef(function PlRadio({label:l,description:o,disabled:t=!1,className:n,style:c,"aria-label":p,"aria-labelledby":m,...f},b){const u=r.useContext(k),h=s(p,m),x=f.readOnly??u.readOnly,j=t||u.disabled;return a(d.Root,{disabled:t,className:["flex flex-col",n??""].filter(Boolean).join(" "),style:c,children:[a("div",{className:`flex items-start gap-2 ${v[u.size]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(i.Root,{ref:b,className:[R,N[u.size],j?O:x?w:z].join(" "),disabled:t,"aria-label":p,"aria-labelledby":h.labelledBy,...f,children:e(i.Indicator,{keepMounted:!0,className:`${P} ${y[u.size]}`})})}),l||o?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[l?e(d.Label,{className:j?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",children:l}):null,o?e(d.Description,{className:`m-0 ${g[u.size]} text-(--plass-muted-fg)`,children:o}):null]}):null]}),h.node]})});export const PlRadioGroup=/* @__PURE__ */r.forwardRef(function PlRadioGroup({size:s,color:i,orientation:f="vertical",label:b,description:u,error:h,invalid:y,disabled:v=!1,readOnly:N=!1,className:j,classNames:R,style:z,children:w,"aria-label":O,"aria-labelledby":P,...$},B){const G=t(),C=o(v),D=s??G.size??"md",L=i??G.color??"primary",M=x(h),E=y??M,I=E?"danger":L,q=r.useMemo(()=>({size:D,color:I,readOnly:N,disabled:C}),[D,I,N,C]);return e(k.Provider,{value:q,children:a(d.Root,{disabled:C,invalid:E,className:["flex flex-col gap-1.5",j??""].filter(Boolean).join(" "),style:{...c(I,0,"solid"),...z},children:[b?e(d.Label,{className:p(g[D],"font-semibold",C?"text-(--plass-muted-fg)":"text-(--plass-fg)",R?.label),children:b}):null,u?e(d.Description,{className:p(m(D),R?.description),children:u}):null,e(n,{ref:B,disabled:C,readOnly:N,className:p("flex","horizontal"===f?"flex-row flex-wrap gap-x-5 gap-y-2":"flex-col gap-2",R?.control),...l(O,P),...$,children:w}),e(d.Error,M?{match:!0,className:p(g[D],"text-(--p-accent)",R?.error),children:h}:{className:p(g[D],"text-(--p-accent)",R?.error)})]})})});
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{controlNaming as l,useDisabled as o}from"../../internal/form.js";import{useDefaults as s}from"../../internal/defaults.js";import{Radio as t}from"@base-ui/react/radio";import{RadioGroup as i}from"@base-ui/react/radio-group";import{Field as n}from"@base-ui/react/field";import{controlSlots as d,cx as c,fieldDescriptionClasses as p,focusRingClasses as m,forcedCheckedClasses as f,forcedDisabledCheckedClasses as u,glassClasses as b,hasContent as h,metaTextClasses as x,tickDotClasses as g,tickRowTextClasses as y,tickSizeClasses as v,transitionClasses as N}from"../../internal/styles.js";const j=/* @__PURE__ */r.createContext({size:"md",color:"primary",readOnly:!1,disabled:!1}),k=/* @__PURE__ */["relative inline-flex shrink-0 items-center justify-center rounded-full border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","plass-fill [--p-fill-edge:1px]",N,m].join(" "),R=/* @__PURE__ */[b,"cursor-pointer bg-(--plass-glass) [border-color:var(--plass-border)]","hover:bg-(--plass-glass-hover) hover:[border-color:var(--p-line)]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent] data-[checked]:hover:brightness-105",f].join(" "),z=/* @__PURE__ */[b,"cursor-default bg-(--plass-glass) [border-color:var(--plass-border)]","saturate-[0.55]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]",f].join(" "),w=/* @__PURE__ */[b,"cursor-not-allowed bg-(--plass-glass) [border-color:var(--plass-border)]","opacity-50 saturate-[0.35]","data-[checked]:[--p-fill-on:1] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]",u].join(" "),O=/* @__PURE__ */["rounded-full bg-current","[transition-property:width,height]","[transition-duration:var(--plass-duration)]","[transition-timing-function:var(--plass-ease)]","motion-reduce:[transition-duration:0ms]"].join(" ");export const PlRadio=/* @__PURE__ */r.forwardRef(function PlRadio({label:l,description:o,disabled:s=!1,className:i,style:d,"aria-label":c,"aria-labelledby":p,...m},f){const u=r.useContext(j),b=m.readOnly??u.readOnly,h=s||u.disabled;return e(n.Root,{disabled:s,className:["flex flex-col",i??""].filter(Boolean).join(" "),style:d,children:a("div",{className:`flex items-start gap-2 ${y[u.size]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(t.Root,{ref:f,className:[k,v[u.size],h?w:b?z:R].join(" "),disabled:s,"aria-label":c,"aria-labelledby":p,...m,children:e(t.Indicator,{keepMounted:!0,className:`${O} ${g[u.size]}`})})}),l||o?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[l?e(n.Label,{className:h?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",children:l}):null,o?e(n.Description,{className:`m-0 ${x[u.size]} text-(--plass-muted-fg)`,children:o}):null]}):null]})})});export const PlRadioGroup=/* @__PURE__ */r.forwardRef(function PlRadioGroup({size:t,color:m,orientation:f="vertical",label:u,description:b,error:g,invalid:y,disabled:v=!1,readOnly:N=!1,className:k,classNames:R,style:z,children:w,"aria-label":O,"aria-labelledby":P,...$},G){const B=s(),C=o(v),D=t??B.size??"md",L=m??B.color??"primary",M=h(g),E=y??M,I=E?"danger":L,q=r.useMemo(()=>({size:D,color:I,readOnly:N,disabled:C}),[D,I,N,C]);return e(j.Provider,{value:q,children:a(n.Root,{disabled:C,invalid:E,className:["flex flex-col gap-1.5",k??""].filter(Boolean).join(" "),style:{...d(I,0,"solid"),...z},children:[u?e(n.Label,{className:c(x[D],"font-semibold",C?"text-(--plass-muted-fg)":"text-(--plass-fg)",R?.label),children:u}):null,b?e(n.Description,{className:c(p(D),R?.description),children:b}):null,e(i,{ref:G,disabled:C,readOnly:N,className:c("flex","horizontal"===f?"flex-row flex-wrap gap-x-5 gap-y-2":"flex-col gap-2",R?.control),...l(O,P),...$,children:w}),e(n.Error,M?{match:!0,className:c(x[D],"text-(--p-accent)",R?.error),children:g}:{className:c(x[D],"text-(--p-accent)",R?.error)})]})})});
@@ -1 +1 @@
1
- "use client";import{jsx as a,jsxs as e,Fragment as r}from"react/jsx-runtime";import*as t from"react";import{useDisabled as l,useLabelReference as o}from"../../internal/form.js";import{useDefaults as s}from"../../internal/defaults.js";import{Switch as c}from"@base-ui/react/switch";import{Field as i}from"@base-ui/react/field";import{controlSlots as n,cx as d,fieldDescriptionClasses as h,focusRingClasses as m,hasContent as p,metaTextClasses as f,tickRowTextClasses as u}from"../../internal/styles.js";const b={xs:"h-3.5 w-6",sm:"h-4 w-7",md:"h-5 w-9",lg:"h-6 w-11",xl:"h-7 w-13"},g={xs:"data-[checked]:start-[calc(100%-0.75rem)]",sm:"data-[checked]:start-[calc(100%-0.875rem)]",md:"data-[checked]:start-[calc(100%-1.125rem)]",lg:"data-[checked]:start-[calc(100%-1.375rem)]",xl:"data-[checked]:start-[calc(100%-1.625rem)]"},x=/* @__PURE__ */["relative inline-flex shrink-0 rounded-full","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","plass-fill","[transition-property:background-color,box-shadow,filter]","[transition-duration:var(--plass-duration)]","[transition-timing-function:var(--plass-ease)]","motion-reduce:[transition-duration:0ms]",m].join(" "),k=/* @__PURE__ */["forced-colors:border forced-colors:[border-color:CanvasText]","forced-colors:data-[checked]:[background-color:Highlight]"].join(" "),w=/* @__PURE__ */[k,"cursor-pointer bg-(--plass-track)","hover:brightness-[0.97] dark:hover:brightness-110","data-[checked]:[--p-fill-on:1]","data-[checked]:[box-shadow:var(--p-lift)] data-[checked]:hover:brightness-105"].join(" "),j=/* @__PURE__ */[k,"cursor-default bg-(--plass-track) saturate-[0.55]","data-[checked]:[--p-fill-on:1]","data-[checked]:shadow-none"].join(" "),v=/* @__PURE__ */["forced-colors:border forced-colors:[border-color:GrayText]","cursor-not-allowed bg-(--plass-track)","opacity-50 saturate-[0.35] shadow-none","data-[checked]:[--p-fill-on:1]"].join(" "),y=/* @__PURE__ */["absolute inset-y-0.5 start-0.5 aspect-square rounded-full bg-white","[box-shadow:0_1px_2px_rgb(20_40_90/0.25)]","forced-colors:[background-color:CanvasText] forced-colors:data-[checked]:[background-color:HighlightText]","[transition:inset-inline-start_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]"].join(" ");export const PlSwitch=/* @__PURE__ */t.forwardRef(function PlSwitch({size:t,color:m,label:k,description:N,error:_,invalid:T,labelPlacement:B="end",disabled:P=!1,readOnly:R=!1,className:S,classNames:$,style:z,"aria-label":C,"aria-labelledby":H,...O},q){const D=s(),E=l(P),F=o(C,H),G=t??D.size??"md",L=m??D.color??"primary",A=p(_),I=T??A,J=I?"danger":L,K=a("span",{className:"flex h-[1lh] shrink-0 items-center",children:a(c.Root,{ref:q,className:d(x,b[G],E?v:R?j:w,$?.control),disabled:E,readOnly:R,"aria-label":C,"aria-labelledby":F.labelledBy,...O,children:a(c.Thumb,{className:`${y} ${g[G]}`})})}),M=k||N?e("span",{className:["flex min-w-0 flex-col gap-0.5","start"===B?"flex-1":""].filter(Boolean).join(" "),children:[k?a(i.Label,{className:d(E?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",$?.label),children:k}):null,N?a(i.Description,{className:d(h(G),$?.description),children:N}):null]}):null;return e(i.Root,{disabled:E,invalid:I,className:["inline-flex flex-col gap-1 align-top",S??""].filter(Boolean).join(" "),style:{...n(J,0,"solid"),...z},children:[a("div",{className:`flex items-start gap-2.5 ${u[G]}`,children:e(r,"start"===B?{children:[M,K]}:{children:[K,M]})}),a(i.Error,A?{match:!0,className:d(f[G],"text-(--p-accent)",$?.error),children:_}:{className:d(f[G],"text-(--p-accent)",$?.error)}),F.node]})});
1
+ "use client";import{jsx as a,jsxs as e,Fragment as r}from"react/jsx-runtime";import*as t from"react";import{useDisabled as o}from"../../internal/form.js";import{useDefaults as l}from"../../internal/defaults.js";import{Switch as s}from"@base-ui/react/switch";import{Field as c}from"@base-ui/react/field";import{controlSlots as i,cx as n,fieldDescriptionClasses as d,focusRingClasses as h,hasContent as m,metaTextClasses as p,tickRowTextClasses as f}from"../../internal/styles.js";const u={xs:"h-3.5 w-6",sm:"h-4 w-7",md:"h-5 w-9",lg:"h-6 w-11",xl:"h-7 w-13"},b={xs:"data-[checked]:start-[calc(100%-0.75rem)]",sm:"data-[checked]:start-[calc(100%-0.875rem)]",md:"data-[checked]:start-[calc(100%-1.125rem)]",lg:"data-[checked]:start-[calc(100%-1.375rem)]",xl:"data-[checked]:start-[calc(100%-1.625rem)]"},g=/* @__PURE__ */["relative inline-flex shrink-0 rounded-full","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","plass-fill","[transition-property:background-color,box-shadow,filter]","[transition-duration:var(--plass-duration)]","[transition-timing-function:var(--plass-ease)]","motion-reduce:[transition-duration:0ms]",h].join(" "),x=/* @__PURE__ */["forced-colors:border forced-colors:[border-color:CanvasText]","forced-colors:data-[checked]:[background-color:Highlight]"].join(" "),k=/* @__PURE__ */[x,"cursor-pointer bg-(--plass-track)","hover:brightness-[0.97] dark:hover:brightness-110","data-[checked]:[--p-fill-on:1]","data-[checked]:[box-shadow:var(--p-lift)] data-[checked]:hover:brightness-105"].join(" "),w=/* @__PURE__ */[x,"cursor-default bg-(--plass-track) saturate-[0.55]","data-[checked]:[--p-fill-on:1]","data-[checked]:shadow-none"].join(" "),j=/* @__PURE__ */["forced-colors:border forced-colors:[border-color:GrayText]","cursor-not-allowed bg-(--plass-track)","opacity-50 saturate-[0.35] shadow-none","data-[checked]:[--p-fill-on:1]"].join(" "),v=/* @__PURE__ */["absolute inset-y-0.5 start-0.5 aspect-square rounded-full bg-white","[box-shadow:0_1px_2px_rgb(20_40_90/0.25)]","forced-colors:[background-color:CanvasText] forced-colors:data-[checked]:[background-color:HighlightText]","[transition:inset-inline-start_var(--plass-duration)_var(--plass-ease)]","motion-reduce:[transition-duration:0ms]"].join(" ");export const PlSwitch=/* @__PURE__ */t.forwardRef(function PlSwitch({size:t,color:h,label:x,description:y,error:N,invalid:_,labelPlacement:T="end",disabled:P=!1,readOnly:R=!1,className:S,classNames:$,style:z,"aria-label":B,"aria-labelledby":C,...H},O){const q=l(),D=o(P),E=t??q.size??"md",F=h??q.color??"primary",G=m(N),L=_??G,A=L?"danger":F,I=a("span",{className:"flex h-[1lh] shrink-0 items-center",children:a(s.Root,{ref:O,className:n(g,u[E],D?j:R?w:k,$?.control),disabled:D,readOnly:R,"aria-label":B,"aria-labelledby":C,...H,children:a(s.Thumb,{className:`${v} ${b[E]}`})})}),J=x||y?e("span",{className:["flex min-w-0 flex-col gap-0.5","start"===T?"flex-1":""].filter(Boolean).join(" "),children:[x?a(c.Label,{className:n(D?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",$?.label),children:x}):null,y?a(c.Description,{className:n(d(E),$?.description),children:y}):null]}):null;return e(c.Root,{disabled:D,invalid:L,className:["inline-flex flex-col gap-1 align-top",S??""].filter(Boolean).join(" "),style:{...i(A,0,"solid"),...z},children:[a("div",{className:`flex items-start gap-2.5 ${f[E]}`,children:e(r,"start"===T?{children:[J,I]}:{children:[I,J]})}),a(c.Error,G?{match:!0,className:n(p[E],"text-(--p-accent)",$?.error),children:N}:{className:n(p[E],"text-(--p-accent)",$?.error)})]})});
@@ -84,13 +84,16 @@ export declare function controlNaming(label: string | undefined, labelledBy: str
84
84
  * the hidden words it points at, for a Base UI part `controlNaming` cannot
85
85
  * reach.
86
86
  *
87
- * A checkbox, a switch, a radio, and the group around a slider's thumbs or a
88
- * code's slots read `aria-labelledby` themselves and fall back to the visible
89
- * label for anything but a reference of the caller's, `undefined` included. So
90
- * an `aria-label` given without an `aria-labelledby` is written into a hidden
91
- * node as well, and the part is pointed at that, which leaves the `aria-label`
92
- * as the name in the label's place. A caller's `aria-labelledby` comes back as
93
- * it was, and with neither there is no reference and no node.
87
+ * The group around a slider's thumbs or a code's slots reads `aria-labelledby`
88
+ * itself and falls back to the visible label for anything but a reference of
89
+ * the caller's, `undefined` included. So an `aria-label` given without an
90
+ * `aria-labelledby` is written into a hidden node as well, and the part is
91
+ * pointed at that, which leaves the `aria-label` as the name in the label's
92
+ * place. A caller's `aria-labelledby` comes back as it was, and with neither
93
+ * there is no reference and no node.
94
+ *
95
+ * A checkbox, a switch and a radio do not need it: since Base UI 1.9.0 they
96
+ * drop the label's reference for a non-blank `aria-label` of their own.
94
97
  */
95
98
  export declare function useLabelReference(label: string | undefined, labelledBy: string | undefined): {
96
99
  labelledBy: string | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "plass-ui",
3
- "version": "1.8.1",
3
+ "version": "1.8.2",
4
4
  "description": "A React UI component library made of glass and gradients — smooth tinted surfaces, shadows in their own colour, and light that follows the pointer. Accessible and themeable, ESM only, types included, dark mode built in.",
5
5
  "type": "module",
6
6
  "types": "dist/index.d.ts",
@@ -143,7 +143,7 @@
143
143
  "eslint-plugin-react-hooks": "^7.1.1",
144
144
  "globals": "^17.13.0",
145
145
  "jiti": "^2.7.0",
146
- "playwright": "^1.63.0",
146
+ "playwright": "^1.64.0",
147
147
  "postcss": "^8.5.29",
148
148
  "prettier": "^3.9.9",
149
149
  "prettier-plugin-tailwindcss": "^0.8.1",
@@ -153,12 +153,12 @@
153
153
  "terser": "^5.51.2",
154
154
  "typescript": "^6.0.3",
155
155
  "typescript-eslint": "^8.71.1",
156
- "vite": "^8.3.3",
156
+ "vite": "^8.3.4",
157
157
  "vitest": "^5.0.3",
158
158
  "vitest-browser-react": "^2.3.0"
159
159
  },
160
160
  "dependencies": {
161
- "@base-ui/react": "^1.8.0",
161
+ "@base-ui/react": "^1.9.0",
162
162
  "highlight.js": "^11.12.0"
163
163
  },
164
164
  "peerDependencies": {