plass-ui 1.8.0 → 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 +34 -0
- package/README.md +1 -1
- package/dist/components/accordion/PlAccordion.d.ts +2 -0
- package/dist/components/alert/PlAlert.d.ts +2 -0
- package/dist/components/badge/PlBadge.d.ts +2 -0
- package/dist/components/blockquote/PlBlockquote.d.ts +2 -0
- package/dist/components/bottom-navigation/PlBottomNavigation.d.ts +2 -0
- package/dist/components/box/PlBox.d.ts +2 -0
- package/dist/components/button/PlButton.d.ts +2 -0
- package/dist/components/button-group/PlButtonGroup.d.ts +2 -0
- package/dist/components/card/PlCard.d.ts +2 -0
- package/dist/components/carousel/PlCarousel.d.ts +2 -0
- package/dist/components/checkbox/PlCheckbox.js +1 -1
- package/dist/components/chip/PlChip.d.ts +2 -0
- package/dist/components/collapsible/PlCollapsible.d.ts +2 -0
- package/dist/components/color-picker/PlColorPicker.d.ts +2 -0
- package/dist/components/combobox/PlCombobox.d.ts +63 -8
- package/dist/components/combobox/PlCombobox.js +1 -1
- package/dist/components/combobox/index.d.ts +1 -1
- package/dist/components/confirm/PlConfirmProvider.js +1 -1
- package/dist/components/data-table/PlDataTable.d.ts +2 -0
- package/dist/components/file-picker/PlFilePicker.d.ts +2 -0
- package/dist/components/hot-keys/PlHotKeys.d.ts +4 -0
- package/dist/components/list/PlList.d.ts +2 -0
- package/dist/components/number-field/PlNumberField.d.ts +2 -0
- package/dist/components/otp-field/PlOtpField.d.ts +2 -0
- package/dist/components/pagination/PlPagination.d.ts +2 -0
- package/dist/components/pill/PlPill.d.ts +2 -0
- package/dist/components/radio-group/PlRadioGroup.js +1 -1
- package/dist/components/scroll-zone/PlScrollZone.d.ts +2 -0
- package/dist/components/segmented-button/PlSegmentedButton.d.ts +6 -1
- package/dist/components/segmented-button/PlSegmentedButton.js +1 -1
- package/dist/components/select/PlSelect.d.ts +2 -0
- package/dist/components/sidebar/PlSidebarTrigger.d.ts +2 -0
- package/dist/components/switch/PlSwitch.js +1 -1
- package/dist/components/table/PlTable.d.ts +2 -0
- package/dist/components/text-field/PlTextField.d.ts +2 -0
- package/dist/components/toast/PlToast.d.ts +2 -0
- package/dist/components/toolbar/PlToolbar.d.ts +2 -0
- package/dist/components/transfer/PlTransfer.d.ts +2 -0
- package/dist/internal/chart-frame.d.ts +2 -0
- package/dist/internal/form.d.ts +10 -7
- package/dist/styles.css +1 -1
- package/dist/types.d.ts +4 -1
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,40 @@
|
|
|
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
|
+
|
|
30
|
+
## 1.8.1 (2026-10-09)
|
|
31
|
+
|
|
32
|
+
### Breaking changes
|
|
33
|
+
|
|
34
|
+
- **`PlConfirmProvider` asks its questions in an alert dialog.** `confirm` and `alert` open a `role="alertdialog"` rather than a `role="dialog"`, which is what WAI-ARIA calls a dialog that breaks into what the reader was doing and waits for an answer, so a screen reader announces the question as an alert. Its name, description, focus and dismissal are as before. A test that finds the question by its role, `getByRole('dialog')`, finds it as `getByRole('alertdialog')` now.
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- **A full-width `PlSegmentedButton` whose labels together need more than its row no longer runs out of its groove.** Each segment kept the width its label needs, so three long labels in a narrow row laid out wider than the row and ran past the end of the groove. The segments now shrink in proportion to what each needs and their labels end in an ellipsis, as the Flutter set's do; a row that has room shares its width as before. In a full-width set a label is now held in a `<span>` of its own.
|
|
39
|
+
- **An editor shows each component's own `variant` default.** `PlassStyleProps` documented `variant` as `'solid'`, so that is what an editor showed on every component that takes it, while most of them default to `'glass'`, `PlTextField`, `PlSelect`, `PlCard` and `PlDataTable` among them, and `PlPagination`, `PlBlockquote`, `PlSidebarTrigger` and the charts default to `'ghost'`. Each component's props now say its own default, and the shared comment says the default is the component's.
|
|
40
|
+
|
|
7
41
|
## 1.8.0 (2026-10-07)
|
|
8
42
|
|
|
9
43
|
### Breaking changes
|
package/README.md
CHANGED
|
@@ -134,7 +134,7 @@ The list also names two exports that are not counted, because each shares a fold
|
|
|
134
134
|
|
|
135
135
|
### Feedback
|
|
136
136
|
|
|
137
|
-
`PlAlert` · `PlConfirmProvider` · `PlDrawer` · `PlEmpty` · `PlMeter` · `PlModal` · `PlOverlay` · `PlPopconfirm` · `PlPopover` · `PlProgressBox` · `PlProgressCircular` · `PlProgressLinear` · `PlSkeleton` · `
|
|
137
|
+
`PlAlert` · `PlConfirmProvider` · `PlDrawer` · `PlEmpty` · `PlMeter` · `PlModal` · `PlOverlay` · `PlPopconfirm` · `PlPopover` · `PlProgressBox` · `PlProgressCircular` · `PlProgressLinear` · `PlSkeleton` · `PlToastProvider` · `PlTooltip` · `PlTour`
|
|
138
138
|
|
|
139
139
|
### Inputs
|
|
140
140
|
|
|
@@ -8,6 +8,8 @@ import type { PlassElevation, PlassHeadingLevel, PlassStyleProps } from '../../t
|
|
|
8
8
|
*/
|
|
9
9
|
export type PlAccordionHeadingLevel = PlassHeadingLevel;
|
|
10
10
|
export interface PlAccordionProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
11
|
+
/** @default 'glass' */
|
|
12
|
+
variant?: PlassStyleProps['variant'];
|
|
11
13
|
/**
|
|
12
14
|
* Drop shadow depth. `0` is the default — an accordion is part of the page it
|
|
13
15
|
* is set into, not a panel floating over it.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
3
3
|
export interface PlAlertProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title'> {
|
|
4
|
+
/** @default 'glass' */
|
|
5
|
+
variant?: PlassStyleProps['variant'];
|
|
4
6
|
/**
|
|
5
7
|
* Drop shadow depth. `0` is the default — an alert belongs to the flow of the
|
|
6
8
|
* page it interrupts. The one that floats above it is a dialog.
|
|
@@ -6,6 +6,8 @@ import type { PlassCorner, PlassElevation, PlassStyleProps } from '../../types.j
|
|
|
6
6
|
*/
|
|
7
7
|
export type PlBadgeOverlap = 'square' | 'circle';
|
|
8
8
|
export interface PlBadgeProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'span'>, 'color' | 'content'> {
|
|
9
|
+
/** @default 'solid' */
|
|
10
|
+
variant?: PlassStyleProps['variant'];
|
|
9
11
|
/**
|
|
10
12
|
* What the badge says — usually a count, sometimes a word.
|
|
11
13
|
*
|
|
@@ -7,6 +7,8 @@ import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
|
7
7
|
* an event handler written against one works on the other.
|
|
8
8
|
*/
|
|
9
9
|
export interface PlBlockquoteProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'figure'>, 'color'> {
|
|
10
|
+
/** @default 'ghost' */
|
|
11
|
+
variant?: PlassStyleProps['variant'];
|
|
10
12
|
/**
|
|
11
13
|
* Drop shadow depth. `0` is the default — a quote is set *into* a page rather
|
|
12
14
|
* than floating over it, so it is raised even less often than a `PlCard`.
|
|
@@ -16,6 +16,8 @@ export type PlBottomNavigationValue = string | number;
|
|
|
16
16
|
*/
|
|
17
17
|
export type PlBottomNavigationLabels = 'all' | 'selected' | 'none';
|
|
18
18
|
export interface PlBottomNavigationProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'nav'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
19
|
+
/** @default 'glass' */
|
|
20
|
+
variant?: PlassStyleProps['variant'];
|
|
19
21
|
/** The destination the reader is on. Use with `onValueChange` for a controlled bar. */
|
|
20
22
|
value?: PlBottomNavigationValue | null;
|
|
21
23
|
/** Which starts current, for an uncontrolled bar. */
|
|
@@ -2,6 +2,8 @@ import * as React from 'react';
|
|
|
2
2
|
import { useRender } from '@base-ui/react/use-render';
|
|
3
3
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
4
4
|
export interface PlBoxProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
|
|
5
|
+
/** @default 'glass' */
|
|
6
|
+
variant?: PlassStyleProps['variant'];
|
|
5
7
|
/**
|
|
6
8
|
* Drop shadow depth. `0` is the default and it is flat — the glass edge is
|
|
7
9
|
* what separates the box from the page. Raise it only for a surface that
|
|
@@ -2,6 +2,8 @@ import * as React from 'react';
|
|
|
2
2
|
import { useRender } from '@base-ui/react/use-render';
|
|
3
3
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
4
4
|
export interface PlButtonProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'button'>, 'color'> {
|
|
5
|
+
/** @default 'solid' */
|
|
6
|
+
variant?: PlassStyleProps['variant'];
|
|
5
7
|
/**
|
|
6
8
|
* Drop shadow depth. `1` is the default, because a moulded key **rests on**
|
|
7
9
|
* the sheet rather than lying flush with it. Hover adds a level and pressing
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassOrientation, PlassStyleProps } from '../../types.js';
|
|
3
3
|
export interface PlButtonGroupProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
|
|
4
|
+
/** @default 'solid' */
|
|
5
|
+
variant?: PlassStyleProps['variant'];
|
|
4
6
|
/**
|
|
5
7
|
* Which way the buttons run. A vertical group is a stacked menu of equal
|
|
6
8
|
* actions; a horizontal one is the default because that is what a toolbar is.
|
|
@@ -2,6 +2,8 @@ import * as React from 'react';
|
|
|
2
2
|
import { useRender } from '@base-ui/react/use-render';
|
|
3
3
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
4
4
|
export interface PlCardProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title'> {
|
|
5
|
+
/** @default 'glass' */
|
|
6
|
+
variant?: PlassStyleProps['variant'];
|
|
5
7
|
/**
|
|
6
8
|
* Drop shadow depth. `1` is the default: a card is a sheet lying **on** the
|
|
7
9
|
* page wash rather than printed into it, and the small amount of grey under
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
3
3
|
export interface PlCarouselProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
4
|
+
/** @default 'glass' */
|
|
5
|
+
variant?: PlassStyleProps['variant'];
|
|
4
6
|
/**
|
|
5
7
|
* Drop shadow depth of the frame. `0` — the default — is flat.
|
|
6
8
|
* @default 0
|
|
@@ -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
|
|
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,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
3
3
|
export interface PlChipProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'span'>, 'color'> {
|
|
4
|
+
/** @default 'glass' */
|
|
5
|
+
variant?: PlassStyleProps['variant'];
|
|
4
6
|
/**
|
|
5
7
|
* Drop shadow depth. `0` is the default — a chip is a token sitting *on*
|
|
6
8
|
* something else, so it is raised even less often than a `PlButton`.
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
3
3
|
export interface PlCollapsibleProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'title' | 'onChange'> {
|
|
4
|
+
/** @default 'glass' */
|
|
5
|
+
variant?: PlassStyleProps['variant'];
|
|
4
6
|
/**
|
|
5
7
|
* Drop shadow depth. `0` is the default — a fold is part of the page it is set
|
|
6
8
|
* into, not a panel floating over it.
|
|
@@ -22,6 +22,8 @@ export interface PlColorPickerLabels {
|
|
|
22
22
|
/** The English the picker uses for the parts nobody can read a name off. */
|
|
23
23
|
export declare const defaultColorPickerLabels: PlColorPickerLabels;
|
|
24
24
|
export interface PlColorPickerProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
25
|
+
/** @default 'glass' */
|
|
26
|
+
variant?: PlassStyleProps['variant'];
|
|
25
27
|
/**
|
|
26
28
|
* The four parts of a labelled field, as every other one names them: the
|
|
27
29
|
* `label`, the `control`, the `description` and the `error`. `className`
|
|
@@ -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,15 +17,38 @@ 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'> {
|
|
50
|
+
/** @default 'glass' */
|
|
51
|
+
variant?: PlassStyleProps['variant'];
|
|
28
52
|
/** Classes on the parts a `className` does not reach. */
|
|
29
53
|
classNames?: PlassFieldClassNames;
|
|
30
54
|
/**
|
|
@@ -50,12 +74,42 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
|
|
|
50
74
|
*/
|
|
51
75
|
multiple?: Multiple;
|
|
52
76
|
/** The chosen value. Use with `onValueChange` for a controlled combobox. */
|
|
53
|
-
value?:
|
|
77
|
+
value?: HeldSelection<Multiple> | null;
|
|
54
78
|
/** The initially chosen value, for an uncontrolled combobox. */
|
|
55
|
-
defaultValue?:
|
|
56
|
-
|
|
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;
|
|
57
82
|
/** Called as the text in the input changes — the filter query, not the value. */
|
|
58
|
-
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;
|
|
59
113
|
/**
|
|
60
114
|
* Whether a value the list does not contain may be committed.
|
|
61
115
|
*
|
|
@@ -127,7 +181,8 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
|
|
|
127
181
|
open?: boolean;
|
|
128
182
|
/** Whether the popup starts open. */
|
|
129
183
|
defaultOpen?: boolean;
|
|
130
|
-
|
|
184
|
+
/** Called as the popup opens or closes, and with what caused it. */
|
|
185
|
+
onOpenChange?: (open: boolean, eventDetails: PlComboboxChangeEventDetails) => void;
|
|
131
186
|
/** Accessible name of the button that opens the list. @default 'Open' */
|
|
132
187
|
openLabel?: string;
|
|
133
188
|
/** Accessible name of the clear button. @default 'Clear' */
|
|
@@ -152,7 +207,7 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
|
|
|
152
207
|
*
|
|
153
208
|
* With `multiple` the chosen values become PlChips inside the field and the
|
|
154
209
|
* input goes on filtering after each one. A row taken from a filtered list
|
|
155
|
-
* closes the list and empties the text, which is how Base UI
|
|
210
|
+
* closes the list and empties the text, which is how Base UI behaves,
|
|
156
211
|
* and a row taken with nothing typed leaves the list open for the next one.
|
|
157
212
|
*
|
|
158
213
|
* Base UI owns everything hard about this: the filtering and its collator, the
|
|
@@ -160,5 +215,5 @@ export interface PlComboboxProps<Multiple extends boolean | undefined = false> e
|
|
|
160
215
|
* navigation across both the list and the chips, and the hidden input that makes
|
|
161
216
|
* the whole thing submit with a form.
|
|
162
217
|
*/
|
|
163
|
-
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;
|
|
164
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
|
|
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
|
|
1
|
+
"use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as n from"react";import{PlButton as o}from"../button/PlButton.js";import{useLabels as t}from"../../internal/labels.js";import{lazyPart as l}from"../../internal/lazy.js";const c=/* @__PURE__ */l(()=>import("../modal/PlModal.js").then(e=>e.PlModal));function ConfirmModal({open:r,...o}){const[t,l]=n.useState(!1);return n.useLayoutEffect(()=>{l(!0)},[]),e(c,{open:!0===r&&t,...o})}const i=/* @__PURE__ */n.createContext(null);export function PlConfirmProvider({size:l,color:s,confirmLabel:u,cancelLabel:a,acknowledgeLabel:f,width:d,children:m}){const h=t(),[p,w]=n.useState(!1),[C,b]=n.useState(null),v=n.useRef(null),k=n.useRef([]),P=n.useRef(0),z=n.useRef(null),j=n.useCallback(e=>{const r=v.current;if(!r)return;r.resolve(e);const n=k.current.shift();if(n)return v.current=n,void b(n);v.current=null,w(!1)},[]),x=n.useCallback((e,r)=>new Promise(n=>{P.current+=1;const o={id:P.current,kind:e,options:r,resolve:n};v.current?k.current.push(o):(v.current=o,b(o),w(!0))}),[]),E=n.useMemo(()=>({confirm:e=>x("confirm",e),alert:e=>x("alert",e).then(()=>{})}),[x]);n.useEffect(()=>function whenIdle(e){if("function"==typeof window.requestIdleCallback){const r=window.requestIdleCallback(e,{timeout:2e3});return()=>window.cancelIdleCallback(r)}const r=window.setTimeout(e,500);return()=>window.clearTimeout(r)}(c.preload),[]);const L=n.useCallback(()=>{const e=[v.current,...k.current];v.current=null,k.current=[],e.forEach(e=>e?.resolve(!1)),w(!1),b(null)},[]);n.useEffect(()=>()=>{v.current?.resolve(!1),k.current.forEach(e=>e.resolve(!1)),v.current=null,k.current=[]},[]);const g=C?.options,y="alert"===C?.kind,M="confirm"===(g?.initialFocus??"cancel")||y,R=n.useRef(!1);n.useLayoutEffect(()=>{p&&R.current&&z.current?.focus(),R.current=p},[p,C]);const I=C?e(n.Suspense,{fallback:null,children:e(ConfirmModal,{open:p,onUnavailable:L,onOpenChange:e=>{e||j(!1)},showClose:!1,role:"alertdialog",initialFocus:z,size:g?.size??l,color:g?.color??s,width:g?.width??d,dismissible:g?.dismissible??!0,title:g?.title,description:g?.description,actions:r(n.Fragment,{children:[y?null:e(o,{ref:M?void 0:z,variant:"ghost",color:"secondary",size:g?.size??l,onClick:()=>j(!1),children:g?.cancelLabel??a??h.cancel}),e(o,{ref:M?z:void 0,color:g?.color??s,size:g?.size??l,onClick:()=>j(!0),children:g?.confirmLabel??(y?f??h.acknowledge:u??h.confirm)})]},C?.id),children:g?.children})}):null;return r(i.Provider,{value:E,children:[m,I]})}export function usePlConfirm(){const e=n.useContext(i);if(!e)throw new Error("[plass-ui] usePlConfirm was called outside a <PlConfirmProvider>.");return e}
|
|
@@ -91,6 +91,8 @@ export interface PlDataTableColumn<Row> {
|
|
|
91
91
|
unsearchable?: boolean;
|
|
92
92
|
}
|
|
93
93
|
export interface PlDataTableProps<Row> extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'onSelect'> {
|
|
94
|
+
/** @default 'glass' */
|
|
95
|
+
variant?: PlassStyleProps['variant'];
|
|
94
96
|
/**
|
|
95
97
|
* Drop shadow depth. `0` is the default — a table is a grid set into the page
|
|
96
98
|
* rather than a panel floating over it.
|
|
@@ -16,6 +16,8 @@ export interface PlFileBatch {
|
|
|
16
16
|
source: 'drop' | 'dialog';
|
|
17
17
|
}
|
|
18
18
|
export interface PlFilePickerProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'title' | 'children'> {
|
|
19
|
+
/** @default 'glass' */
|
|
20
|
+
variant?: PlassStyleProps['variant'];
|
|
19
21
|
/**
|
|
20
22
|
* Drop shadow depth. `0` is the default — a dropzone is cut into the page
|
|
21
23
|
* rather than floating over it.
|
|
@@ -17,6 +17,8 @@ export interface PlHotKeysCluster {
|
|
|
17
17
|
right: string;
|
|
18
18
|
}
|
|
19
19
|
export interface PlHotKeysProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'span'>, 'color' | 'children'> {
|
|
20
|
+
/** @default 'glass' */
|
|
21
|
+
variant?: PlassStyleProps['variant'];
|
|
20
22
|
/**
|
|
21
23
|
* The keys, innermost punctuation and all.
|
|
22
24
|
*
|
|
@@ -54,6 +56,8 @@ export interface PlHotKeysProps extends PlassStyleProps, Omit<React.ComponentPro
|
|
|
54
56
|
elevation?: PlassElevation;
|
|
55
57
|
}
|
|
56
58
|
export interface PlKbdProps extends Pick<PlassStyleProps, 'variant' | 'size' | 'density'>, Omit<React.ComponentPropsWithoutRef<'kbd'>, 'color'> {
|
|
59
|
+
/** @default 'glass' */
|
|
60
|
+
variant?: PlassStyleProps['variant'];
|
|
57
61
|
children?: React.ReactNode;
|
|
58
62
|
}
|
|
59
63
|
/**
|
|
@@ -2,6 +2,8 @@ import * as React from 'react';
|
|
|
2
2
|
import { useRender } from '@base-ui/react/use-render';
|
|
3
3
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
4
4
|
export interface PlListProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'ul'>, 'color'> {
|
|
5
|
+
/** @default 'glass' */
|
|
6
|
+
variant?: PlassStyleProps['variant'];
|
|
5
7
|
/**
|
|
6
8
|
* Drop shadow depth. `0` is the default — a list is a sheet lying flat, not a
|
|
7
9
|
* key resting on one.
|
|
@@ -15,6 +15,8 @@ import type { PlassElevation, PlassFieldClassNames, PlassHotKeys, PlassFieldLabe
|
|
|
15
15
|
*/
|
|
16
16
|
export type PlNumberFieldSteppers = 'end' | 'split' | 'none';
|
|
17
17
|
export interface PlNumberFieldProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'children'> {
|
|
18
|
+
/** @default 'glass' */
|
|
19
|
+
variant?: PlassStyleProps['variant'];
|
|
18
20
|
/** Classes on the parts a `className` does not reach. */
|
|
19
21
|
classNames?: PlassFieldClassNames;
|
|
20
22
|
/**
|
|
@@ -9,6 +9,8 @@ import type { PlassElevation, PlassFieldClassNames, PlassHotKeys, PlassStyleProp
|
|
|
9
9
|
*/
|
|
10
10
|
export type PlOtpCharset = 'numeric' | 'alpha' | 'alphanumeric' | 'any';
|
|
11
11
|
export interface PlOtpFieldProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange' | 'children'> {
|
|
12
|
+
/** @default 'glass' */
|
|
13
|
+
variant?: PlassStyleProps['variant'];
|
|
12
14
|
/** Classes on the parts a `className` does not reach. */
|
|
13
15
|
classNames?: PlassFieldClassNames;
|
|
14
16
|
/**
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
3
3
|
export interface PlPaginationProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'nav'>, 'color' | 'onChange'> {
|
|
4
|
+
/** @default 'ghost' */
|
|
5
|
+
variant?: PlassStyleProps['variant'];
|
|
4
6
|
/** How many pages there are. Fewer than two and the whole control renders nothing. */
|
|
5
7
|
count: number;
|
|
6
8
|
/** The current page, 1-based. Use with `onPageChange` for a controlled row. */
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { PlassElevation, PlassPosition, PlassStyleProps } from '../../types.js';
|
|
3
3
|
export interface PlPillProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'onClick' | 'title'> {
|
|
4
|
+
/** @default 'solid' */
|
|
5
|
+
variant?: PlassStyleProps['variant'];
|
|
4
6
|
/**
|
|
5
7
|
* Drop shadow depth. `2` here, against the `0` almost everything else takes.
|
|
6
8
|
*
|
|
@@ -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
|
|
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)})]})})});
|
|
@@ -48,6 +48,8 @@ export type PlScrollZoneMode = 'item' | 'page' | 'hold';
|
|
|
48
48
|
*/
|
|
49
49
|
export type PlScrollZoneButtonPlacement = 'inline' | 'overlay';
|
|
50
50
|
export interface PlScrollZoneProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
|
|
51
|
+
/** @default 'glass' */
|
|
52
|
+
variant?: PlassStyleProps['variant'];
|
|
51
53
|
/**
|
|
52
54
|
* Which way the children run, and therefore which way the zone scrolls.
|
|
53
55
|
* @default 'horizontal'
|
|
@@ -33,7 +33,12 @@ export interface PlSegmentedButtonProps extends Omit<PlassStyleProps, 'variant'>
|
|
|
33
33
|
readOnly?: boolean;
|
|
34
34
|
/** Identifies the value when a form is submitted. */
|
|
35
35
|
name?: string;
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* The segments share the full width, an equal part each. A segment whose
|
|
38
|
+
* label needs more than its part keeps the width it needs, and the others
|
|
39
|
+
* share the rest. Labels that together need more than the row end in an
|
|
40
|
+
* ellipsis.
|
|
41
|
+
*/
|
|
37
42
|
fullWidth?: boolean;
|
|
38
43
|
children?: React.ReactNode;
|
|
39
44
|
}
|