plass-ui 1.0.3 → 1.2.0
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 +189 -0
- package/README.md +2 -0
- package/dist/components/avatar/PlAvatar.js +1 -1
- package/dist/components/avatar-group/PlAvatarGroup.d.ts +47 -0
- package/dist/components/avatar-group/PlAvatarGroup.js +1 -0
- package/dist/components/avatar-group/index.d.ts +2 -0
- package/dist/components/avatar-group/index.js +1 -0
- package/dist/components/checkbox/PlCheckbox.d.ts +3 -1
- package/dist/components/checkbox/PlCheckbox.js +1 -1
- package/dist/components/color-picker/PlColorPicker.d.ts +88 -0
- package/dist/components/color-picker/PlColorPicker.js +1 -0
- package/dist/components/color-picker/index.d.ts +2 -0
- package/dist/components/color-picker/index.js +1 -0
- package/dist/components/combobox/PlCombobox.d.ts +4 -2
- package/dist/components/combobox/PlCombobox.js +1 -1
- package/dist/components/command-palette/PlCommandPalette.d.ts +89 -0
- package/dist/components/command-palette/PlCommandPalette.js +1 -0
- package/dist/components/command-palette/index.d.ts +2 -0
- package/dist/components/command-palette/index.js +1 -0
- package/dist/components/divider/PlDivider.js +1 -1
- package/dist/components/drawer/PlDrawer.d.ts +4 -2
- package/dist/components/drawer/PlDrawer.js +1 -1
- package/dist/components/fieldset/PlFieldset.d.ts +35 -0
- package/dist/components/fieldset/PlFieldset.js +1 -0
- package/dist/components/fieldset/index.d.ts +2 -0
- package/dist/components/fieldset/index.js +1 -0
- package/dist/components/footer/PlFooter.d.ts +90 -0
- package/dist/components/footer/PlFooter.js +1 -0
- package/dist/components/footer/index.d.ts +2 -0
- package/dist/components/footer/index.js +1 -0
- package/dist/components/form/PlForm.d.ts +61 -0
- package/dist/components/form/PlForm.js +1 -0
- package/dist/components/form/index.d.ts +2 -0
- package/dist/components/form/index.js +1 -0
- package/dist/components/header/PlHeader.d.ts +124 -0
- package/dist/components/header/PlHeader.js +1 -0
- package/dist/components/header/index.d.ts +2 -0
- package/dist/components/header/index.js +1 -0
- package/dist/components/menu/PlMenu.d.ts +4 -2
- package/dist/components/menu/PlMenu.js +1 -1
- package/dist/components/menubar/PlMenubar.d.ts +60 -0
- package/dist/components/menubar/PlMenubar.js +1 -0
- package/dist/components/menubar/index.d.ts +2 -0
- package/dist/components/menubar/index.js +1 -0
- package/dist/components/modal/PlModal.d.ts +4 -2
- package/dist/components/modal/PlModal.js +1 -1
- package/dist/components/navigation-menu/PlNavigationMenu.d.ts +103 -0
- package/dist/components/navigation-menu/PlNavigationMenu.js +1 -0
- package/dist/components/navigation-menu/index.d.ts +2 -0
- package/dist/components/navigation-menu/index.js +1 -0
- package/dist/components/number-field/PlNumberField.d.ts +4 -2
- package/dist/components/number-field/PlNumberField.js +1 -1
- package/dist/components/otp-field/PlOtpField.d.ts +3 -1
- package/dist/components/otp-field/PlOtpField.js +1 -1
- package/dist/components/overlay/PlOverlay.d.ts +4 -2
- package/dist/components/overlay/PlOverlay.js +1 -1
- package/dist/components/page-layout/PlPageLayout.d.ts +139 -0
- package/dist/components/page-layout/PlPageLayout.js +1 -0
- package/dist/components/page-layout/index.d.ts +2 -0
- package/dist/components/page-layout/index.js +1 -0
- package/dist/components/radio-group/PlRadioGroup.d.ts +3 -1
- package/dist/components/radio-group/PlRadioGroup.js +1 -1
- package/dist/components/scroll-zone/PlScrollZone.d.ts +35 -15
- package/dist/components/scroll-zone/PlScrollZone.js +1 -1
- package/dist/components/select/PlSelect.d.ts +3 -1
- package/dist/components/select/PlSelect.js +1 -1
- package/dist/components/sidebar/PlSidebar.d.ts +141 -0
- package/dist/components/sidebar/PlSidebar.js +1 -0
- package/dist/components/sidebar/PlSidebarTrigger.d.ts +34 -0
- package/dist/components/sidebar/PlSidebarTrigger.js +1 -0
- package/dist/components/sidebar/index.d.ts +4 -0
- package/dist/components/sidebar/index.js +1 -0
- package/dist/components/switch/PlSwitch.d.ts +3 -1
- package/dist/components/switch/PlSwitch.js +1 -1
- package/dist/components/text-field/PlTextField.d.ts +3 -1
- package/dist/components/text-field/PlTextField.js +1 -1
- package/dist/components/text-link/PlTextLink.d.ts +11 -2
- package/dist/components/text-link/PlTextLink.js +1 -1
- package/dist/components/toast/PlToast.d.ts +10 -0
- package/dist/components/toast/PlToast.js +1 -1
- package/dist/components/toggle/PlToggle.d.ts +55 -0
- package/dist/components/toggle/PlToggle.js +1 -0
- package/dist/components/toggle/PlToggleGroup.d.ts +48 -0
- package/dist/components/toggle/PlToggleGroup.js +1 -0
- package/dist/components/toggle/index.d.ts +4 -0
- package/dist/components/toggle/index.js +1 -0
- package/dist/components/transfer/PlTransfer.d.ts +55 -0
- package/dist/components/transfer/PlTransfer.js +1 -0
- package/dist/components/transfer/index.d.ts +2 -0
- package/dist/components/transfer/index.js +1 -0
- package/dist/css/avatar-group.css +2 -0
- package/dist/css/color-picker.css +2 -0
- package/dist/css/command-palette.css +2 -0
- package/dist/css/fieldset.css +2 -0
- package/dist/css/footer.css +2 -0
- package/dist/css/form.css +2 -0
- package/dist/css/header.css +2 -0
- package/dist/css/menubar.css +2 -0
- package/dist/css/navigation-menu.css +2 -0
- package/dist/css/page-layout.css +2 -0
- package/dist/css/sidebar.css +2 -0
- package/dist/css/toggle.css +2 -0
- package/dist/css/transfer.css +2 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +1 -1
- package/dist/internal/avatar-group.d.ts +25 -0
- package/dist/internal/avatar-group.js +2 -0
- package/dist/internal/color.d.ts +109 -0
- package/dist/internal/color.js +1 -0
- package/dist/internal/link.d.ts +18 -0
- package/dist/internal/link.js +1 -0
- package/dist/internal/page-layout.d.ts +140 -0
- package/dist/internal/page-layout.js +1 -0
- package/dist/internal/picker.d.ts +4 -2
- package/dist/internal/picker.js +1 -1
- package/dist/internal/search.d.ts +31 -0
- package/dist/internal/search.js +1 -0
- package/dist/internal/styles.d.ts +9 -0
- package/dist/internal/styles.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/types.d.ts +72 -0
- package/package.json +3 -3
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Radio as BaseUIRadio } from '@base-ui/react/radio';
|
|
3
3
|
import { RadioGroup as BaseUIRadioGroup } from '@base-ui/react/radio-group';
|
|
4
|
-
import type { PlassColor, PlassOrientation, PlassSize } from '../../types.js';
|
|
4
|
+
import type { PlassColor, PlassFieldClassNames, PlassOrientation, PlassSize } from '../../types.js';
|
|
5
5
|
export interface PlRadioGroupProps extends Omit<React.ComponentPropsWithoutRef<typeof BaseUIRadioGroup>, 'className' | 'style' | 'render'> {
|
|
6
|
+
/** Classes on the parts a `className` does not reach. */
|
|
7
|
+
classNames?: PlassFieldClassNames;
|
|
6
8
|
/** @default 'md' */
|
|
7
9
|
size?: PlassSize;
|
|
8
10
|
/** @default 'primary' */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{Radio as l}from"@base-ui/react/radio";import{RadioGroup as o}from"@base-ui/react/radio-group";import{Field as s}from"@base-ui/react/field";import{controlSlots as t,
|
|
1
|
+
"use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{Radio as l}from"@base-ui/react/radio";import{RadioGroup as o}from"@base-ui/react/radio-group";import{Field as s}from"@base-ui/react/field";import{controlSlots as t,cx as i,focusRingClasses as c,glassClasses as d,hasContent as n,metaTextClasses as p,tickDotClasses as m,tickRowTextClasses as f,tickSizeClasses as u,transitionClasses as h}from"../../internal/styles.js";const b=/* @__PURE__ */r.createContext({size:"md",color:"primary",readOnly:!1}),g=/* @__PURE__ */["relative inline-flex shrink-0 items-center justify-center rounded-full border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",h,c].join(" "),x=/* @__PURE__ */[d,"cursor-pointer bg-(--plass-glass) [border-color:var(--plass-border)]","hover:bg-(--plass-glass-hover) hover:[border-color:var(--p-line)]","data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent] data-[checked]:hover:brightness-105"].join(" "),v=/* @__PURE__ */[d,"cursor-default bg-(--plass-glass) [border-color:var(--plass-border)]","saturate-[0.55]","data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]"].join(" "),N=/* @__PURE__ */[d,"cursor-not-allowed bg-(--plass-glass) [border-color:var(--plass-border)]","opacity-50 saturate-[0.35]","data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]"].join(" ");export const PlRadio=/* @__PURE__ */r.forwardRef(function PlRadio({label:o,description:t,disabled:i=!1,className:c,style:d,...n},h){const k=r.useContext(b),y=n.readOnly??k.readOnly;return e(s.Root,{disabled:i,className:["flex flex-col",c??""].filter(Boolean).join(" "),style:d,children:a("div",{className:`flex items-start gap-2 ${f[k.size]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(l.Root,{ref:h,className:[g,u[k.size],i?N:y?v:x].join(" "),disabled:i,...n,children:e(l.Indicator,{className:`rounded-full bg-current ${m[k.size]}`})})}),o||t?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[o?e(s.Label,{className:i?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",children:o}):null,t?e(s.Description,{className:`${p[k.size]} text-(--plass-muted-fg)`,children:t}):null]}):null]})})});export const PlRadioGroup=/* @__PURE__ */r.forwardRef(function PlRadioGroup({size:l="md",color:c="primary",orientation:d="vertical",label:m,description:f,error:u,invalid:h,disabled:g=!1,readOnly:x=!1,className:v,classNames:N,style:k,children:y,...j},R){const z=n(u),w=h??z,O=w?"danger":c,P=r.useMemo(()=>({size:l,color:O,readOnly:x}),[l,O,x]);return e(b.Provider,{value:P,children:a(s.Root,{disabled:g,invalid:w,className:["flex flex-col gap-1.5",v??""].filter(Boolean).join(" "),style:{...t(O,0,"solid"),...k},children:[m?e(s.Label,{className:i(p[l],"font-semibold",g?"text-(--plass-muted-fg)":"text-(--plass-fg)",N?.label),children:m}):null,f?e(s.Description,{className:i(p[l],"text-(--plass-muted-fg)",N?.description),children:f}):null,e(o,{ref:R,disabled:g,readOnly:x,className:i("flex","horizontal"===d?"flex-row flex-wrap gap-x-5 gap-y-2":"flex-col gap-2",N?.control),...j,children:y}),e(s.Error,z?{match:!0,className:i(p[l],"text-(--p-accent)",N?.error),children:u}:{className:i(p[l],"text-(--p-accent)",N?.error)})]})})});
|
|
@@ -28,19 +28,21 @@ export type PlScrollZoneMode = 'item' | 'page' | 'hold';
|
|
|
28
28
|
/**
|
|
29
29
|
* Where the scroll buttons sit, which is also where the strip ends.
|
|
30
30
|
*
|
|
31
|
+
* - `inline` — beside the strip, in the layout. The default: the scroller stops
|
|
32
|
+
* where the button starts, so an item is *cut off* at the button's edge
|
|
33
|
+
* rather than sliding beneath it, nothing is ever half-hidden behind a
|
|
34
|
+
* control, and the button is legible over the page rather than over whatever
|
|
35
|
+
* it landed on.
|
|
31
36
|
* - `overlay` — over the ends of the strip, which keeps every pixel of the box
|
|
32
|
-
* for content and lets an item pass under a button.
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* button starts, so an item is *cut off* at the button's edge rather than
|
|
36
|
-
* sliding beneath it: nothing is ever half-hidden behind a control, and the
|
|
37
|
-
* button is legible over the page rather than over whatever it landed on.
|
|
37
|
+
* for content and lets an item pass under a button. What a shelf of pictures
|
|
38
|
+
* wants, where the strip reaching the edge of its box is worth more than
|
|
39
|
+
* seeing the whole of the item a button came to rest on.
|
|
38
40
|
*
|
|
39
41
|
* The lane an `inline` button sits in is kept even while that button has
|
|
40
42
|
* nowhere to go, or the strip would resize under the pointer every time it
|
|
41
43
|
* reached an end.
|
|
42
44
|
*/
|
|
43
|
-
export type PlScrollZoneButtonPlacement = '
|
|
45
|
+
export type PlScrollZoneButtonPlacement = 'inline' | 'overlay';
|
|
44
46
|
export interface PlScrollZoneProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
|
|
45
47
|
/**
|
|
46
48
|
* Which way the children run, and therefore which way the zone scrolls.
|
|
@@ -63,10 +65,10 @@ export interface PlScrollZoneProps extends PlassStyleProps, Omit<React.Component
|
|
|
63
65
|
/** When the scroll buttons are drawn. @default 'auto' */
|
|
64
66
|
buttons?: PlScrollZoneButtons;
|
|
65
67
|
/**
|
|
66
|
-
* Whether the buttons sit
|
|
67
|
-
* reach for when
|
|
68
|
-
*
|
|
69
|
-
* @default '
|
|
68
|
+
* Whether the buttons sit beside the strip or over it. `overlay` is what to
|
|
69
|
+
* reach for when the strip reaching the edge of its box is worth more than
|
|
70
|
+
* seeing the whole of the item a button came to rest on.
|
|
71
|
+
* @default 'inline'
|
|
70
72
|
*/
|
|
71
73
|
buttonPlacement?: PlScrollZoneButtonPlacement;
|
|
72
74
|
/** What pressing one does. @default 'item' */
|
|
@@ -89,6 +91,23 @@ export interface PlScrollZoneProps extends PlassStyleProps, Omit<React.Component
|
|
|
89
91
|
* @default true
|
|
90
92
|
*/
|
|
91
93
|
drag?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Turns a vertical wheel over a horizontal strip into scrolling along it.
|
|
96
|
+
*
|
|
97
|
+
* A mouse has one wheel and it points the wrong way for a strip that runs
|
|
98
|
+
* across the box. What a browser does with it there is its own business,
|
|
99
|
+
* which is the problem: it makes the answer depend on which browser the
|
|
100
|
+
* reader happens to be in. The pointer being on the strip is them saying
|
|
101
|
+
* which of the two things under it they meant to move.
|
|
102
|
+
*
|
|
103
|
+
* Only the vertical half of a gesture, and only while the strip has somewhere
|
|
104
|
+
* to go. A trackpad's two fingers, a tilt wheel and Shift held down already
|
|
105
|
+
* scroll it sideways and are left alone; and the moment it reaches an end the
|
|
106
|
+
* wheel goes back to the page, so a reader on their way down a long page is
|
|
107
|
+
* held up by one shelf rather than caught in it.
|
|
108
|
+
* @default true
|
|
109
|
+
*/
|
|
110
|
+
wheel?: boolean;
|
|
92
111
|
/** Shows the native scrollbar. @default false */
|
|
93
112
|
scrollbar?: boolean;
|
|
94
113
|
/** What the scrollable region is called — "Categories", "Recent files". */
|
|
@@ -110,10 +129,11 @@ export interface PlScrollZoneProps extends PlassStyleProps, Omit<React.Component
|
|
|
110
129
|
*
|
|
111
130
|
* The mechanism is an ordinary scroll container, and everything the component
|
|
112
131
|
* offers is a way of driving one. Swiping on a phone, two-finger dragging on a
|
|
113
|
-
* trackpad, the
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
*
|
|
132
|
+
* trackpad, the arrow keys and the scrollbar are the browser's own and are
|
|
133
|
+
* never intercepted; what is added on top is a pair of buttons for the pointer
|
|
134
|
+
* that has neither a wheel nor a finger, a mouse drag for the strip that reads
|
|
135
|
+
* as something to pull rather than something to page, and the vertical wheel a
|
|
136
|
+
* horizontal strip would otherwise have no use for.
|
|
117
137
|
*
|
|
118
138
|
* Nothing is transformed. A translated track would have to argue for an
|
|
119
139
|
* exception to the house rule; a scroll offset does not, and it is also what
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as n from"react";import{PlIconButton as r}from"../icon-button/PlIconButton.js";import{spacingValue as o}from"../../internal/grid.js";import{ChevronIcon as s}from"../../internal/icons.js";import{cx as
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as n from"react";import{PlIconButton as r}from"../icon-button/PlIconButton.js";import{spacingValue as o}from"../../internal/grid.js";import{ChevronIcon as s}from"../../internal/icons.js";import{cx as l}from"../../internal/styles.js";const i={xs:"p-1",sm:"p-1.5",md:"p-2",lg:"p-3",xl:"p-4"},a={xs:"gap-1",sm:"gap-1.5",md:"gap-2",lg:"gap-3",xl:"gap-4"};export const PlScrollZone=/* @__PURE__ */n.forwardRef(function PlScrollZone({orientation:c="horizontal",lines:u=1,spacing:d=2,buttons:f="auto",buttonPlacement:p="inline",mode:m="item",step:v=1,speed:b=900,snap:w=!1,drag:g=!0,wheel:h=!0,scrollbar:y=!1,variant:x="glass",size:E="md",color:L="primary",density:k="default",label:M,previousLabel:C="Previous",nextLabel:P="Next",className:D,style:R,children:A,...B},N){const T="horizontal"===c,j=Math.max(1,Math.round(u)),z=Math.max(1,Math.round(v)),S=n.useRef(null),W=n.useRef(null),[Y,_]=n.useState({back:!1,forward:!1}),H=n.useCallback(()=>{const e=S.current;if(!e)return;const t=T?e.clientWidth:e.clientHeight,n=T?e.scrollWidth:e.scrollHeight,r=Math.abs(T?e.scrollLeft:e.scrollTop);_(e=>{const o=r>1,s=n-t-r>1;return e.back===o&&e.forward===s?e:{back:o,forward:s}})},[T]);n.useEffect(()=>{const e=S.current,t=W.current;if(!e)return;if(H(),"undefined"==typeof ResizeObserver)return;const n=new ResizeObserver(H);return n.observe(e),t&&n.observe(t),()=>n.disconnect()},[H]);const F=n.useCallback(()=>{const e=S.current;return e&&T&&"rtl"===getComputedStyle(e).direction?-1:1},[T]),I=n.useCallback((e,t)=>{const n=S.current;if(!n)return;const r=t?function scrollBehavior(){return"undefined"!=typeof window&&window.matchMedia?.("(prefers-reduced-motion: reduce)").matches?"auto":"smooth"}():"auto";n.scrollBy(T?{left:e,behavior:r}:{top:e,behavior:r})},[T]);n.useEffect(()=>{const e=S.current;if(!e||!h||!T)return;const onWheel=t=>{if(Math.abs(t.deltaY)<=Math.abs(t.deltaX))return;const n=t.deltaMode===t.DOM_DELTA_LINE?16*t.deltaY:t.deltaMode===t.DOM_DELTA_PAGE?t.deltaY*e.clientWidth:t.deltaY,r=Math.abs(e.scrollLeft);(n>0?e.scrollWidth-e.clientWidth-r>1:r>1)&&(t.preventDefault(),I(n*F(),!1))};return e.addEventListener("wheel",onWheel,{passive:!1}),()=>e.removeEventListener("wheel",onWheel)},[F,T,I,h]);const O=n.useCallback(()=>{const e=S.current,t=W.current;if(!e||!t)return[];const n=T&&"rtl"===getComputedStyle(e).direction,r=T?n?"right":"left":"top",o=n?-1:1,s=e.getBoundingClientRect()[r],l=[];for(const e of Array.from(t.children)){const t=Math.round((e.getBoundingClientRect()[r]-s)*o);l.includes(t)||l.push(t)}return l.sort((e,t)=>e-t)},[T]),X=n.useCallback((e,t=m)=>{const n=S.current;if(!n)return;const r=F(),o=T?n.clientWidth:n.clientHeight;if("page"===t)return void I(o*(e?1:-1)*r,!0);const s=O(),l=s.filter(e=>e>1),i=s.filter(e=>e<-1),a=e?l[z-1]:i[i.length-z];I(void 0!==a?a*r:o*(e?1:-1)*r,!0)},[F,T,O,z,m,I]),$=n.useRef(null);n.useEffect(()=>()=>$.current?.(),[]);const q=n.useCallback((e,t)=>{if($.current)return;const n=F(),r=performance.now();let o=r,s=0;const tick=t=>{const r=t-o;o=t,I(b*r/1e3*(e?1:-1)*n,!1),s=requestAnimationFrame(tick)};s=requestAnimationFrame(tick);const release=()=>{cancelAnimationFrame(s),$.current=null,window.removeEventListener(t,release),window.removeEventListener("pointercancel",release),window.removeEventListener("blur",release),performance.now()-r<140&&X(e,"item")};$.current=release,window.addEventListener(t,release),window.addEventListener("pointercancel",release),window.addEventListener("blur",release)},[X,F,I,b]),Z=n.useRef(null);function pressHandlers(e){return"hold"!==m?{onClick:()=>X(e)}:{onPointerDown:t=>{0===t.button&&q(e,"pointerup")},onKeyDown:t=>{"Enter"!==t.key&&" "!==t.key||(t.preventDefault(),q(e,"keyup"))}}}n.useEffect(()=>()=>Z.current?.(),[]);const G="none"!==f&&("always"===f||Y.back||Y.forward),K="inline"===p;function scrollButton(t){const n=t?Y.forward:Y.back;if("auto"===f&&!n&&!K)return e("span",{});const o="auto"===f&&!n,i=e(r,{variant:x,size:E,color:L,density:k,elevation:1,label:t?P:C,disabled:!n,className:"pointer-events-auto",icon:e("span",{className:l("flex items-center",T?t?"-rotate-90 rtl:rotate-90":"rotate-90 rtl:-rotate-90":t?"":"rotate-180"),children:e(s,{})}),...pressHandlers(t)});return K?e("span",{className:l("flex shrink-0 items-center justify-center",o?"invisible":""),inert:o,children:i}):i}return t("div",{ref:N,className:l("relative flex min-w-0",K&&T?"flex-row items-stretch":"flex-col",K?a[E]:"",D),style:{"--p-ring":`var(--plass-${L}-ring)`,...R},...B,children:[G&&K?scrollButton(!1):null,e("div",{ref:S,tabIndex:0,role:M?"group":void 0,"aria-label":M,className:l("min-h-0 min-w-0 grow",T?"overflow-x-auto overflow-y-hidden":"overflow-y-auto overflow-x-hidden",w?T?"snap-x snap-mandatory":"snap-y snap-mandatory":"",y?"":"[scrollbar-width:none] [&::-webkit-scrollbar]:hidden",g&&(Y.back||Y.forward)?"cursor-grab data-[dragging]:cursor-grabbing":"","focus-visible:[outline:2px_solid_var(--p-ring)] focus-visible:[outline-offset:-2px]"),onScroll:H,onPointerDown:function beginDrag(e){if(!g||"touch"===e.pointerType||0!==e.button)return;Z.current?.();const t=e.currentTarget,n=e.clientX,r=e.clientY,o=t.scrollLeft,s=t.scrollTop;let l=!1;const i=document.body.style.getPropertyValue("-webkit-user-select"),move=e=>{const i=e.clientX-n,a=e.clientY-r;if(!l){if(Math.abs(T?i:a)<4)return;l=!0,t.setPointerCapture(e.pointerId),t.dataset.dragging="true",document.body.style.setProperty("-webkit-user-select","none")}T?t.scrollLeft=o-i:t.scrollTop=s-a},release=()=>{Z.current=null,t.removeEventListener("pointermove",move),t.removeEventListener("pointerup",end),t.removeEventListener("pointercancel",release),delete t.dataset.dragging,i?document.body.style.setProperty("-webkit-user-select",i):document.body.style.removeProperty("-webkit-user-select")},end=()=>{const e=l;if(release(),!e)return;const swallow=e=>{e.stopPropagation(),e.preventDefault()};t.addEventListener("click",swallow,{capture:!0,once:!0}),window.setTimeout(()=>t.removeEventListener("click",swallow,!0),0)};Z.current=release,t.addEventListener("pointermove",move),t.addEventListener("pointerup",end),t.addEventListener("pointercancel",release)},children:e("div",{ref:W,className:l(w?"[&>*]:snap-start":""),style:{display:"grid",gap:o(d),gridAutoFlow:T?"column":"row",...T?{width:"max-content",gridTemplateRows:`repeat(${j}, auto)`,gridAutoColumns:"max-content"}:{gridTemplateColumns:`repeat(${j}, minmax(0, 1fr))`,gridAutoRows:"max-content"}},children:A})}),G&&K?scrollButton(!0):null,G&&!K?t("div",{className:l("pointer-events-none absolute inset-0 flex justify-between",T?"items-center":"flex-col items-center",i[E]),children:[scrollButton(!1),scrollButton(!0)]}):null]})});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
2
|
+
import type { PlassElevation, PlassFieldClassNames, PlassStyleProps } from '../../types.js';
|
|
3
3
|
/**
|
|
4
4
|
* What a select's value may be.
|
|
5
5
|
*
|
|
@@ -19,6 +19,8 @@ export interface PlSelectOption {
|
|
|
19
19
|
disabled?: boolean;
|
|
20
20
|
}
|
|
21
21
|
export interface PlSelectProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'children'> {
|
|
22
|
+
/** Classes on the parts a `className` does not reach. */
|
|
23
|
+
classNames?: PlassFieldClassNames;
|
|
22
24
|
/**
|
|
23
25
|
* The options, as data. There is no `<PlSelect.Option>` to compose: what a
|
|
24
26
|
* caller has is almost always an array already, and the list has to be
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{Select as t}from"@base-ui/react/select";import{Field as s}from"@base-ui/react/field";import{CheckIcon as r,ChevronIcon as i}from"../../internal/icons.js";import{WidthSizer as n}from"../../internal/sizer.js";import{controlHeightClasses as o,controlTextLeadingClasses as c,
|
|
1
|
+
"use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{Select as t}from"@base-ui/react/select";import{Field as s}from"@base-ui/react/field";import{CheckIcon as r,ChevronIcon as i}from"../../internal/icons.js";import{WidthSizer as n}from"../../internal/sizer.js";import{controlHeightClasses as o,controlTextLeadingClasses as c,cx as d,disabledClasses as m,fieldReadOnlyClasses as p,fieldRestClasses as u,focusWithinRingClasses as h,gapClasses as f,glassClasses as g,hasContent as x,iconClasses as v,metaTextClasses as b,paddingXClasses as N,radiusClasses as j,stackGapClasses as w,surfaceSlots as y,transitionClasses as I}from"../../internal/styles.js";const S=/* @__PURE__ */["group relative flex w-full cursor-pointer items-center select-none","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",I,h,v].join(" "),z=/* @__PURE__ */[g,"max-h-[min(20rem,var(--available-height))] overflow-y-auto overscroll-contain","min-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]"].join(" "),P=/* @__PURE__ */["relative flex cursor-pointer items-center gap-2 select-none","rounded-(--plass-radius-xs) py-1.5 pe-2 ps-7",I,"data-[highlighted]:bg-(--p-soft-hover) data-[highlighted]:text-(--p-accent)","data-[selected]:font-semibold data-[selected]:text-(--p-accent)","data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50","[outline:none]"].join(" ");export const PlSelect=/* @__PURE__ */l.forwardRef(function PlSelect({variant:h="glass",size:g="md",color:v="primary",density:I="default",elevation:V=0,items:$,value:k,defaultValue:O,onValueChange:R,placeholder:T,label:q,description:B,error:C,invalid:M,startIcon:W,fullWidth:_=!1,disabled:D=!1,readOnly:E=!1,required:L=!1,name:A,id:F,className:G,classNames:H,style:J,...K},Q){const U=x(C),X=M??U,Y=X?"danger":v,Z=l.useMemo(()=>$.map(e=>({label:e.label??String(e.value),value:e.value})),[$]),ee=l.useMemo(()=>[...$.map(e=>e.label??String(e.value)),...x(T)?[T]:[]],[$,T]);return a(s.Root,{disabled:D,invalid:X,className:["flex-col align-top",w[g],_?"flex w-full":"inline-flex",G??""].filter(Boolean).join(" "),style:{...y(Y,V),...J},...K,children:[q?e(s.Label,{className:d(b[g],"font-semibold",D?"text-(--plass-muted-fg)":"text-(--plass-fg)",H?.label),children:q}):null,a(t.Root,{id:F,name:A,items:Z,value:k,defaultValue:O,onValueChange:e=>R?.(e),disabled:D,readOnly:E,required:L,children:[a(t.Trigger,{ref:Q,className:[S,o[g],c[g],j[g],f[g],N[I][g],D?m[h]:E?`${p[h]} cursor-default`:u[h],H?.control].filter(Boolean).join(" "),children:[W?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)",children:W}):null,a("span",{className:"flex min-w-0 flex-1 flex-col",children:[e(t.Value,{className:["w-full truncate text-start","data-[placeholder]:text-(--plass-muted-fg)"].join(" "),placeholder:T}),e(n,{samples:ee})]}),e(t.Icon,{className:["flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)","[transition:rotate_var(--plass-duration)_var(--plass-ease)]","data-[popup-open]:rotate-180"].join(" "),children:e(i,{})})]}),e(t.Portal,{children:e(t.Positioner,{className:"plass-portal z-(--plass-z-portal) [outline:none]",sideOffset:6,alignItemWithTrigger:!1,children:e(t.Popup,{className:`${z} ${j[g]} ${c[g]}`,style:y(Y,3),children:$.map(l=>a(t.Item,{value:l.value,disabled:l.disabled,className:P,children:[e(t.ItemIndicator,{className:"absolute start-1.5 flex size-4 items-center justify-center",children:e(r,{})}),e(t.ItemText,{className:"truncate",children:l.label??String(l.value)})]},String(l.value)))})})})]}),B?e(s.Description,{className:d(b[g],"text-(--plass-muted-fg)",H?.description),children:B}):null,e(s.Error,U?{match:!0,className:d(b[g],"text-(--p-accent)",H?.error),children:C}:{className:d(b[g],"text-(--p-accent)",H?.error)})]})});
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PlPageLayoutCollapse, PlassSidebarSide } from '../../internal/page-layout.js';
|
|
3
|
+
import type { PlassColor, PlassDensity, PlassElevation, PlassSize, PlassVariant } from '../../types.js';
|
|
4
|
+
export type { PlassSidebarSide } from '../../internal/page-layout.js';
|
|
5
|
+
export interface PlSidebarProps extends Omit<React.ComponentPropsWithoutRef<'aside'>, 'color' | 'title'> {
|
|
6
|
+
/**
|
|
7
|
+
* Which end of the band it takes. Logical rather than physical — `start` is
|
|
8
|
+
* the left of an English page and the right of an Arabic one — because a
|
|
9
|
+
* navigation rail is beside the text it belongs to in every writing
|
|
10
|
+
* direction.
|
|
11
|
+
*
|
|
12
|
+
* Inside a `PlPageLayout` this is already decided by which slot the sidebar
|
|
13
|
+
* was handed to, and setting it again is only a way of disagreeing with the
|
|
14
|
+
* layout.
|
|
15
|
+
* @default 'start'
|
|
16
|
+
*/
|
|
17
|
+
side?: PlassSidebarSide;
|
|
18
|
+
/**
|
|
19
|
+
* How wide the column is — a number in pixels or any CSS length. Left out, it
|
|
20
|
+
* is the width `size` implies.
|
|
21
|
+
*
|
|
22
|
+
* With `resizable` it is only the width the sidebar *starts* at: dragging
|
|
23
|
+
* writes over it, and the caller hears about it through `onResize`.
|
|
24
|
+
*/
|
|
25
|
+
width?: number | string;
|
|
26
|
+
/** How narrow it may be dragged. @default 160 */
|
|
27
|
+
minWidth?: number | string;
|
|
28
|
+
/** And how wide. @default 480 */
|
|
29
|
+
maxWidth?: number | string;
|
|
30
|
+
/**
|
|
31
|
+
* Lets the reader drag the inner edge to change the column's width.
|
|
32
|
+
*
|
|
33
|
+
* Off by default. A sidebar that can be resized is a sidebar whose width is
|
|
34
|
+
* the reader's to remember, which means a caller who turns this on usually
|
|
35
|
+
* also wants to store what `onResizeEnd` reports.
|
|
36
|
+
* @default false
|
|
37
|
+
*/
|
|
38
|
+
resizable?: boolean;
|
|
39
|
+
/** Fires with the width in pixels while the edge is being dragged. */
|
|
40
|
+
onResize?: (width: number) => void;
|
|
41
|
+
/** Fires once, with the same number, when it is let go. */
|
|
42
|
+
onResizeEnd?: (width: number) => void;
|
|
43
|
+
/**
|
|
44
|
+
* The window width below which the sidebar stops being a column and becomes a
|
|
45
|
+
* drawer that is opened — with a `PlSidebarTrigger` somewhere on the page as
|
|
46
|
+
* the way to open it. `none` keeps it a column at every width.
|
|
47
|
+
*
|
|
48
|
+
* Defaults to the `PlPageLayout`'s own `collapseBelow`, and to `none` outside
|
|
49
|
+
* one: a sidebar that collapsed with nothing on the page able to bring it
|
|
50
|
+
* back would be a sidebar the reader has lost.
|
|
51
|
+
*/
|
|
52
|
+
collapseBelow?: PlPageLayoutCollapse;
|
|
53
|
+
/**
|
|
54
|
+
* Whether the drawer is open. Only meaningful once the sidebar has collapsed;
|
|
55
|
+
* a column is not opened, it is there.
|
|
56
|
+
*
|
|
57
|
+
* Inside a `PlPageLayout` the layout owns this — it is what a trigger
|
|
58
|
+
* anywhere on the page talks to — so control it there rather than here.
|
|
59
|
+
* `onOpenChange` still fires either way.
|
|
60
|
+
*/
|
|
61
|
+
open?: boolean;
|
|
62
|
+
/** Which state it starts in, for an uncontrolled standalone sidebar. @default false */
|
|
63
|
+
defaultOpen?: boolean;
|
|
64
|
+
onOpenChange?: (open: boolean) => void;
|
|
65
|
+
/**
|
|
66
|
+
* Whether the column holds its place while the page scrolls past it.
|
|
67
|
+
*
|
|
68
|
+
* On by default, and it costs nothing when it is not needed: with the page
|
|
69
|
+
* scrolling it becomes a `sticky` column as tall as what is left of the
|
|
70
|
+
* window under the header, and with only the content scrolling it is already
|
|
71
|
+
* as tall as the layout and this changes nothing.
|
|
72
|
+
* @default true
|
|
73
|
+
*/
|
|
74
|
+
sticky?: boolean;
|
|
75
|
+
/**
|
|
76
|
+
* The heading, drawn only while the sidebar is a drawer. A column has the
|
|
77
|
+
* page around it to say what it is; a panel that has covered the page does
|
|
78
|
+
* not.
|
|
79
|
+
*/
|
|
80
|
+
title?: React.ReactNode;
|
|
81
|
+
/**
|
|
82
|
+
* What the sheet is made of, said the way a **container** says it: the panel
|
|
83
|
+
* is never dyed, because what is on it arrives with colours of its own.
|
|
84
|
+
* @default 'glass'
|
|
85
|
+
*/
|
|
86
|
+
variant?: PlassVariant;
|
|
87
|
+
/** The panel's scale — its default width and the air around its content. @default 'md' */
|
|
88
|
+
size?: PlassSize;
|
|
89
|
+
/** @default 'primary' */
|
|
90
|
+
color?: PlassColor;
|
|
91
|
+
/** @default 'default' */
|
|
92
|
+
density?: PlassDensity;
|
|
93
|
+
/** Drop shadow depth. `0` — the default — is flat. @default 0 */
|
|
94
|
+
elevation?: PlassElevation;
|
|
95
|
+
/**
|
|
96
|
+
* Draws a hairline down the inner edge — the one facing the content. The
|
|
97
|
+
* outer edge is against the window, where there is nothing on the other side
|
|
98
|
+
* to be separated from.
|
|
99
|
+
* @default true
|
|
100
|
+
*/
|
|
101
|
+
divider?: boolean;
|
|
102
|
+
/** The gutter and the air above and below the content. @default true */
|
|
103
|
+
padded?: boolean;
|
|
104
|
+
/**
|
|
105
|
+
* The name the region is announced by. Every `<aside>` on a page should have
|
|
106
|
+
* one, and a page with two sidebars *must*, or a screen reader offers two
|
|
107
|
+
* regions called "complementary".
|
|
108
|
+
* @default 'Sidebar'
|
|
109
|
+
*/
|
|
110
|
+
label?: string;
|
|
111
|
+
/** What the drawer's close button says, once the sidebar has collapsed. @default 'Close sidebar' */
|
|
112
|
+
closeLabel?: string;
|
|
113
|
+
/** What the drag handle is announced as. @default 'Resize sidebar' */
|
|
114
|
+
resizeLabel?: string;
|
|
115
|
+
/** Everything in it: a nav, a filter panel, a table of contents. */
|
|
116
|
+
children?: React.ReactNode;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* A column beside the page's content, and a drawer once the window is too
|
|
120
|
+
* narrow to hold one.
|
|
121
|
+
*
|
|
122
|
+
* Two presentations of one panel, exactly as `PlDrawer` is: above
|
|
123
|
+
* `collapseBelow` it is an `<aside>` in the layout that the content is laid out
|
|
124
|
+
* around, and below it the same children are a drawer over a scrim with a focus
|
|
125
|
+
* trap, an Escape and a way back to the trigger. They are one component because
|
|
126
|
+
* they are one thing — a caller should not have to swap components at a
|
|
127
|
+
* breakpoint — and because the children only exist once either way, so nothing
|
|
128
|
+
* inside is rendered twice into the document for a screen reader to read twice.
|
|
129
|
+
*
|
|
130
|
+
* Which of the two is showing is a media query, and it is answered in CSS for
|
|
131
|
+
* the first paint and in JavaScript from then on. That split is deliberate: the
|
|
132
|
+
* markup a server sends is the column, so a narrow screen would draw a full
|
|
133
|
+
* width sidebar and throw it away a moment later — the class that hides it
|
|
134
|
+
* below the breakpoint is what stops that, and `matchMedia` is what decides,
|
|
135
|
+
* once there is a window to ask, that the drawer should exist at all.
|
|
136
|
+
*
|
|
137
|
+
* A real `<aside>`, which is the `complementary` landmark: the region a screen
|
|
138
|
+
* reader offers as "related to the page but not the page", and what a search
|
|
139
|
+
* engine reads as navigation chrome rather than as the article.
|
|
140
|
+
*/
|
|
141
|
+
export declare const PlSidebar: React.ForwardRefExoticComponent<PlSidebarProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as r from"react";import{PlDrawer as n}from"../drawer/PlDrawer.js";import{drawerSide as o,expandedOnlyClasses as s,PlPageLayoutContext as i,PlassSidebarSideContext as a,useCollapsed as l}from"../../internal/page-layout.js";import{cx as d,sheetPaddingXClasses as c,sheetPaddingYClasses as u,sheetRestClasses as p,surfaceSlots as m,toLength as f,transitionClasses as y}from"../../internal/styles.js";const b={xs:"11rem",sm:"13rem",md:"16rem",lg:"18rem",xl:"21rem"},v=p;function toPixels(e,t){if(null==e)return t;if("number"==typeof e)return e;const r=/^\s*(-?[\d.]+)\s*(px|rem|em|%)\s*$/.exec(e);if(!r)return t;const n=Number(r[1]);if(Number.isNaN(n))return t;switch(r[2]){case"px":return n;case"%":return"undefined"==typeof window?t:window.innerWidth*n/100;default:return n*parseFloat(("undefined"==typeof document?"":getComputedStyle(document.documentElement).fontSize)||"16")}}export const PlSidebar=/* @__PURE__ */r.forwardRef(function PlSidebar({side:p,width:g,minWidth:w=160,maxWidth:h=480,resizable:x=!1,onResize:P,onResizeEnd:C,collapseBelow:k,open:z,defaultOpen:L=!1,onOpenChange:R,sticky:E=!0,title:N,variant:S="glass",size:j="md",color:B="primary",density:D="default",elevation:O=0,divider:A=!0,padded:M=!0,label:W="Sidebar",closeLabel:I="Close sidebar",resizeLabel:T="Resize sidebar",className:X,style:$,children:_,...F},K){const V=r.useContext(i),q=r.useContext(a),G=p??q??"start",H=k??(V.present?V.collapseBelow:"none"),J=l(H),[Q,U]=r.useState(L),Y=void 0!==z,Z=Y?z:V.present?V.open[G]:Q,ee=f(g)??b[j],te=r.useRef(null),re=r.useCallback(e=>{te.current=e,"function"==typeof K?K(e):K&&(K.current=e)},[K]),ne=r.useRef(null);r.useEffect(()=>()=>ne.current?.(),[]);const applyWidth=e=>{const t=te.current;if(!t)return e;const r=Math.min(toPixels(h,480),Math.max(toPixels(w,160),Math.round(e)));return t.style.setProperty("--p-sidebar-w",`${r}px`),r};return J?e(n,{side:o(G),mode:"overlay",open:Z,onOpenChange:e=>{Y||(V.present?V.setOpen(G,e):U(e)),R?.(e)},title:N,size:j,color:B,density:D,closeLabel:I,extent:void 0===g?void 0:ee,"aria-label":N?void 0:W,className:X,style:$,children:_}):t("aside",{ref:re,"aria-label":W,className:d("relative flex min-w-0 shrink-0 flex-col","w-(--p-sidebar-w)",v[S],A?d("start"===G?"border-e":"border-s","[border-color:var(--plass-divider)]"):"","content"===V.scroll?"h-full":E?d("self-start","sticky [top:var(--p-layout-header,0px)]","[height:calc(100dvh-var(--p-layout-header,0px)-var(--p-layout-footer,0px))]"):"",s[H],y,X),style:{...m(B,O),"--p-sidebar-w":ee,...$},...F,children:[e("div",{className:d("min-h-0 flex-1 overflow-y-auto overscroll-contain",M?d(c[D][j],u[D][j]):""),children:_}),x?e("div",{role:"separator","aria-orientation":"vertical","aria-label":T,tabIndex:0,className:d("absolute inset-y-0 z-1 w-2 cursor-col-resize","start"===G?"end-0 -me-1":"start-0 -ms-1","bg-transparent hover:bg-(--p-soft) data-[dragging]:bg-(--p-soft)",y,"[outline:none] focus-visible:[outline:2px_solid_var(--p-ring)]","focus-visible:[outline-offset:0px]"),onPointerDown:e=>{const t=te.current;if(!t||0!==e.button)return;const r=e.currentTarget;r.setPointerCapture(e.pointerId),r.dataset.dragging="true";const n=document.body.style.getPropertyValue("-webkit-user-select");document.body.style.setProperty("-webkit-user-select","none");const o=e.clientX,s=t.getBoundingClientRect().width,i="rtl"===getComputedStyle(t).direction,a="start"===G===i?-1:1;let l=s;const move=e=>{l=applyWidth(s+(e.clientX-o)*a),P?.(l)},release=()=>{ne.current=null,r.removeEventListener("pointermove",move),r.removeEventListener("pointerup",end),r.removeEventListener("pointercancel",end),delete r.dataset.dragging,n?document.body.style.setProperty("-webkit-user-select",n):document.body.style.removeProperty("-webkit-user-select")},end=()=>{release(),C?.(l)};ne.current=release,r.addEventListener("pointermove",move),r.addEventListener("pointerup",end),r.addEventListener("pointercancel",end)},onKeyDown:e=>{if("ArrowLeft"!==e.key&&"ArrowRight"!==e.key)return;e.preventDefault();const t="rtl"===getComputedStyle(e.currentTarget).direction,r="start"===G===t?-1:1;(e=>{const t=te.current;if(!t)return;const r=applyWidth(t.getBoundingClientRect().width+e);P?.(r),C?.(r)})(("ArrowRight"===e.key?16:-16)*r)}}):null]})});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PlIconButtonProps } from '../icon-button/PlIconButton.js';
|
|
3
|
+
import type { PlPageLayoutCollapse, PlassSidebarSide } from '../../internal/page-layout.js';
|
|
4
|
+
export interface PlSidebarTriggerProps extends Omit<PlIconButtonProps, 'icon' | 'label'> {
|
|
5
|
+
/** Which of the layout's two sidebars it opens. @default 'start' */
|
|
6
|
+
side?: PlassSidebarSide;
|
|
7
|
+
/**
|
|
8
|
+
* The width below which the button appears — the same one the sidebar
|
|
9
|
+
* collapses at, since the button exists exactly while the sidebar does not.
|
|
10
|
+
* Inherited from the `PlPageLayout`, which is where it should be set.
|
|
11
|
+
*/
|
|
12
|
+
collapseBelow?: PlPageLayoutCollapse;
|
|
13
|
+
/** The glyph. A hamburger, drawn here, unless something else is given. */
|
|
14
|
+
icon?: React.ReactNode;
|
|
15
|
+
/** What it does, in words. @default 'Open sidebar' / 'Close sidebar' */
|
|
16
|
+
label?: string;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* The button that brings back a `PlSidebar` the window has become too narrow to
|
|
20
|
+
* hold.
|
|
21
|
+
*
|
|
22
|
+
* It is drawn only while that is true, and the "while" is a media query rather
|
|
23
|
+
* than a piece of state: the button carries a class that hides it at and above
|
|
24
|
+
* the breakpoint. That matters more than it looks — a trigger whose presence
|
|
25
|
+
* depended on `matchMedia` would be absent from the markup a server sends and
|
|
26
|
+
* would pop into the header a moment after the page arrived, on every phone,
|
|
27
|
+
* every time.
|
|
28
|
+
*
|
|
29
|
+
* Put it in a `PlHeader`'s `brand` slot, ahead of the logo, which is where
|
|
30
|
+
* thirty years of hamburgers have taught readers to look for it. It has to be
|
|
31
|
+
* inside a `PlPageLayout` to have something to open; outside one there is no
|
|
32
|
+
* sidebar it could be talking about, and it renders nothing.
|
|
33
|
+
*/
|
|
34
|
+
export declare const PlSidebarTrigger: React.ForwardRefExoticComponent<PlSidebarTriggerProps & React.RefAttributes<HTMLButtonElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e}from"react/jsx-runtime";import*as r from"react";import{PlIconButton as n}from"../icon-button/PlIconButton.js";import{collapsedOnlyClasses as o,PlPageLayoutContext as t}from"../../internal/page-layout.js";import{cx as i}from"../../internal/styles.js";function MenuIcon(){return e("svg",{viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:"2","aria-hidden":"true",children:e("path",{d:"M4 7h16M4 12h16M4 17h16",strokeLinecap:"round"})})}export const PlSidebarTrigger=/* @__PURE__ */r.forwardRef(function PlSidebarTrigger({side:a="start",collapseBelow:s,icon:l,label:c,variant:u="ghost",className:p,onClick:d,...m},f){const h=r.useContext(t);if(!h.present)return null;const b=s??h.collapseBelow,g=h.open[a];return e(n,{ref:f,variant:u,icon:l??e(MenuIcon,{}),label:c??(g?"Close sidebar":"Open sidebar"),"aria-expanded":g,className:i(o[b],p),onClick:e=>{h.setOpen(a,!g),d?.(e)},...m})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{PlSidebar}from"./PlSidebar.js";export{PlSidebarTrigger}from"./PlSidebarTrigger.js";
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { Switch as BaseUISwitch } from '@base-ui/react/switch';
|
|
3
|
-
import type { PlassAlign, PlassColor, PlassSize } from '../../types.js';
|
|
3
|
+
import type { PlassAlign, PlassColor, PlassFieldClassNames, PlassSize } from '../../types.js';
|
|
4
4
|
/** Which side of the track the label sits on. */
|
|
5
5
|
export type PlSwitchLabelPlacement = Extract<PlassAlign, 'start' | 'end'>;
|
|
6
6
|
type BaseSwitchProps = Omit<React.ComponentPropsWithoutRef<typeof BaseUISwitch.Root>, 'className' | 'style' | 'render' | 'children'>;
|
|
7
7
|
export interface PlSwitchProps extends BaseSwitchProps {
|
|
8
|
+
/** Classes on the parts a `className` does not reach. */
|
|
9
|
+
classNames?: PlassFieldClassNames;
|
|
8
10
|
/** @default 'md' */
|
|
9
11
|
size?: PlassSize;
|
|
10
12
|
/** @default 'primary' */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as
|
|
1
|
+
"use client";import{jsx as e,jsxs as a,Fragment as r}from"react/jsx-runtime";import*as t from"react";import{Switch as l}from"@base-ui/react/switch";import{Field as s}from"@base-ui/react/field";import{controlSlots as c,cx as i,focusRingClasses as n,hasContent as o,metaTextClasses as d,tickRowTextClasses as h}from"../../internal/styles.js";const m={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"},p={xs:"data-[checked]:left-[calc(100%-0.75rem)]",sm:"data-[checked]:left-[calc(100%-0.875rem)]",md:"data-[checked]:left-[calc(100%-1.125rem)]",lg:"data-[checked]:left-[calc(100%-1.375rem)]",xl:"data-[checked]:left-[calc(100%-1.625rem)]"},f=/* @__PURE__ */["relative inline-flex shrink-0 rounded-full","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","[transition-property:background-color,background-image,box-shadow,filter]","[transition-duration:var(--plass-duration)]","[transition-timing-function:var(--plass-ease)]",n].join(" "),u=/* @__PURE__ */["cursor-pointer bg-(--plass-track)","hover:brightness-[0.97] dark:hover:brightness-110","data-[checked]:[background-image:var(--p-fill)]","data-[checked]:[box-shadow:var(--p-lift)] data-[checked]:hover:brightness-105"].join(" "),g=/* @__PURE__ */["cursor-default bg-(--plass-track) saturate-[0.55]","data-[checked]:[background-image:var(--p-fill)]","data-[checked]:shadow-none"].join(" "),b=/* @__PURE__ */["cursor-not-allowed bg-(--plass-track)","opacity-50 saturate-[0.35] shadow-none","data-[checked]:[background-image:var(--p-fill)]"].join(" "),x=/* @__PURE__ */["absolute inset-y-0.5 left-0.5 aspect-square rounded-full bg-white","[box-shadow:0_1px_2px_rgb(20_40_90/0.25)]","[transition:left_var(--plass-duration)_var(--plass-ease)]"].join(" ");export const PlSwitch=/* @__PURE__ */t.forwardRef(function PlSwitch({size:t="md",color:n="primary",label:k,description:w,error:v,invalid:N,labelPlacement:j="end",disabled:y=!1,readOnly:_=!1,className:P,classNames:R,style:S,...$},B){const O=o(v),q=N??O,z=q?"danger":n,D=e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(l.Root,{ref:B,className:i(f,m[t],y?b:_?g:u,R?.control),disabled:y,readOnly:_,...$,children:e(l.Thumb,{className:`${x} ${p[t]}`})})}),E=k||w?a("span",{className:["flex min-w-0 flex-col gap-0.5","start"===j?"flex-1":""].filter(Boolean).join(" "),children:[k?e(s.Label,{className:i(y?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",R?.label),children:k}):null,w?e(s.Description,{className:i(d[t],"text-(--plass-muted-fg)",R?.description),children:w}):null]}):null;return a(s.Root,{disabled:y,invalid:q,className:["inline-flex flex-col gap-1 align-top",P??""].filter(Boolean).join(" "),style:{...c(z,0,"solid"),...S},children:[e("div",{className:`flex items-start gap-2.5 ${h[t]}`,children:a(r,"start"===j?{children:[E,D]}:{children:[D,E]})}),e(s.Error,O?{match:!0,className:i(d[t],"text-(--p-accent)",R?.error),children:v}:{className:i(d[t],"text-(--p-accent)",R?.error)})]})});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import type { PlassElevation, PlassStyleProps } from '../../types.js';
|
|
2
|
+
import type { PlassElevation, PlassFieldClassNames, PlassStyleProps } from '../../types.js';
|
|
3
3
|
/** How the multiline control may be resized by the user. Ignored when single line. */
|
|
4
4
|
export type PlTextFieldResize = 'none' | 'vertical' | 'horizontal' | 'both';
|
|
5
5
|
/**
|
|
@@ -9,6 +9,8 @@ export type PlTextFieldResize = 'none' | 'vertical' | 'horizontal' | 'both';
|
|
|
9
9
|
*/
|
|
10
10
|
type NativeControlProps = Omit<React.ComponentPropsWithoutRef<'input'>, 'color' | 'size' | 'onChange' | 'children'>;
|
|
11
11
|
export interface PlTextFieldProps extends PlassStyleProps, NativeControlProps {
|
|
12
|
+
/** Classes on the parts a `className` does not reach. */
|
|
13
|
+
classNames?: PlassFieldClassNames;
|
|
12
14
|
/**
|
|
13
15
|
* Drop shadow depth. `0` is the default — a field is a well cut into the
|
|
14
16
|
* sheet, not a key resting on it, and the one place in the library where a
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as l from"react";import{Field as
|
|
1
|
+
"use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as l from"react";import{Field as s}from"@base-ui/react/field";import{Input as r}from"@base-ui/react/input";import{Spinner as n}from"../../internal/icons.js";import{controlHeightClasses as a,controlTextLeadingClasses as i,cx as o,disabledClasses as c,fieldReadOnlyClasses as m,fieldRestClasses as d,focusWithinRingClasses as p,gapClasses as x,hasContent as u,iconClasses as f,metaTextClasses as h,paddingXClasses as g,radiusClasses as $,stackGapClasses as b,surfaceSlots as y,transitionClasses as N}from"../../internal/styles.js";const v={xs:`${x.xs} ${$.xs} ${i.xs}`,sm:`${x.sm} ${$.sm} ${i.sm}`,md:`${x.md} ${$.md} ${i.md}`,lg:`${x.lg} ${$.lg} ${i.lg}`,xl:`${x.xl} ${$.xl} ${i.xl}`},w={xs:"min-h-6 py-[3px]",sm:"min-h-8 py-[6px]",md:"min-h-10 py-[9px]",lg:"min-h-12 py-[11px]",xl:"min-h-14 py-[13px]"},j={none:"resize-none",vertical:"resize-y",horizontal:"resize-x",both:"resize"},z=/* @__PURE__ */["group relative flex w-full cursor-text","[-webkit-tap-highlight-color:transparent]",N,p,f].join(" "),k=d,D=m;export const PlTextField=/* @__PURE__ */l.forwardRef(function PlTextField({variant:i="glass",size:m="md",color:d="primary",density:p="default",elevation:x=0,multiline:f=!1,rows:$=3,resize:N="vertical",label:P,description:R,error:T,invalid:B,startIcon:F,endIcon:I,loading:O=!1,fullWidth:C=!1,readOnly:E=!1,disabled:L=!1,type:W="text",className:q,classNames:A,style:G,...H},J){const K=u(T),M=B??K,Q=M?"danger":d,S=l.useRef(null),U=l.useCallback(e=>{S.current=e,"function"==typeof J?J(e):J&&(J.current=e)},[J]),V=[z,v[m],f?`${w[m]} items-start`:`${a[m]} items-center`,g[p][m],L?c[i]:E?D[i]:k[i]].filter(Boolean).join(" "),X=["min-w-0 flex-1 bg-transparent [font:inherit] text-inherit","[outline:none]","placeholder:text-(--plass-muted-fg)","caret-(--p-accent) selection:bg-(--p-soft-press)","disabled:cursor-not-allowed",f?`block ${j[N]}`:"self-stretch"].join(" "),Y="inline-flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg) transition-[color] duration-(--plass-duration) group-focus-within:text-(--p-accent)";return t(s.Root,{disabled:L,invalid:M,className:["flex-col align-top",b[m],C?"flex w-full":"inline-flex",q??""].filter(Boolean).join(" "),style:{...y(Q,x),...G},children:[P?e(s.Label,{className:o(h[m],"font-semibold",L?"text-(--plass-muted-fg)":"text-(--plass-fg)",A?.label),children:P}):null,t("span",{className:o(V,A?.control),onPointerDown:e=>{e.target!==e.currentTarget||L||(e.preventDefault(),S.current?.focus())},children:[F?e("span",{className:Y,children:F}):null,e(r,{ref:U,className:X,disabled:L,readOnly:E,"aria-busy":O||void 0,"data-loading":O||void 0,...f?{render:e("textarea",{rows:$})}:{type:W},...H}),O?e("span",{className:Y,children:e(n,{})}):I?e("span",{className:Y,children:I}):null]}),R?e(s.Description,{className:o(h[m],"text-(--plass-muted-fg)",A?.description),children:R}):null,e(s.Error,K?{match:!0,className:o(h[m],"text-(--p-accent)",A?.error),children:T}:{className:o(h[m],"text-(--p-accent)",A?.error)})]})});
|
|
@@ -71,8 +71,17 @@ export interface PlTextLinkProps extends Omit<React.ComponentPropsWithoutRef<'a'
|
|
|
71
71
|
newTabLabel?: string;
|
|
72
72
|
/**
|
|
73
73
|
* Renders something other than an `<a>` — the `Link` a router brings, most of
|
|
74
|
-
* the time.
|
|
75
|
-
*
|
|
74
|
+
* the time.
|
|
75
|
+
*
|
|
76
|
+
* **An `href` on what comes back wins.** A router's `Link` does not pass its
|
|
77
|
+
* address through; it *resolves* one — a locale prefix, a base path, a typed
|
|
78
|
+
* route — and hands the anchor the result. So when the element carries an
|
|
79
|
+
* `href` of its own, this component's is not merged over it, and the router
|
|
80
|
+
* keeps what it worked out. Written the other way round, every localised link
|
|
81
|
+
* in an app silently lost its prefix.
|
|
82
|
+
*
|
|
83
|
+
* The element having none is the ordinary case (`render={<a />}`), and there
|
|
84
|
+
* the `href` above is used.
|
|
76
85
|
*/
|
|
77
86
|
render?: useRender.RenderProp;
|
|
78
87
|
/** The label. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as n,Fragment as e,jsxs as r}from"react/jsx-runtime";import*as s from"react";import{useRender as i}from"@base-ui/react/use-render";import{ExternalLinkIcon as l,LinkIcon as a}from"../../internal/icons.js";import{controlTextLeadingClasses as o,focusRingClasses as t,srOnlyClasses as c}from"../../internal/styles.js";const
|
|
1
|
+
"use client";import{jsx as n,Fragment as e,jsxs as r}from"react/jsx-runtime";import*as s from"react";import{useRender as i}from"@base-ui/react/use-render";import{ExternalLinkIcon as l,LinkIcon as a}from"../../internal/icons.js";import{controlTextLeadingClasses as o,focusRingClasses as t,srOnlyClasses as c}from"../../internal/styles.js";import{safeRel as p}from"../../internal/link.js";const m={always:"[&.plass-link]:underline",hover:"[&.plass-link]:no-underline [&.plass-link]:hover:underline",none:"[&.plass-link]:no-underline"},d=/* @__PURE__ */["plass-link","cursor-pointer","[&_svg]:pointer-events-none [&_svg]:inline [&_svg]:size-[0.95em] [&_svg]:shrink-0",/* @__PURE__ */["[transition-property:color,text-decoration-color]","[transition-duration:var(--plass-duration)]","[transition-timing-function:var(--plass-ease)]"].join(" "),t,"focus-visible:rounded-[0.25rem]"].join(" ");export const PlTextLink=/* @__PURE__ */s.forwardRef(function PlTextLink({href:t,underline:u="always",color:f,size:v,newTab:h=!1,icon:k,startIcon:x,newTabLabel:b="(opens in a new tab)",render:g,className:j,style:y,children:w,..._},N){const T=k??h,L=!0===T?n(h?l:a,{}):T,z=[d,v?o[v]:"",m[u],f?"[&.plass-link]:text-(--p-accent)":"[&.plass-link]:text-inherit",j??""].filter(Boolean).join(" "),C={"--p-underline":"color-mix(in oklab, currentColor 45%, transparent)","--p-underline-hover":"currentColor","--p-ring":`var(--plass-${f??"primary"}-ring)`,...f?{"--p-accent":`var(--plass-${f}-accent)`}:null},P=s.isValidElement(g)&&void 0!==g.props.href,{rel:$,...B}=_,E=p(h?"_blank":void 0,$);return i({render:g??n("a",{}),ref:N,props:{...P?null:{href:t},target:h?"_blank":void 0,className:z,style:{...C,...y},children:r(e,{children:[x?n("span",{className:"me-[0.25em]",children:x}):null,w,L?n("span",{className:"ms-[0.25em]",children:L}):null,h?r(e,{children:[" ",n("span",{className:c,children:b})]}):null]}),...B,rel:E}})});
|
|
@@ -18,6 +18,16 @@ export interface PlToastData {
|
|
|
18
18
|
color?: PlassColor;
|
|
19
19
|
variant?: PlassVariant;
|
|
20
20
|
icon?: React.ReactNode | false;
|
|
21
|
+
/**
|
|
22
|
+
* Classes on this toast, alongside the ones the provider gives every toast.
|
|
23
|
+
*
|
|
24
|
+
* A toast has no element a caller can put a `className` on — it is raised
|
|
25
|
+
* from a click handler rather than written into a tree — so the class travels
|
|
26
|
+
* with the message, in the same `data` the colour and the variant do.
|
|
27
|
+
*/
|
|
28
|
+
className?: string;
|
|
29
|
+
/** Inline styles on this toast, applied over the tokens it sets. */
|
|
30
|
+
style?: React.CSSProperties;
|
|
21
31
|
}
|
|
22
32
|
export interface PlToastOptions extends PlToastData {
|
|
23
33
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as t,jsxs as
|
|
1
|
+
"use client";import{jsx as t,jsxs as s}from"react/jsx-runtime";import*as e from"react";import{Toast as o}from"@base-ui/react/toast";import{CloseIcon as a,severityIcon as i}from"../../internal/icons.js";import{controlSlots as r,focusRingClasses as n,glassClasses as l,hasContent as c,iconClasses as p,metaTextClasses as d,radiusClasses as m,sheetBodyClasses as u,sheetHeaderGapClasses as f,sheetPaddingXClasses as h,sheetPaddingYClasses as g,sheetSectionGapClasses as v,sheetTitleClasses as x}from"../../internal/styles.js";const b={"top-start":"top-0 items-start","top-center":"top-0 items-center","top-end":"top-0 items-end","bottom-start":"bottom-0 flex-col-reverse items-start","bottom-center":"bottom-0 flex-col-reverse items-center","bottom-end":"bottom-0 flex-col-reverse items-end"},y={solid:/* @__PURE__ */["text-(--p-on-solid) [background-image:var(--p-fill)]","[box-shadow:var(--plass-shadow-3),var(--p-lift)]"].join(" "),glass:/* @__PURE__ */[l,"border text-(--plass-fg) bg-(--plass-glass-press)","[border-color:var(--p-line)]","[box-shadow:var(--plass-shadow-3),var(--plass-gloss-glass)]"].join(" "),ghost:/* @__PURE__ */[l,"text-(--plass-fg) bg-(--plass-glass-press)","[box-shadow:var(--plass-shadow-3),var(--plass-gloss-glass)]"].join(" ")},w={solid:"",glass:"text-(--p-accent)",ghost:"text-(--p-accent)"};function toManagerOptions(t){const{color:s,variant:e,icon:o,className:a,style:i,actionLabel:r,onAction:n,...l}=t;return{...l,data:{color:s,variant:e,icon:o,className:a,style:i},actionProps:void 0===r?void 0:{children:r,onClick:n}}}export function usePlToast(){const t=o.useToastManager();return e.useMemo(()=>({add:s=>t.add(toManagerOptions(s)),close:s=>t.close(s),update:(s,e)=>t.update(s,toManagerOptions(e)),promise:(s,e)=>t.promise(s,{loading:toManagerOptions(e.loading),success:t=>toManagerOptions("function"==typeof e.success?e.success(t):e.success),error:t=>toManagerOptions("function"==typeof e.error?e.error(t):e.error)}),toasts:t.toasts}),[t])}function ToastItem({toast:e,variant:l,color:b,size:j,density:N,closeLabel:T,swipeDirection:M}){const z=e.data?.variant??l??"glass",O=e.data?.color??b,P=void 0===e.data?.icon?i(O):e.data.icon,k=w[z],$=c(e.title);return s(o.Root,{toast:e,swipeDirection:M,className:["pointer-events-auto flex w-full items-start",h[N??"default"][j],g[N??"default"][j],m[j],v[j],u[j],y[z],p,"[transition:opacity_var(--plass-duration)_var(--plass-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0","data-[limited]:hidden",n,"[outline:none]",e.data?.className??""].filter(Boolean).join(" "),style:{...r(O,3,z),...e.data?.style},children:[c(P)?t("span",{className:`flex h-[1lh] shrink-0 items-center ${k}`,children:P}):null,s("div",{className:`flex min-w-0 flex-1 flex-col ${f[j]}`,children:[t(o.Title,{className:`plass-title font-semibold ${x[j]} ${k}`}),t(o.Description,{className:$&&"solid"!==z?"text-(--plass-muted-fg)":""})]}),t(o.Action,{className:["flex h-[1lh] shrink-0 cursor-pointer items-center rounded-full px-2","font-medium underline-offset-2",k||"text-(--p-on-solid)","hover:underline",n,d[j]].join(" ")}),t("span",{className:"flex h-[1lh] shrink-0 items-center",children:t(o.Close,{"aria-label":T,className:["inline-flex size-[1.15em] cursor-pointer items-center justify-center rounded-full","opacity-70 [transition:opacity_var(--plass-duration)_var(--plass-ease)]","hover:opacity-100 focus-visible:opacity-100",n].join(" "),children:t(a,{})})})]})}function ToastViewport(s){const{toasts:e}=o.useToastManager(),{position:a,width:i,...r}=s,n=[a.startsWith("top")?"up":"down","left","right"];return t(o.Portal,{children:t(o.Viewport,{className:["plass-portal pointer-events-none fixed inset-x-0 z-(--plass-z-portal) flex flex-col gap-2 p-4",b[a]].join(" "),children:e.map(s=>t("div",{className:"w-full",style:{maxWidth:"number"==typeof i?`${i}px`:i},children:t(ToastItem,{toast:s,swipeDirection:n,...r})},s.id))})})}export function PlToastProvider({variant:e="glass",size:a="md",color:i="primary",density:r="default",position:n="bottom-end",timeout:l=5e3,limit:c=3,width:p=380,closeLabel:d="Close",children:m}){return s(o.Provider,{timeout:l,limit:c,children:[m,t(ToastViewport,{position:n,variant:e,size:a,color:i,density:r,width:p,closeLabel:d})]})}
|