plass-ui 1.0.3 → 1.1.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 +169 -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.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.js +1 -1
- package/dist/components/command-palette/PlCommandPalette.d.ts +83 -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/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/menubar/PlMenubar.d.ts +56 -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/navigation-menu/PlNavigationMenu.d.ts +99 -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.js +1 -1
- package/dist/components/otp-field/PlOtpField.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.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.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.js +1 -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/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/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/package.json +3 -3
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PlassOrientation, PlassStyleProps } from '../../types.js';
|
|
3
|
+
export interface PlNavigationMenuProps extends Pick<PlassStyleProps, 'size' | 'color' | 'density'>, Omit<React.ComponentPropsWithoutRef<'nav'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
4
|
+
/**
|
|
5
|
+
* Which way the row runs. `vertical` is a nav rail whose panels open beside
|
|
6
|
+
* it; the arrow keys follow either way.
|
|
7
|
+
* @default 'horizontal'
|
|
8
|
+
*/
|
|
9
|
+
orientation?: PlassOrientation;
|
|
10
|
+
/** Which item's panel is open, by its `value`. Nullish means closed. */
|
|
11
|
+
value?: string | null;
|
|
12
|
+
/** Which starts open, for an uncontrolled menu. */
|
|
13
|
+
defaultValue?: string | null;
|
|
14
|
+
onValueChange?: (value: string | null) => void;
|
|
15
|
+
/** How long the pointer rests before a panel opens, in milliseconds. */
|
|
16
|
+
delay?: number;
|
|
17
|
+
/** How long a panel stays after the pointer leaves, in milliseconds. */
|
|
18
|
+
closeDelay?: number;
|
|
19
|
+
/** Distance from the row, in pixels. @default 8 */
|
|
20
|
+
sideOffset?: number;
|
|
21
|
+
/** The items. */
|
|
22
|
+
children?: React.ReactNode;
|
|
23
|
+
}
|
|
24
|
+
export interface PlNavigationMenuItemProps {
|
|
25
|
+
/** The word in the row. */
|
|
26
|
+
label: React.ReactNode;
|
|
27
|
+
/**
|
|
28
|
+
* Makes the item a plain link rather than something that opens a panel. An
|
|
29
|
+
* item with an `href` and no children is a destination, and it is announced
|
|
30
|
+
* as one — which is the whole reason a site nav is not a `PlMenu`.
|
|
31
|
+
*/
|
|
32
|
+
href?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Where the link opens. Ignored without `href`.
|
|
35
|
+
*
|
|
36
|
+
* Anything other than this tab also gets `rel="noopener noreferrer"`, merged
|
|
37
|
+
* with whatever `rel` was asked for, exactly as on `PlTextLink`.
|
|
38
|
+
*/
|
|
39
|
+
target?: string;
|
|
40
|
+
/** The link's `rel`. The two tokens a new tab needs are added to it. */
|
|
41
|
+
rel?: string;
|
|
42
|
+
/** Content before the label. Sized in `em`, so it tracks it. */
|
|
43
|
+
startIcon?: React.ReactNode;
|
|
44
|
+
/**
|
|
45
|
+
* Identifies the item, for a controlled menu. Left out is fine for an
|
|
46
|
+
* uncontrolled one — Base UI gives each item an identity of its own.
|
|
47
|
+
*/
|
|
48
|
+
value?: string;
|
|
49
|
+
/** Unavailable. The word stays in the row and opens nothing. */
|
|
50
|
+
disabled?: boolean;
|
|
51
|
+
/** How many columns the panel lays its links out in. @default 1 */
|
|
52
|
+
columns?: number;
|
|
53
|
+
/** The panel's contents — usually `PlNavigationMenuLink`s. */
|
|
54
|
+
children?: React.ReactNode;
|
|
55
|
+
}
|
|
56
|
+
export interface PlNavigationMenuLinkProps extends Omit<React.ComponentPropsWithoutRef<'a'>, 'color' | 'title'> {
|
|
57
|
+
/** Where it goes. */
|
|
58
|
+
href: string;
|
|
59
|
+
/** The row's name. */
|
|
60
|
+
title: React.ReactNode;
|
|
61
|
+
/** A second line under it, one step down the scale and muted. */
|
|
62
|
+
description?: React.ReactNode;
|
|
63
|
+
/** A glyph before the title. */
|
|
64
|
+
startIcon?: React.ReactNode;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* One row inside a panel: where it goes, what it is called, and a line saying
|
|
68
|
+
* what is there.
|
|
69
|
+
*
|
|
70
|
+
* It is a real `<a>`, which is the point of the whole component — a site's
|
|
71
|
+
* navigation is a list of destinations, and a destination that is a `<div>` with
|
|
72
|
+
* a click handler is not in the link list, not on the status bar and not in a
|
|
73
|
+
* crawler's index.
|
|
74
|
+
*/
|
|
75
|
+
export declare const PlNavigationMenuLink: React.ForwardRefExoticComponent<PlNavigationMenuLinkProps & React.RefAttributes<HTMLAnchorElement>>;
|
|
76
|
+
/**
|
|
77
|
+
* One word in the row, and what opens under it.
|
|
78
|
+
*
|
|
79
|
+
* With children it is a trigger and a panel; with an `href` and nothing else it
|
|
80
|
+
* is a link, and the difference is not cosmetic — the second is announced as a
|
|
81
|
+
* destination and the first as something that expands.
|
|
82
|
+
*/
|
|
83
|
+
export declare function PlNavigationMenuItem({ label, href, target, rel, startIcon, value, disabled, columns, children }: PlNavigationMenuItemProps): React.ReactElement;
|
|
84
|
+
/**
|
|
85
|
+
* A site's navigation: a row of destinations, some of which open a panel of
|
|
86
|
+
* more of them.
|
|
87
|
+
*
|
|
88
|
+
* The difference from a `PlMenu` is what the rows *are*. A menu holds actions,
|
|
89
|
+
* so its rows are `menuitem`s and the whole thing is a widget that traps the
|
|
90
|
+
* arrow keys. This holds links, so it is a `<nav>` full of real `<a>`s — which
|
|
91
|
+
* is what puts them in the link list, on the status bar and in a crawler's
|
|
92
|
+
* index. Reach for a menu when the row *does* something and for this when the
|
|
93
|
+
* row *goes* somewhere.
|
|
94
|
+
*
|
|
95
|
+
* One panel is open at a time and it resizes between items rather than closing
|
|
96
|
+
* and reopening, which is Base UI's doing and is what makes crossing the row
|
|
97
|
+
* read as one surface rather than three.
|
|
98
|
+
*/
|
|
99
|
+
export declare const PlNavigationMenu: React.ForwardRefExoticComponent<PlNavigationMenuProps & React.RefAttributes<HTMLElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as a,Fragment as t}from"react/jsx-runtime";import*as s from"react";import{NavigationMenu as n}from"@base-ui/react/navigation-menu";import{ChevronIcon as l}from"../../internal/icons.js";import{safeRel as r}from"../../internal/link.js";import{controlHeightClasses as i,controlTextClasses as o,controlTextLeadingClasses as d,cx as c,focusRingClasses as p,focusRingInsetClasses as u,gapClasses as m,glassClasses as f,hasContent as h,iconClasses as g,metaTextClasses as v,paddingXClasses as x,radiusClasses as y,surfaceSlots as N,transitionClasses as b}from"../../internal/styles.js";const w=/* @__PURE__ */s.createContext({size:"md",density:"default"}),j=/* @__PURE__ */["inline-flex shrink-0 cursor-pointer select-none items-center justify-center","whitespace-nowrap font-medium leading-none no-underline","text-(--plass-fg) bg-transparent","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",b,g,p,"hover:bg-(--p-soft)","data-[popup-open]:bg-(--p-soft-hover) data-[popup-open]:text-(--p-accent)","data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50","data-[disabled]:saturate-[0.35] data-[disabled]:hover:bg-transparent"].join(" "),P=/* @__PURE__ */[f,"relative border text-(--plass-fg) bg-(--plass-glass-press)","[border-color:var(--plass-glass-line)]","[box-shadow:var(--plass-shadow-3),var(--plass-gloss-glass)]","[outline:none] overflow-hidden","[transition:opacity_var(--plass-duration)_var(--plass-ease),width_var(--plass-duration)_var(--plass-ease),height_var(--plass-duration)_var(--plass-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),k=/* @__PURE__ */["flex min-w-0 cursor-pointer items-start no-underline","text-(--plass-fg) bg-transparent",b,g,"hover:bg-(--p-soft)",u].join(" "),z={xs:"p-1",sm:"p-1.5",md:"p-2",lg:"p-2.5",xl:"p-3"};export const PlNavigationMenuLink=/* @__PURE__ */s.forwardRef(function PlNavigationMenuLink({href:t,title:l,description:r,startIcon:i,className:o,children:p,...u},f){const{size:g,density:N}=s.useContext(w);return a(n.Link,{ref:f,href:t,className:c(k,y[g],m[g],x[N][g],"py-2",o),...u,children:[h(i)?e("span",{className:"flex h-[1lh] shrink-0 items-center",children:i}):null,a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[e("span",{className:c("font-medium",d[g]),children:l}),h(r)?e("span",{className:c("text-(--plass-muted-fg)",v[g]),children:r}):null,p]})]})});export function PlNavigationMenuItem({label:d,href:p,target:u,rel:f,startIcon:g,value:v,disabled:N=!1,columns:b=1,children:P}){const{size:k,density:_}=s.useContext(w),C=void 0!==p&&!h(P),M=c(j,i[k],o[k],m[k],x[_][k],y[k]);return e(n.Item,{value:v,children:C?a(n.Link,{href:p,target:u,rel:r(u,f),className:M,children:[h(g)?g:null,d]}):a(t,{children:[a(n.Trigger,{disabled:N,className:M,children:[h(g)?g:null,d,e(n.Icon,{className:"flex items-center [transition:rotate_var(--plass-duration)_var(--plass-ease)] data-[popup-open]:rotate-180",children:e(l,{})})]}),e(n.Content,{className:c("grid gap-1",z[k]),style:b>1?{gridTemplateColumns:`repeat(${b}, minmax(0, 1fr))`}:void 0,children:P})]})})}export const PlNavigationMenu=/* @__PURE__ */s.forwardRef(function PlNavigationMenu({size:t="md",color:l="primary",density:r="default",orientation:i="horizontal",value:o,defaultValue:d,onValueChange:p,delay:u,closeDelay:f,sideOffset:h=8,className:g,style:v,children:x,...b},j){const k=s.useMemo(()=>({size:t,density:r}),[t,r]);return e(w.Provider,{value:k,children:a(n.Root,{ref:j,orientation:i,value:o,defaultValue:d,onValueChange:e=>p?.(e),delay:u,closeDelay:f,className:g,style:{...N(l,3),...v},...b,children:[e(n.List,{className:c("flex items-center","vertical"===i?"flex-col items-stretch":"flex-row",m[t]),children:x}),e(n.Portal,{children:e(n.Positioner,{className:"plass-portal z-(--plass-z-portal) [outline:none]",sideOffset:h,collisionPadding:12,children:e(n.Popup,{className:c(P,y[t]),children:e(n.Viewport,{})})})})]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{PlNavigationMenu,PlNavigationMenuItem,PlNavigationMenuLink}from"./PlNavigationMenu.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as
|
|
1
|
+
"use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import{NumberField as l}from"@base-ui/react/number-field";import{Field as t}from"@base-ui/react/field";import{MinusIcon as s,PlusIcon as n}from"../../internal/icons.js";import{controlHeightClasses as r,controlTextLeadingClasses as i,disabledClasses as o,fieldReadOnlyClasses as c,fieldRestClasses as d,focusRingClasses as p,focusWithinRingClasses as m,gapClasses as u,hasContent as f,iconClasses as h,metaTextClasses as b,paddingXClasses as x,radiusClasses as g,stackGapClasses as v,surfaceSlots as N,transitionClasses as j}from"../../internal/styles.js";const y=/* @__PURE__ */["group relative flex w-full cursor-text items-center","[-webkit-tap-highlight-color:transparent]",j,"focus-within:[transition-duration:0ms]",m,h].join(" "),w=/* @__PURE__ */["inline-flex size-[1.7em] shrink-0 cursor-pointer items-center justify-center","rounded-(--plass-radius-xs) text-(--plass-muted-fg) select-none","[&_svg]:size-[0.9em] [&_svg]:shrink-0","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]","[transition:background-color_var(--plass-duration)_var(--plass-ease),color_var(--plass-duration)_var(--plass-ease),opacity_var(--plass-duration)_var(--plass-ease)]","active:[transition-duration:0ms]","hover:bg-(--p-soft) hover:text-(--p-accent)","active:bg-(--p-soft-press)",p,"disabled:cursor-not-allowed disabled:bg-transparent disabled:opacity-40"].join(" ");export function PlNumberField({variant:p="glass",size:m="md",color:h="primary",density:j="default",elevation:k=0,value:S,defaultValue:_,onValueChange:V,onValueCommitted:I,min:C,max:O,step:$,largeStep:z,smallStep:B,snapOnStep:D,allowWheelScrub:L=!1,format:W,locale:q,steppers:F="end",incrementLabel:R="Increase",decrementLabel:E="Decrease",label:G,description:P,error:A,invalid:H,startIcon:J,endIcon:K,fullWidth:M=!1,disabled:Q=!1,readOnly:T=!1,required:U=!1,name:X,placeholder:Y,id:Z,className:ee,style:ae,...le}){const te=f(A),se=H??te,ne=se?"danger":h,re=x[j][m],ie={end:`${re} pe-1`,split:"px-1",none:re},oe=e(l.Decrement,{"aria-label":E,className:w,children:e(s,{})}),ce=e(l.Increment,{"aria-label":R,className:w,children:e(n,{})}),de="none"!==F&&!T;return a(t.Root,{disabled:Q,invalid:se,className:["flex-col align-top",v[m],M?"flex w-full":"inline-flex",ee??""].filter(Boolean).join(" "),style:{...N(ne,k),...ae},...le,children:[G?e(t.Label,{className:[b[m],"font-medium text-(--plass-fg)",Q?"opacity-50":""].filter(Boolean).join(" "),children:G}):null,e(l.Root,{id:Z,name:X,className:"contents",value:S,defaultValue:_,onValueChange:e=>V?.(e),onValueCommitted:e=>I?.(e),min:C,max:O,step:$,largeStep:z,smallStep:B,snapOnStep:D,allowWheelScrub:L,format:W,locale:q,disabled:Q,readOnly:T,required:U,children:a(l.Group,{className:[y,r[m],i[m],g[m],u[m],de?ie[F]:re,Q?o[p]:T?c[p]:d[p]].join(" "),children:[de&&"split"===F?oe:null,J?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)",children:J}):null,e(l.Input,{placeholder:Y,className:["min-w-0 flex-1 self-stretch bg-transparent [font:inherit] text-inherit","[outline:none]","tabular-nums","split"===F&&de?"text-center":"","placeholder:text-(--plass-muted-fg)","caret-(--p-accent) selection:bg-(--p-soft-press)","disabled:cursor-not-allowed"].filter(Boolean).join(" ")}),K?e("span",{className:"flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg)",children:K}):null,de&&"end"===F?a("span",{className:"flex shrink-0 items-center gap-0.5",children:[oe,ce]}):null,de&&"split"===F?ce:null]})}),P?e(t.Description,{className:`${b[m]} text-(--plass-muted-fg)`,children:P}):null,e(t.Error,te?{match:!0,className:`${b[m]} text-(--p-accent)`,children:A}:{className:`${b[m]} text-(--p-accent)`})]})}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Field as l}from"@base-ui/react/field";import{OTPField as r}from"@base-ui/react/otp-field";import{cx as n,disabledClasses as s,fieldReadOnlyClasses as i,fieldRestClasses as o,hasContent as m,metaTextClasses as d,stackGapClasses as u,surfaceSlots as c,transitionClasses as p}from"../../internal/styles.js";const f={xs:"h-7 w-6",sm:"h-8 w-7",md:"h-10 w-8",lg:"h-12 w-10",xl:"h-14 w-12"},x={xs:"rounded-[0.3125rem]",sm:"rounded-[0.375rem]",md:"rounded-[0.4375rem]",lg:"rounded-[0.5625rem]",xl:"rounded-[0.6875rem]"},g={xs:"text-[0.8125rem]",sm:"text-[0.9375rem]",md:"text-[1.0625rem]",lg:"text-[1.25rem]",xl:"text-[1.5rem]"},h={default:{xs:"gap-1",sm:"gap-1",md:"gap-1.5",lg:"gap-2",xl:"gap-2.5"},compact:{xs:"gap-0.5",sm:"gap-0.5",md:"gap-1",lg:"gap-1",xl:"gap-1.5"}},y={numeric:"numeric",alpha:"alpha",alphanumeric:"alphanumeric",any:"none"};export const PlOtpField=/* @__PURE__ */t.forwardRef(function PlOtpField({variant:b="glass",size:v="md",color:N="primary",density:V="default",elevation:w=0,length:F=6,charset:j="numeric",mask:C=!1,groupSize:M,separator:O="–",value:I,defaultValue:R,onValueChange:S,onComplete:k,onValueInvalid:q,autoSubmit:z=!1,label:P,description:_,error:A,invalid:D,name:E,required:L=!1,disabled:T=!1,readOnly:B=!1,autoFocus:G=!1,className:H,style:J,...K},Q){const U=Math.min(12,Math.max(2,Math.round(F))),W=m(A),X=D??W,Y=X?"danger":N,Z=n("text-center font-medium [font-family:inherit]",f[v],g[v],x[v],p,"caret-(--p-accent) selection:bg-(--p-soft-press)","focus:[outline:2px_solid_var(--p-ring)] focus:[outline-offset:0px]","focus:[transition-duration:0ms]",T?s[b]:B?i[b]:o[b]),$=M&&M>0?Math.round(M):0;return a(l.Root,{disabled:T,invalid:X,className:n("inline-flex flex-col align-top",u[v],H),style:{...c(Y,w),...J},children:[m(P)?e(l.Label,{className:n(d[v],"font-medium",T?"text-(--plass-muted-fg)":"text-(--plass-fg)"),children:P}):null,e(r.Root,{ref:Q,length:U,validationType:y[j],mask:C,name:E,required:L,disabled:T,readOnly:B,autoSubmit:z,value:I,defaultValue:R,onValueChange:e=>S?.(e),onValueComplete:e=>k?.(e),onValueInvalid:e=>q?.(e),className:n("flex items-center",h[V][v]),...K,children:Array.from({length:U},(l,s)=>a(t.Fragment,{children:[$>0&&s>0&&s%$===0?e("span",{"aria-hidden":"true",className:n("select-none px-0.5 text-(--plass-muted-fg)",g[v]),children:O}):null,e(r.Input,{className:Z,autoFocus:G&&0===s})]},s))}),m(_)?e(l.Description,{className:n(d[v],"text-(--plass-muted-fg)"),children:_}):null,
|
|
1
|
+
"use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Field as l}from"@base-ui/react/field";import{OTPField as r}from"@base-ui/react/otp-field";import{cx as n,disabledClasses as s,fieldReadOnlyClasses as i,fieldRestClasses as o,hasContent as m,metaTextClasses as d,stackGapClasses as u,surfaceSlots as c,transitionClasses as p}from"../../internal/styles.js";const f={xs:"h-7 w-6",sm:"h-8 w-7",md:"h-10 w-8",lg:"h-12 w-10",xl:"h-14 w-12"},x={xs:"rounded-[0.3125rem]",sm:"rounded-[0.375rem]",md:"rounded-[0.4375rem]",lg:"rounded-[0.5625rem]",xl:"rounded-[0.6875rem]"},g={xs:"text-[0.8125rem]",sm:"text-[0.9375rem]",md:"text-[1.0625rem]",lg:"text-[1.25rem]",xl:"text-[1.5rem]"},h={default:{xs:"gap-1",sm:"gap-1",md:"gap-1.5",lg:"gap-2",xl:"gap-2.5"},compact:{xs:"gap-0.5",sm:"gap-0.5",md:"gap-1",lg:"gap-1",xl:"gap-1.5"}},y={numeric:"numeric",alpha:"alpha",alphanumeric:"alphanumeric",any:"none"};export const PlOtpField=/* @__PURE__ */t.forwardRef(function PlOtpField({variant:b="glass",size:v="md",color:N="primary",density:V="default",elevation:w=0,length:F=6,charset:j="numeric",mask:C=!1,groupSize:M,separator:O="–",value:I,defaultValue:R,onValueChange:S,onComplete:k,onValueInvalid:q,autoSubmit:z=!1,label:P,description:_,error:A,invalid:D,name:E,required:L=!1,disabled:T=!1,readOnly:B=!1,autoFocus:G=!1,className:H,style:J,...K},Q){const U=Math.min(12,Math.max(2,Math.round(F))),W=m(A),X=D??W,Y=X?"danger":N,Z=n("text-center font-medium [font-family:inherit]",f[v],g[v],x[v],p,"caret-(--p-accent) selection:bg-(--p-soft-press)","focus:[outline:2px_solid_var(--p-ring)] focus:[outline-offset:0px]","focus:[transition-duration:0ms]",T?s[b]:B?i[b]:o[b]),$=M&&M>0?Math.round(M):0;return a(l.Root,{disabled:T,invalid:X,className:n("inline-flex flex-col align-top",u[v],H),style:{...c(Y,w),...J},children:[m(P)?e(l.Label,{className:n(d[v],"font-medium",T?"text-(--plass-muted-fg)":"text-(--plass-fg)"),children:P}):null,e(r.Root,{ref:Q,length:U,validationType:y[j],mask:C,name:E,required:L,disabled:T,readOnly:B,autoSubmit:z,value:I,defaultValue:R,onValueChange:e=>S?.(e),onValueComplete:e=>k?.(e),onValueInvalid:e=>q?.(e),className:n("flex items-center",h[V][v]),...K,children:Array.from({length:U},(l,s)=>a(t.Fragment,{children:[$>0&&s>0&&s%$===0?e("span",{"aria-hidden":"true",className:n("select-none px-0.5 text-(--plass-muted-fg)",g[v]),children:O}):null,e(r.Input,{className:Z,autoFocus:G&&0===s})]},s))}),m(_)?e(l.Description,{className:n(d[v],"text-(--plass-muted-fg)"),children:_}):null,e(l.Error,W?{match:!0,className:n(d[v],"text-(--p-accent)"),children:A}:{className:n(d[v],"text-(--p-accent)")})]})});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { type PlPageLayoutCollapse, type PlPageLayoutScroll, type PlPageLayoutSpan } from '../../internal/page-layout.js';
|
|
3
|
+
import type { PlassColor } from '../../types.js';
|
|
4
|
+
export type { PlPageLayoutCollapse, PlPageLayoutScroll, PlPageLayoutSpan } from '../../internal/page-layout.js';
|
|
5
|
+
export interface PlPageLayoutProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
6
|
+
/** The bar across the top. A `PlHeader`, usually. */
|
|
7
|
+
header?: React.ReactNode;
|
|
8
|
+
/** The sheet at the end. A `PlFooter`, usually. */
|
|
9
|
+
footer?: React.ReactNode;
|
|
10
|
+
/**
|
|
11
|
+
* The leading column — the left of an English page, the right of an Arabic
|
|
12
|
+
* one. A `PlSidebar`, which is told which end it is on and needs no `side`
|
|
13
|
+
* prop of its own in here.
|
|
14
|
+
*/
|
|
15
|
+
sidebar?: React.ReactNode;
|
|
16
|
+
/**
|
|
17
|
+
* The trailing column, for the layouts that have two: navigation down one
|
|
18
|
+
* side and a table of contents, an inspector or a filter panel down the
|
|
19
|
+
* other. Each is a sidebar with its own width, its own drawer and its own
|
|
20
|
+
* trigger.
|
|
21
|
+
*/
|
|
22
|
+
endSidebar?: React.ReactNode;
|
|
23
|
+
/**
|
|
24
|
+
* Which of the header and the sidebars takes the top corner.
|
|
25
|
+
*
|
|
26
|
+
* - `full` — the header spans the whole width and the sidebars begin
|
|
27
|
+
* underneath it. The arrangement of a website. The default.
|
|
28
|
+
* - `content` — the sidebars run the full height of the window and the header
|
|
29
|
+
* sits between them, belonging to the view rather than to the site. The
|
|
30
|
+
* arrangement of an application.
|
|
31
|
+
* @default 'full'
|
|
32
|
+
*/
|
|
33
|
+
headerSpan?: PlPageLayoutSpan;
|
|
34
|
+
/**
|
|
35
|
+
* The same question for the footer, and it is worth answering separately: a
|
|
36
|
+
* dashboard with a full-height navigation rail still usually wants its
|
|
37
|
+
* copyright line under the content rather than under the rail.
|
|
38
|
+
* @default 'full'
|
|
39
|
+
*/
|
|
40
|
+
footerSpan?: PlPageLayoutSpan;
|
|
41
|
+
/**
|
|
42
|
+
* What scrolls: the document, or only the region between the header and the
|
|
43
|
+
* footer.
|
|
44
|
+
*
|
|
45
|
+
* `page` is the default and is what almost every page wants — the browser's
|
|
46
|
+
* own address bar hides on a phone, the scroll position is restored on a back
|
|
47
|
+
* navigation, and the header holds its place with `position: sticky` without
|
|
48
|
+
* anything having to be padded out of its way. Reach for `content` when the
|
|
49
|
+
* page is a workspace rather than a document.
|
|
50
|
+
* @default 'page'
|
|
51
|
+
*/
|
|
52
|
+
scroll?: PlPageLayoutScroll;
|
|
53
|
+
/**
|
|
54
|
+
* How tall the layout is.
|
|
55
|
+
*
|
|
56
|
+
* - `viewport` — the window's, which is what a page wants: a short page still
|
|
57
|
+
* pushes its footer to the bottom of the screen, and with `scroll="content"`
|
|
58
|
+
* the layout is exactly one screen tall. The default.
|
|
59
|
+
* - `auto` — its parent's, for a layout that is not the page. An app shell
|
|
60
|
+
* inside a preview, a pane of a larger tool, the frame in a documentation
|
|
61
|
+
* demo.
|
|
62
|
+
* - a length — a number in pixels, or any CSS length.
|
|
63
|
+
*
|
|
64
|
+
* It sets a floor while the page scrolls and an exact height while only the
|
|
65
|
+
* content does, which is the same difference `scroll` makes everywhere else.
|
|
66
|
+
* @default 'viewport'
|
|
67
|
+
*/
|
|
68
|
+
height?: 'viewport' | 'auto' | number | string;
|
|
69
|
+
/**
|
|
70
|
+
* The window width below which the sidebars stop being columns and become
|
|
71
|
+
* drawers, with a `PlSidebarTrigger` as the way to open them. `none` keeps
|
|
72
|
+
* them as columns at every width.
|
|
73
|
+
* @default 'md'
|
|
74
|
+
*/
|
|
75
|
+
collapseBelow?: PlPageLayoutCollapse;
|
|
76
|
+
/**
|
|
77
|
+
* Whether the leading sidebar's drawer is open. Use with
|
|
78
|
+
* `onSidebarOpenChange` for a controlled layout — a route change that should
|
|
79
|
+
* close the drawer behind it, a state the app already stores.
|
|
80
|
+
*/
|
|
81
|
+
sidebarOpen?: boolean;
|
|
82
|
+
/** Which state it starts in. @default false */
|
|
83
|
+
defaultSidebarOpen?: boolean;
|
|
84
|
+
onSidebarOpenChange?: (open: boolean) => void;
|
|
85
|
+
/** The same three for the trailing sidebar. */
|
|
86
|
+
endSidebarOpen?: boolean;
|
|
87
|
+
defaultEndSidebarOpen?: boolean;
|
|
88
|
+
onEndSidebarOpenChange?: (open: boolean) => void;
|
|
89
|
+
/**
|
|
90
|
+
* Puts a "Skip to content" link first in the document, drawn only while it
|
|
91
|
+
* holds the focus.
|
|
92
|
+
*
|
|
93
|
+
* On by default, and it is the one thing here that is not a style decision. A
|
|
94
|
+
* keyboard reader arriving on a page whose navigation holds forty links has
|
|
95
|
+
* to walk past all forty on every page before reaching the article, and this
|
|
96
|
+
* is the one link that spares them. It costs a sighted reader nothing,
|
|
97
|
+
* because it is invisible until it is tabbed to.
|
|
98
|
+
* @default true
|
|
99
|
+
*/
|
|
100
|
+
skipLink?: boolean;
|
|
101
|
+
/** What that link says. @default 'Skip to content' */
|
|
102
|
+
skipLabel?: React.ReactNode;
|
|
103
|
+
/**
|
|
104
|
+
* The `id` the skip link jumps to, put on the `<main>`.
|
|
105
|
+
* @default 'main'
|
|
106
|
+
*/
|
|
107
|
+
mainId?: string;
|
|
108
|
+
/** Anything else the `<main>` needs — a `className`, an `aria-label`. */
|
|
109
|
+
mainProps?: Omit<React.ComponentPropsWithoutRef<'main'>, 'id' | 'children'>;
|
|
110
|
+
/** The colour family the skip link lights up in. @default 'primary' */
|
|
111
|
+
color?: PlassColor;
|
|
112
|
+
/** The page. Rendered inside the `<main>`. */
|
|
113
|
+
children?: React.ReactNode;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The skeleton a page is hung on: a header, a footer, one sidebar or two, and
|
|
117
|
+
* the content between them.
|
|
118
|
+
*
|
|
119
|
+
* What it is really for is the landmarks. A page assembled out of `<div>`s is a
|
|
120
|
+
* page a screen reader offers as one undifferentiated region and a search
|
|
121
|
+
* engine reads as one undifferentiated blob; the same page built out of
|
|
122
|
+
* `<header>`, `<nav>`, `<aside>`, `<main>` and `<footer>` is a page with a
|
|
123
|
+
* table of contents. Those tags come from the components this one arranges — it
|
|
124
|
+
* draws no surface of its own and contributes exactly one element to the
|
|
125
|
+
* document, plus the `<main>` and the skip link that jumps to it.
|
|
126
|
+
*
|
|
127
|
+
* The arrangement is flexbox and media queries, which is deliberate rather than
|
|
128
|
+
* incidental: everything that decides where a column goes is stated in CSS, so
|
|
129
|
+
* the layout is right in the first frame the browser paints and right in a page
|
|
130
|
+
* with JavaScript turned off. The only things measured are the header's and the
|
|
131
|
+
* footer's heights, and only because a sidebar that holds its place has to
|
|
132
|
+
* start below a bar whose height nobody but the bar knows.
|
|
133
|
+
*
|
|
134
|
+
* It draws no gutter and no measure. That is `PlContainer`'s job, and a layout
|
|
135
|
+
* that also did it would be a second spelling of one idea — put a container
|
|
136
|
+
* inside, where a page can have a wide dashboard on one route and a narrow
|
|
137
|
+
* article on the next.
|
|
138
|
+
*/
|
|
139
|
+
export declare const PlPageLayout: React.ForwardRefExoticComponent<PlPageLayoutProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as t from"react";import{PlPageLayoutContext as o,PlassSidebarSideContext as n}from"../../internal/page-layout.js";import{controlSlots as r,cx as s,hasContent as a,toLength as i}from"../../internal/styles.js";const u=["header","footer"];export const PlPageLayout=/* @__PURE__ */t.forwardRef(function PlPageLayout({header:c,footer:d,sidebar:f,endSidebar:p,headerSpan:h="full",footerSpan:m="full",scroll:v="page",height:x="viewport",collapseBelow:y="md",sidebarOpen:b,defaultSidebarOpen:g=!1,onSidebarOpenChange:w,endSidebarOpen:P,defaultEndSidebarOpen:S=!1,onEndSidebarOpenChange:k,skipLink:C=!0,skipLabel:O="Skip to content",mainId:N="main",mainProps:$,color:j="primary",className:R,style:z,children:L,...E},B){const[H,M]=t.useState(g),[_,I]=t.useState(S),q=t.useMemo(()=>({start:b??H,end:P??_}),[b,H,P,_]),A=t.useCallback((e,l)=>{if("start"===e)return void 0===b&&M(l),void w?.(l);void 0===P&&I(l),k?.(l)},[b,P,w,k]),D=t.useRef(null),F=t.useCallback(e=>{D.current=e,"function"==typeof B?B(e):B&&(B.current=e)},[B]),G=t.useRef({header:null,footer:null}),J=t.useRef(null),K=t.useCallback(()=>{const e=D.current;if(e)for(const l of u){const t=G.current[l],o="header"===l?h:m;if(!t){e.style.setProperty(`--p-layout-${l}`,"0px"),e.style.setProperty(`--p-layout-${l}-inset`,"0px");continue}const n=getComputedStyle(t).position,r=`${t.offsetHeight}px`,s="sticky"===n||"fixed"===n;e.style.setProperty(`--p-layout-${l}`,s&&"full"===o?r:"0px"),e.style.setProperty(`--p-layout-${l}-inset`,"fixed"===n?r:"0px")}},[h,m]),Q=t.useCallback(()=>{const e=J.current;if(e){e.disconnect();for(const l of u){const t=G.current[l];t&&e.observe(t)}}K()},[K]);t.useEffect(()=>(J.current=new ResizeObserver(()=>K()),Q(),()=>{J.current?.disconnect(),J.current=null}),[K,Q]);const T=t.useCallback((e,l)=>{G.current[e]=l,Q()},[Q]),U=t.useMemo(()=>({present:!0,register:T,collapseBelow:y,open:q,setOpen:A,scroll:v}),[T,y,q,A,v]),V="content"===v,W=i("viewport"===x||"auto"===x?void 0:x),X=void 0!==W?"":"auto"===x?V?"h-full":"min-h-full":V?"h-dvh":"min-h-dvh",Y=a(c)?c:null,Z=a(d)?d:null;return e(o.Provider,{value:U,children:l("div",{ref:F,className:s("relative flex w-full flex-col",V?"overflow-hidden":"",X,"full"===h?"[padding-top:var(--p-layout-header-inset,0px)]":"","full"===m?"[padding-bottom:var(--p-layout-footer-inset,0px)]":"",R),style:void 0===W?z:{...V?{height:W}:{minHeight:W},...z},...E,children:[C?e("a",{href:`#${N}`,className:s("absolute start-3 top-3 z-40 size-px overflow-hidden whitespace-nowrap","[clip-path:inset(50%)] focus:size-auto focus:overflow-visible focus:[clip-path:none]","focus:rounded-(--plass-radius-md) focus:[background-image:var(--p-fill)]","focus:px-4 focus:py-2 focus:font-medium focus:text-(--p-on-solid) focus:no-underline","focus:[box-shadow:var(--p-elev),var(--p-lift)]","focus:[outline:2px_solid_var(--p-ring)] focus:[outline-offset:0px]"),style:r(j,2,"solid"),children:O}):null,"full"===h?Y:null,l("div",{className:s("flex w-full flex-1",V?"min-h-0":""),children:[a(f)?e(n.Provider,{value:"start",children:f}):null,l("div",{className:s("flex min-w-0 flex-1 flex-col",V?"min-h-0":"","content"===h?"[padding-top:var(--p-layout-header-inset,0px)]":"","content"===m?"[padding-bottom:var(--p-layout-footer-inset,0px)]":""),children:["content"===h?Y:null,e("main",{...$,id:N,className:s("min-w-0 flex-1",V?"min-h-0 overflow-y-auto":"",$?.className),children:L}),"content"===m?Z:null]}),a(p)?e(n.Provider,{value:"end",children:p}):null]}),"full"===m?Z:null]})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{PlPageLayout}from"./PlPageLayout.js";
|
|
@@ -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,focusRingClasses as i,glassClasses as
|
|
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,focusRingClasses as i,glassClasses as c,hasContent as d,metaTextClasses as n,tickDotClasses as p,tickRowTextClasses as m,tickSizeClasses as f,transitionClasses as u}from"../../internal/styles.js";const h=/* @__PURE__ */r.createContext({size:"md",color:"primary",readOnly:!1}),b=/* @__PURE__ */["relative inline-flex shrink-0 items-center justify-center rounded-full border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",u,i].join(" "),g=/* @__PURE__ */[c,"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(" "),x=/* @__PURE__ */[c,"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(" "),v=/* @__PURE__ */[c,"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,...u},k){const y=r.useContext(h),N=u.readOnly??y.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 ${m[y.size]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(l.Root,{ref:k,className:[b,f[y.size],i?v:N?x:g].join(" "),disabled:i,...u,children:e(l.Indicator,{className:`rounded-full bg-current ${p[y.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:`${n[y.size]} text-(--plass-muted-fg)`,children:t}):null]}):null]})})});export const PlRadioGroup=/* @__PURE__ */r.forwardRef(function PlRadioGroup({size:l="md",color:i="primary",orientation:c="vertical",label:p,description:m,error:f,invalid:u,disabled:b=!1,readOnly:g=!1,className:x,style:v,children:k,...y},N){const j=d(f),R=u??j,z=R?"danger":i,w=r.useMemo(()=>({size:l,color:z,readOnly:g}),[l,z,g]);return e(h.Provider,{value:w,children:a(s.Root,{disabled:b,invalid:R,className:["flex flex-col gap-1.5",x??""].filter(Boolean).join(" "),style:{...t(z,0,"solid"),...v},children:[p?e(s.Label,{className:[n[l],"font-semibold",b?"text-(--plass-muted-fg)":"text-(--plass-fg)"].join(" "),children:p}):null,m?e(s.Description,{className:`${n[l]} text-(--plass-muted-fg)`,children:m}):null,e(o,{ref:N,disabled:b,readOnly:g,className:["flex","horizontal"===c?"flex-row flex-wrap gap-x-5 gap-y-2":"flex-col gap-2"].join(" "),...y,children:k}),e(s.Error,j?{match:!0,className:`${n[l]} text-(--p-accent)`,children:f}:{className:`${n[l]} text-(--p-accent)`})]})})});
|
|
@@ -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 +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,disabledClasses as d,fieldReadOnlyClasses as m,fieldRestClasses as
|
|
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,disabledClasses as d,fieldReadOnlyClasses as m,fieldRestClasses as p,focusWithinRingClasses as u,gapClasses as h,glassClasses as f,hasContent as g,iconClasses as x,metaTextClasses as v,paddingXClasses as b,radiusClasses as N,stackGapClasses as j,surfaceSlots as w,transitionClasses as y}from"../../internal/styles.js";const I=/* @__PURE__ */["group relative flex w-full cursor-pointer items-center select-none","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",y,u,x].join(" "),S=/* @__PURE__ */[f,"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(" "),$=/* @__PURE__ */["relative flex cursor-pointer items-center gap-2 select-none","rounded-(--plass-radius-xs) py-1.5 pe-2 ps-7",y,"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:u="glass",size:f="md",color:x="primary",density:y="default",elevation:z=0,items:P,value:V,defaultValue:k,onValueChange:O,placeholder:R,label:T,description:q,error:C,invalid:M,startIcon:W,fullWidth:_=!1,disabled:B=!1,readOnly:D=!1,required:E=!1,name:L,id:A,className:F,style:G,...H},J){const K=g(C),Q=M??K,U=Q?"danger":x,X=l.useMemo(()=>P.map(e=>({label:e.label??String(e.value),value:e.value})),[P]),Y=l.useMemo(()=>[...P.map(e=>e.label??String(e.value)),...g(R)?[R]:[]],[P,R]);return a(s.Root,{disabled:B,invalid:Q,className:["flex-col align-top",j[f],_?"flex w-full":"inline-flex",F??""].filter(Boolean).join(" "),style:{...w(U,z),...G},...H,children:[T?e(s.Label,{className:[v[f],"font-semibold",B?"text-(--plass-muted-fg)":"text-(--plass-fg)"].join(" "),children:T}):null,a(t.Root,{id:A,name:L,items:X,value:V,defaultValue:k,onValueChange:e=>O?.(e),disabled:B,readOnly:D,required:E,children:[a(t.Trigger,{ref:J,className:[I,o[f],c[f],N[f],h[f],b[y][f],B?d[u]:D?`${m[u]} cursor-default`:p[u]].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:R}),e(n,{samples:Y})]}),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:`${S} ${N[f]} ${c[f]}`,style:w(U,3),children:P.map(l=>a(t.Item,{value:l.value,disabled:l.disabled,className:$,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)))})})})]}),q?e(s.Description,{className:`${v[f]} text-(--plass-muted-fg)`,children:q}):null,e(s.Error,K?{match:!0,className:`${v[f]} text-(--p-accent)`,children:C}:{className:`${v[f]} text-(--p-accent)`})]})});
|