plass-ui 1.0.2 → 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 +14 -15
- package/dist/components/accordion/PlAccordion.d.ts +14 -0
- package/dist/components/accordion/PlAccordion.js +1 -1
- 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/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.js +1 -1
- 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/modal/PlModal.js +1 -1
- 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/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/pagination/PlPagination.d.ts +23 -0
- package/dist/components/pagination/PlPagination.js +1 -1
- package/dist/components/popover/PlPopover.js +1 -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.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/table/PlTable.js +1 -1
- package/dist/components/text-field/PlTextField.js +1 -1
- package/dist/components/text-link/PlTextLink.d.ts +25 -2
- package/dist/components/text-link/PlTextLink.js +1 -1
- 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/tooltip/PlTooltip.js +1 -1
- 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.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/tailwind.css +26 -0
- package/dist/tokens.css +26 -0
- package/package.json +3 -3
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PlassElevation, PlassOrientation, PlassStyleProps, PlassVariant } from '../../types.js';
|
|
3
|
+
export interface PlToggleGroupProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
4
|
+
/** Passed to every toggle in the set. @default 'glass' */
|
|
5
|
+
variant?: PlassVariant;
|
|
6
|
+
/**
|
|
7
|
+
* Which toggles are on, by their `value`. An array in both the single and the
|
|
8
|
+
* multiple case — Base UI's own shape, and the one that does not change type
|
|
9
|
+
* when `multiple` is turned on.
|
|
10
|
+
*/
|
|
11
|
+
value?: readonly string[];
|
|
12
|
+
/** Which start on, for an uncontrolled set. */
|
|
13
|
+
defaultValue?: readonly string[];
|
|
14
|
+
onValueChange?: (value: string[]) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Whether more than one can be on at a time. Off, turning one on turns the
|
|
17
|
+
* last one off — which is a one-of-a-set, and worth a second thought: if the
|
|
18
|
+
* choice is a *value* rather than a state, that is a `PlSegmentedButton` or a
|
|
19
|
+
* `PlRadioGroup`.
|
|
20
|
+
* @default false
|
|
21
|
+
*/
|
|
22
|
+
multiple?: boolean;
|
|
23
|
+
/** Which way the toggles run. @default 'horizontal' */
|
|
24
|
+
orientation?: PlassOrientation;
|
|
25
|
+
/** Drop shadow depth, passed to every toggle in the set. @default 0 */
|
|
26
|
+
elevation?: PlassElevation;
|
|
27
|
+
/** Disables every toggle in the set at once. */
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/** Whether the arrow keys wrap around at the ends. @default true */
|
|
30
|
+
loopFocus?: boolean;
|
|
31
|
+
/** Stretches to the container and divides the width evenly between toggles. */
|
|
32
|
+
fullWidth?: boolean;
|
|
33
|
+
children?: React.ReactNode;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* A set of toggles that share one state.
|
|
37
|
+
*
|
|
38
|
+
* Two things are happening and only one of them is visual. The corners facing a
|
|
39
|
+
* neighbour are squared off — that is the look. The other half is that the set
|
|
40
|
+
* owns the value: the toggles report into one array, `multiple` decides whether
|
|
41
|
+
* more than one of them can be on, and `variant`, `size`, `color`, `density`,
|
|
42
|
+
* `elevation` and `disabled` are set once here rather than on every toggle.
|
|
43
|
+
*
|
|
44
|
+
* Base UI owns the roving tab index — one tab stop for the whole set, arrow keys
|
|
45
|
+
* between the members — which is what makes a toolbar of eight toggles two key
|
|
46
|
+
* presses deep instead of eight.
|
|
47
|
+
*/
|
|
48
|
+
export declare const PlToggleGroup: React.ForwardRefExoticComponent<PlToggleGroupProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e}from"react/jsx-runtime";import*as o from"react";import{ToggleGroup as l}from"@base-ui/react/toggle-group";import{ButtonGroupContext as i}from"../../internal/button-group.js";import{cx as t}from"../../internal/styles.js";const n={horizontal:"[&>*:not(:first-child)]:rounded-s-none [&>*:not(:last-child)]:rounded-e-none",vertical:"[&>*:not(:first-child)]:rounded-t-none [&>*:not(:last-child)]:rounded-b-none"},r={horizontal:"[&>*:not(:first-child)]:-ms-px",vertical:"[&>*:not(:first-child)]:-mt-px"},a=/* @__PURE__ */["inline-flex align-middle","[&>*]:relative [&>*:hover]:z-10 [&>*:focus-visible]:z-10","[&>*]:shrink-0"].join(" ");export const PlToggleGroup=/* @__PURE__ */o.forwardRef(function PlToggleGroup({variant:s,size:d,color:u,density:c,elevation:f,value:m,defaultValue:h,onValueChange:p,multiple:g=!1,orientation:v="horizontal",disabled:x,loopFocus:b=!0,fullWidth:z=!1,className:j,children:V,...w},y){const G=o.useMemo(()=>({variant:s,size:d,color:u,density:c,elevation:f,disabled:x}),[s,d,u,c,f,x]);return e(i.Provider,{value:G,children:e(l,{ref:y,value:m,defaultValue:h,onValueChange:e=>p?.(e),multiple:g,orientation:v,disabled:x,loopFocus:b,className:t(a,"vertical"===v?"flex-col":"flex-row",n[v],"glass"===(s??"glass")?r[v]:"",z?"flex w-full [&>*]:flex-1":"",j),...w,children:V})})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{PlToggle}from"./PlToggle.js";export{PlToggleGroup}from"./PlToggleGroup.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use client";import{jsx as s,jsxs as a}from"react/jsx-runtime";import*as e from"react";import{Tooltip as t}from"@base-ui/react/tooltip";import{glassClasses as o,metaTextClasses as l,paddingXClasses as i,radiusClasses as r,surfaceSlots as n}from"../../internal/styles.js";export const PlTooltipProvider=t.Provider;const d=/* @__PURE__ */[o,"max-w-64 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]","[transition:opacity_var(--plass-duration)_var(--plass-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0","data-[instant]:[transition-duration:0ms]"].join(" "),p={xs:"py-0.5",sm:"py-0.5",md:"py-1",lg:"py-1.5",xl:"py-2"},c={xs:6,sm:7,md:8,lg:9,xl:10};export function PlTooltip({content:o,children:m,size:g="sm",color:h="secondary",density:f="default",side:y="top",align:u="center",sideOffset:x=6,delay:b,closeDelay:v,arrow:j=!0,open:w,defaultOpen:P,onOpenChange:O,disabled:
|
|
1
|
+
"use client";import{jsx as s,jsxs as a}from"react/jsx-runtime";import*as e from"react";import{Tooltip as t}from"@base-ui/react/tooltip";import{glassClasses as o,metaTextClasses as l,paddingXClasses as i,radiusClasses as r,surfaceSlots as n}from"../../internal/styles.js";export const PlTooltipProvider=t.Provider;const d=/* @__PURE__ */[o,"max-w-64 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]","[transition:opacity_var(--plass-duration)_var(--plass-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0","data-[instant]:[transition-duration:0ms]"].join(" "),p={xs:"py-0.5",sm:"py-0.5",md:"py-1",lg:"py-1.5",xl:"py-2"},c={xs:6,sm:7,md:8,lg:9,xl:10};export function PlTooltip({content:o,children:m,size:g="sm",color:h="secondary",density:f="default",side:y="top",align:u="center",sideOffset:x=6,delay:b,closeDelay:v,arrow:j=!0,open:w,defaultOpen:P,onOpenChange:O,disabled:z=!1,className:N,style:T,...B}){const C=c[g],D=e.useId(),[L,M]=e.useState(P??!1),_=w??L;return a(t.Root,{open:w,defaultOpen:P,onOpenChange:s=>{M(s),O?.(s)},children:[s(t.Trigger,{render:m,delay:b,closeDelay:v,disabled:z,"aria-describedby":_?D:void 0}),s(t.Portal,{children:s(t.Positioner,{className:"plass-portal z-(--plass-z-portal) [outline:none]",side:y,align:u,sideOffset:x,children:a(t.Popup,{id:D,role:"tooltip",className:[d,r[g],i[f][g],p[g],l[g],N??""].filter(Boolean).join(" "),style:{...n(h,3),...T},...B,children:[j?s(t.Arrow,{className:["data-[side=top]:bottom-[-1px]","data-[side=bottom]:top-[-1px] data-[side=bottom]:rotate-180","data-[side=left]:right-[-1px] data-[side=left]:-rotate-90","data-[side=right]:left-[-1px] data-[side=right]:rotate-90"].join(" "),children:a("svg",{width:C,height:C/2,viewBox:"0 0 10 5","aria-hidden":"true",className:"block",children:[s("path",{d:"M0 0h10L5 5z",fill:"var(--plass-glass-line)"}),s("path",{d:"M0 0h10L5 5z",fill:"var(--plass-glass-press)",transform:"translate(0 -1)"})]})}):null,o]})})})]})}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PlassStyleProps } from '../../types.js';
|
|
3
|
+
/** One thing that can be on either side. */
|
|
4
|
+
export interface PlTransferItem {
|
|
5
|
+
/** What identifies it, and what `value` is a list of. */
|
|
6
|
+
value: string;
|
|
7
|
+
/** What the row says. */
|
|
8
|
+
label: React.ReactNode;
|
|
9
|
+
/** In the list but not movable. */
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
}
|
|
12
|
+
export interface PlTransferProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'div'>, 'color' | 'defaultValue' | 'onChange'> {
|
|
13
|
+
/** Everything that can be on either side, in the order the lists show it. */
|
|
14
|
+
items: readonly PlTransferItem[];
|
|
15
|
+
/** What is on the trailing side. Use with `onValueChange` for a controlled pair. */
|
|
16
|
+
value?: readonly string[];
|
|
17
|
+
/** What starts there, for an uncontrolled one. */
|
|
18
|
+
defaultValue?: readonly string[];
|
|
19
|
+
onValueChange?: (value: string[]) => void;
|
|
20
|
+
/** The heading over the leading list. @default 'Available' */
|
|
21
|
+
sourceLabel?: React.ReactNode;
|
|
22
|
+
/** And over the trailing one. @default 'Selected' */
|
|
23
|
+
targetLabel?: React.ReactNode;
|
|
24
|
+
/** Puts a filter above each list. @default false */
|
|
25
|
+
searchable?: boolean;
|
|
26
|
+
/** What that filter says while it is empty. @default 'Search' */
|
|
27
|
+
searchLabel?: string;
|
|
28
|
+
/** What a list with nothing in it says. @default 'Nothing here' */
|
|
29
|
+
emptyLabel?: string;
|
|
30
|
+
/** What the tick in a list's heading is announced as. @default 'Select all' */
|
|
31
|
+
selectAllLabel?: string;
|
|
32
|
+
/** What the two arrows are announced as. */
|
|
33
|
+
toTargetLabel?: string;
|
|
34
|
+
toSourceLabel?: string;
|
|
35
|
+
/** How tall each list is. A number of pixels or any CSS length. @default 220 */
|
|
36
|
+
height?: number | string;
|
|
37
|
+
/** Nothing can be ticked or moved. */
|
|
38
|
+
disabled?: boolean;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Two lists and the arrows between them: everything that could be chosen on one
|
|
42
|
+
* side, everything that has been on the other.
|
|
43
|
+
*
|
|
44
|
+
* It is the shape for a choice that is *long* — the columns in a report, the
|
|
45
|
+
* permissions on a role, the people on a channel — where a `PlCombobox` with
|
|
46
|
+
* forty chips in its field stops being readable and a list of forty checkboxes
|
|
47
|
+
* gives no answer to "what did I actually pick". Below about a dozen options,
|
|
48
|
+
* one of those two is the smaller component.
|
|
49
|
+
*
|
|
50
|
+
* The order of `items` is the order both lists show, so a row does not move when
|
|
51
|
+
* it is sent across and back. What ticks are for is choosing which rows to move;
|
|
52
|
+
* `value` is which side they are on, and the two are deliberately separate —
|
|
53
|
+
* **ticking is not choosing**.
|
|
54
|
+
*/
|
|
55
|
+
export declare const PlTransfer: React.ForwardRefExoticComponent<PlTransferProps & React.RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as a from"react";import{PlCheckbox as t}from"../checkbox/PlCheckbox.js";import{PlIconButton as s}from"../icon-button/PlIconButton.js";import{PlTextField as r}from"../text-field/PlTextField.js";import{ArrowRightIcon as i}from"../../internal/icons.js";import{searchText as n}from"../../internal/search.js";import{cx as o,fieldRestClasses as c,hasContent as d,metaTextClasses as h,paddingXClasses as m,radiusClasses as u,surfaceSlots as b,toLength as f}from"../../internal/styles.js";const v={xs:"py-1",sm:"py-1.5",md:"py-2",lg:"py-2.5",xl:"py-3"},p={xs:"py-0.5",sm:"py-1",md:"py-1",lg:"py-1.5",xl:"py-2"};function Panel({title:a,rows:s,ticked:i,onTick:n,onTickAll:d,search:f,onSearch:g,searchable:y,disabled:x,height:k,emptyLabel:w,searchLabel:S,selectAllLabel:L,style:N}){const{variant:T,size:j,color:A,density:C}=N,z=s.filter(e=>!e.disabled),P=z.filter(e=>i.has(e.value)),M=z.length>0&&P.length===z.length,V=P.length>0&&!M,_=m[C][j];return l("div",{className:o("flex min-w-0 flex-col overflow-hidden",c[T],u[j]),style:b(A,0),children:[l("div",{className:o("flex items-center gap-2 border-b [border-color:var(--plass-divider)]",_,v[j]),children:[e(t,{size:j,color:A,checked:M,indeterminate:V,disabled:x||0===z.length,"aria-label":L,onCheckedChange:e=>d(!0===e)}),e("span",{className:o("min-w-0 flex-1 truncate font-medium",h[j]),children:a}),l("span",{className:o("shrink-0 tabular-nums text-(--plass-muted-fg)",h[j]),children:[P.length,"/",s.length]})]}),y?e("div",{className:o(_,v[j]),children:e(r,{size:j,color:A,density:C,fullWidth:!0,variant:"ghost",disabled:x,placeholder:S,"aria-label":S,value:f,onChange:e=>g(e.target.value)})}):null,e("div",{className:"min-h-0 flex-1 overflow-y-auto overscroll-contain",style:void 0===k?void 0:{height:k},children:e("div",{className:o("flex flex-col",_,v[j]),children:0===s.length?e("span",{className:o("text-(--plass-muted-fg)",h[j],p[j]),children:w}):s.map(l=>e(t,{size:j,color:A,className:p[j],label:l.label,checked:i.has(l.value),disabled:x||l.disabled,onCheckedChange:e=>n(l.value,!0===e)},l.value))})})]})}function narrow(e,l){const a=n(l);return""===a?e:e.filter(e=>"string"!=typeof e.label||n(e.label).includes(a))}export const PlTransfer=/* @__PURE__ */a.forwardRef(function PlTransfer({items:t,value:r,defaultValue:n,onValueChange:c,sourceLabel:h="Available",targetLabel:m="Selected",searchable:u=!1,searchLabel:b="Search",emptyLabel:v="Nothing here",selectAllLabel:p="Select all",toTargetLabel:g="Move to selected",toSourceLabel:y="Move to available",height:x=220,disabled:k=!1,variant:w="glass",size:S="md",color:L="primary",density:N="default",className:T,...j},A){const[C,z]=a.useState(n??[]),P=r??C,[M,V]=a.useState(()=>new Set),[_,B]=a.useState(""),[F,I]=a.useState(""),R=a.useMemo(()=>new Set(P),[P]),W=a.useMemo(()=>t.filter(e=>!R.has(e.value)),[t,R]),q=a.useMemo(()=>t.filter(e=>R.has(e.value)),[t,R]),tick=(e,l)=>{V(a=>{const t=new Set(a);return l?t.add(e):t.delete(e),t})},tickAll=(e,l)=>{V(a=>{const t=new Set(a);for(const a of e)a.disabled||(l?t.add(a.value):t.delete(a.value));return t})},move=(e,l)=>{const a=e.filter(e=>!e.disabled&&M.has(e.value));if(0===a.length)return;const s=new Set(a.map(e=>e.value)),i=l?t.filter(e=>R.has(e.value)||s.has(e.value)).map(e=>e.value):P.filter(e=>!s.has(e));V(e=>new Set([...e].filter(e=>!s.has(e)))),(e=>{void 0===r&&z(e),c?.(e)})(i)},D=narrow(W,_),E=narrow(q,F),G=D.some(e=>!e.disabled&&M.has(e.value)),H=E.some(e=>!e.disabled&&M.has(e.value)),J=f(x),K={variant:w,size:S,color:L,density:N},O="ghost"===w?"ghost":"glass";return l("div",{ref:A,className:o("grid w-full items-center gap-3","[grid-template-columns:minmax(0,1fr)_auto_minmax(0,1fr)]",T),...j,children:[e(Panel,{title:d(h)?h:"Available",rows:D,ticked:M,onTick:tick,onTickAll:e=>tickAll(D,e),search:_,onSearch:B,searchable:u,disabled:k,height:J,emptyLabel:v,searchLabel:b,selectAllLabel:p,style:K}),l("div",{className:"flex flex-col gap-2",children:[e(s,{size:S,color:L,variant:O,label:g,disabled:k||!G,onClick:()=>move(D,!0),icon:e(i,{})}),e(s,{size:S,color:L,variant:O,label:y,disabled:k||!H,onClick:()=>move(E,!1),icon:e("span",{className:"flex rotate-180",children:e(i,{})})})]}),e(Panel,{title:d(m)?m:"Selected",rows:E,ticked:M,onTick:tick,onTickAll:e=>tickAll(E,e),search:F,onSearch:I,searchable:u,disabled:k,height:J,emptyLabel:v,searchLabel:b,selectAllLabel:p,style:K})]})});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export{PlTransfer}from"./PlTransfer.js";
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,7 @@ export * from './components/animate-typing/index.js';
|
|
|
14
14
|
export * from './components/animate-zoom/index.js';
|
|
15
15
|
export * from './components/aspect-ratio/index.js';
|
|
16
16
|
export * from './components/avatar/index.js';
|
|
17
|
+
export * from './components/avatar-group/index.js';
|
|
17
18
|
export * from './components/badge/index.js';
|
|
18
19
|
export * from './components/blockquote/index.js';
|
|
19
20
|
export * from './components/bottom-navigation/index.js';
|
|
@@ -27,26 +28,35 @@ export * from './components/chat-bubble/index.js';
|
|
|
27
28
|
export * from './components/checkbox/index.js';
|
|
28
29
|
export * from './components/chip/index.js';
|
|
29
30
|
export * from './components/collapsible/index.js';
|
|
31
|
+
export * from './components/color-picker/index.js';
|
|
30
32
|
export * from './components/combobox/index.js';
|
|
33
|
+
export * from './components/command-palette/index.js';
|
|
31
34
|
export * from './components/container/index.js';
|
|
32
35
|
export * from './components/date-picker/index.js';
|
|
33
36
|
export * from './components/date-range-picker/index.js';
|
|
34
37
|
export * from './components/date-time-picker/index.js';
|
|
35
38
|
export * from './components/divider/index.js';
|
|
36
39
|
export * from './components/drawer/index.js';
|
|
40
|
+
export * from './components/fieldset/index.js';
|
|
37
41
|
export * from './components/file-picker/index.js';
|
|
38
42
|
export * from './components/floating-bottom-navigation/index.js';
|
|
43
|
+
export * from './components/footer/index.js';
|
|
44
|
+
export * from './components/form/index.js';
|
|
39
45
|
export * from './components/grid/index.js';
|
|
46
|
+
export * from './components/header/index.js';
|
|
40
47
|
export * from './components/highlight/index.js';
|
|
41
48
|
export * from './components/hot-keys/index.js';
|
|
42
49
|
export * from './components/icon/index.js';
|
|
43
50
|
export * from './components/icon-button/index.js';
|
|
44
51
|
export * from './components/list/index.js';
|
|
45
52
|
export * from './components/menu/index.js';
|
|
53
|
+
export * from './components/menubar/index.js';
|
|
46
54
|
export * from './components/modal/index.js';
|
|
55
|
+
export * from './components/navigation-menu/index.js';
|
|
47
56
|
export * from './components/number-field/index.js';
|
|
48
57
|
export * from './components/otp-field/index.js';
|
|
49
58
|
export * from './components/overlay/index.js';
|
|
59
|
+
export * from './components/page-layout/index.js';
|
|
50
60
|
export * from './components/pagination/index.js';
|
|
51
61
|
export * from './components/panes/index.js';
|
|
52
62
|
export * from './components/pill/index.js';
|
|
@@ -59,6 +69,7 @@ export * from './components/rating/index.js';
|
|
|
59
69
|
export * from './components/scroll-zone/index.js';
|
|
60
70
|
export * from './components/segmented-button/index.js';
|
|
61
71
|
export * from './components/select/index.js';
|
|
72
|
+
export * from './components/sidebar/index.js';
|
|
62
73
|
export * from './components/skeleton/index.js';
|
|
63
74
|
export * from './components/slider/index.js';
|
|
64
75
|
export * from './components/spoiler/index.js';
|
|
@@ -70,6 +81,8 @@ export * from './components/text-link/index.js';
|
|
|
70
81
|
export * from './components/time-picker/index.js';
|
|
71
82
|
export * from './components/timeline/index.js';
|
|
72
83
|
export * from './components/toast/index.js';
|
|
84
|
+
export * from './components/toggle/index.js';
|
|
73
85
|
export * from './components/toolbar/index.js';
|
|
74
86
|
export * from './components/tooltip/index.js';
|
|
87
|
+
export * from './components/transfer/index.js';
|
|
75
88
|
export * from './components/typography/index.js';
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export*from"./types.js";export*from"./components/accordion/index.js";export*from"./components/alert/index.js";export*from"./components/animate-appear/index.js";export*from"./components/animate-blink/index.js";export*from"./components/animate-fade/index.js";export*from"./components/animate-grow/index.js";export*from"./components/animate-headline/index.js";export*from"./components/animate-lighting/index.js";export*from"./components/animate-marquee/index.js";export*from"./components/animate-rotate/index.js";export*from"./components/animate-slide/index.js";export*from"./components/animate-typing/index.js";export*from"./components/animate-zoom/index.js";export*from"./components/aspect-ratio/index.js";export*from"./components/avatar/index.js";export*from"./components/badge/index.js";export*from"./components/blockquote/index.js";export*from"./components/bottom-navigation/index.js";export*from"./components/box/index.js";export*from"./components/breadcrumb/index.js";export*from"./components/button/index.js";export*from"./components/button-group/index.js";export*from"./components/card/index.js";export*from"./components/carousel/index.js";export*from"./components/chat-bubble/index.js";export*from"./components/checkbox/index.js";export*from"./components/chip/index.js";export*from"./components/collapsible/index.js";export*from"./components/combobox/index.js";export*from"./components/container/index.js";export*from"./components/date-picker/index.js";export*from"./components/date-range-picker/index.js";export*from"./components/date-time-picker/index.js";export*from"./components/divider/index.js";export*from"./components/drawer/index.js";export*from"./components/file-picker/index.js";export*from"./components/floating-bottom-navigation/index.js";export*from"./components/grid/index.js";export*from"./components/highlight/index.js";export*from"./components/hot-keys/index.js";export*from"./components/icon/index.js";export*from"./components/icon-button/index.js";export*from"./components/list/index.js";export*from"./components/menu/index.js";export*from"./components/modal/index.js";export*from"./components/number-field/index.js";export*from"./components/otp-field/index.js";export*from"./components/overlay/index.js";export*from"./components/pagination/index.js";export*from"./components/panes/index.js";export*from"./components/pill/index.js";export*from"./components/popover/index.js";export*from"./components/progress-box/index.js";export*from"./components/progress-circular/index.js";export*from"./components/progress-linear/index.js";export*from"./components/radio-group/index.js";export*from"./components/rating/index.js";export*from"./components/scroll-zone/index.js";export*from"./components/segmented-button/index.js";export*from"./components/select/index.js";export*from"./components/skeleton/index.js";export*from"./components/slider/index.js";export*from"./components/spoiler/index.js";export*from"./components/switch/index.js";export*from"./components/table/index.js";export*from"./components/tabs/index.js";export*from"./components/text-field/index.js";export*from"./components/text-link/index.js";export*from"./components/time-picker/index.js";export*from"./components/timeline/index.js";export*from"./components/toast/index.js";export*from"./components/toolbar/index.js";export*from"./components/tooltip/index.js";export*from"./components/typography/index.js";
|
|
1
|
+
export*from"./types.js";export*from"./components/accordion/index.js";export*from"./components/alert/index.js";export*from"./components/animate-appear/index.js";export*from"./components/animate-blink/index.js";export*from"./components/animate-fade/index.js";export*from"./components/animate-grow/index.js";export*from"./components/animate-headline/index.js";export*from"./components/animate-lighting/index.js";export*from"./components/animate-marquee/index.js";export*from"./components/animate-rotate/index.js";export*from"./components/animate-slide/index.js";export*from"./components/animate-typing/index.js";export*from"./components/animate-zoom/index.js";export*from"./components/aspect-ratio/index.js";export*from"./components/avatar/index.js";export*from"./components/avatar-group/index.js";export*from"./components/badge/index.js";export*from"./components/blockquote/index.js";export*from"./components/bottom-navigation/index.js";export*from"./components/box/index.js";export*from"./components/breadcrumb/index.js";export*from"./components/button/index.js";export*from"./components/button-group/index.js";export*from"./components/card/index.js";export*from"./components/carousel/index.js";export*from"./components/chat-bubble/index.js";export*from"./components/checkbox/index.js";export*from"./components/chip/index.js";export*from"./components/collapsible/index.js";export*from"./components/color-picker/index.js";export*from"./components/combobox/index.js";export*from"./components/command-palette/index.js";export*from"./components/container/index.js";export*from"./components/date-picker/index.js";export*from"./components/date-range-picker/index.js";export*from"./components/date-time-picker/index.js";export*from"./components/divider/index.js";export*from"./components/drawer/index.js";export*from"./components/fieldset/index.js";export*from"./components/file-picker/index.js";export*from"./components/floating-bottom-navigation/index.js";export*from"./components/footer/index.js";export*from"./components/form/index.js";export*from"./components/grid/index.js";export*from"./components/header/index.js";export*from"./components/highlight/index.js";export*from"./components/hot-keys/index.js";export*from"./components/icon/index.js";export*from"./components/icon-button/index.js";export*from"./components/list/index.js";export*from"./components/menu/index.js";export*from"./components/menubar/index.js";export*from"./components/modal/index.js";export*from"./components/navigation-menu/index.js";export*from"./components/number-field/index.js";export*from"./components/otp-field/index.js";export*from"./components/overlay/index.js";export*from"./components/page-layout/index.js";export*from"./components/pagination/index.js";export*from"./components/panes/index.js";export*from"./components/pill/index.js";export*from"./components/popover/index.js";export*from"./components/progress-box/index.js";export*from"./components/progress-circular/index.js";export*from"./components/progress-linear/index.js";export*from"./components/radio-group/index.js";export*from"./components/rating/index.js";export*from"./components/scroll-zone/index.js";export*from"./components/segmented-button/index.js";export*from"./components/select/index.js";export*from"./components/sidebar/index.js";export*from"./components/skeleton/index.js";export*from"./components/slider/index.js";export*from"./components/spoiler/index.js";export*from"./components/switch/index.js";export*from"./components/table/index.js";export*from"./components/tabs/index.js";export*from"./components/text-field/index.js";export*from"./components/text-link/index.js";export*from"./components/time-picker/index.js";export*from"./components/timeline/index.js";export*from"./components/toast/index.js";export*from"./components/toggle/index.js";export*from"./components/toolbar/index.js";export*from"./components/tooltip/index.js";export*from"./components/transfer/index.js";export*from"./components/typography/index.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a `PlAvatar` inherits from the `PlAvatarGroup` around it.
|
|
3
|
+
*
|
|
4
|
+
* `button-group.ts`'s arrangement, one component over and for the same two
|
|
5
|
+
* reasons. Cloning the children with `React.cloneElement` stops working the
|
|
6
|
+
* moment a caller wraps one of them in a `PlTooltip`, a `<Fragment>` or a
|
|
7
|
+
* `.map()` — which is most of the time — and a context reaches the avatar
|
|
8
|
+
* wherever it ended up. And it lives here rather than beside the group so that
|
|
9
|
+
* `PlAvatar` can read it without the two components importing each other.
|
|
10
|
+
*
|
|
11
|
+
* Every field is optional, and every one of them means *not specified* rather
|
|
12
|
+
* than a value: an avatar falls back to its own default, so a group with no
|
|
13
|
+
* props of its own changes nothing except the overlap.
|
|
14
|
+
*/
|
|
15
|
+
import * as React from 'react';
|
|
16
|
+
import type { PlAvatarShape } from '../components/avatar/PlAvatar.js';
|
|
17
|
+
import type { PlassColor, PlassElevation, PlassSize, PlassVariant } from '../types.js';
|
|
18
|
+
export interface PlassAvatarGroupContextValue {
|
|
19
|
+
size?: PlassSize;
|
|
20
|
+
shape?: PlAvatarShape;
|
|
21
|
+
variant?: PlassVariant;
|
|
22
|
+
color?: PlassColor;
|
|
23
|
+
elevation?: PlassElevation;
|
|
24
|
+
}
|
|
25
|
+
export declare const AvatarGroupContext: React.Context<PlassAvatarGroupContextValue | null>;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Colour arithmetic, written out rather than installed.
|
|
3
|
+
*
|
|
4
|
+
* `PlColorPicker` is the only component that has to *compute* a colour rather
|
|
5
|
+
* than name one, and the whole of what it needs is here: three representations,
|
|
6
|
+
* the conversions between them, one parser and one formatter. It is a hundred
|
|
7
|
+
* lines of trigonometry-free arithmetic, which is the entire reason a component
|
|
8
|
+
* that computes colours brings no colour library with it.
|
|
9
|
+
*
|
|
10
|
+
* Two decisions worth knowing before reading:
|
|
11
|
+
*
|
|
12
|
+
* - **HSV is the model the panel is drawn in, and it never leaves.** A
|
|
13
|
+
* saturation/value square with a hue rail beside it *is* HSV, so the picker
|
|
14
|
+
* keeps its state that way and converts on the way out. Round-tripping
|
|
15
|
+
* through RGB instead would lose the hue of every greyscale colour — black is
|
|
16
|
+
* `#000` at every hue — and the rail would jump to red the moment the pointer
|
|
17
|
+
* reached a corner.
|
|
18
|
+
* - **`alpha` is 0–1, everything else is what CSS says it is.** `h` is degrees,
|
|
19
|
+
* `s`/`v`/`l` are percentages, `r`/`g`/`b` are 0–255. Nothing here invents a
|
|
20
|
+
* normalised unit, because every one of these numbers is eventually written
|
|
21
|
+
* into a string a human reads.
|
|
22
|
+
*
|
|
23
|
+
* Nothing here is exported from `src/index.ts` except the two types the picker's
|
|
24
|
+
* own props need. It is the library talking to itself, in the sense that
|
|
25
|
+
* `internal/` always means.
|
|
26
|
+
*/
|
|
27
|
+
/** 0–255 per channel, the way a hex triplet and `rgb()` both spell it. */
|
|
28
|
+
export interface PlassRgb {
|
|
29
|
+
r: number;
|
|
30
|
+
g: number;
|
|
31
|
+
b: number;
|
|
32
|
+
}
|
|
33
|
+
/** `h` in degrees, `s` and `v` as percentages. The panel's own model. */
|
|
34
|
+
export interface PlassHsv {
|
|
35
|
+
h: number;
|
|
36
|
+
s: number;
|
|
37
|
+
v: number;
|
|
38
|
+
}
|
|
39
|
+
/** `h` in degrees, `s` and `l` as percentages. Only ever an output format. */
|
|
40
|
+
export interface PlassHsl {
|
|
41
|
+
h: number;
|
|
42
|
+
s: number;
|
|
43
|
+
l: number;
|
|
44
|
+
}
|
|
45
|
+
/** A colour and how much of it there is. `alpha` is 0–1. */
|
|
46
|
+
export interface PlassColorValue {
|
|
47
|
+
hsv: PlassHsv;
|
|
48
|
+
alpha: number;
|
|
49
|
+
}
|
|
50
|
+
/** The three ways the picker will write a colour back out. */
|
|
51
|
+
export type PlColorFormat = 'hex' | 'rgb' | 'hsl';
|
|
52
|
+
export declare function clamp(value: number, min: number, max: number): number;
|
|
53
|
+
export declare function hsvToRgb({ h, s, v }: PlassHsv): PlassRgb;
|
|
54
|
+
export declare function rgbToHsv({ r, g, b }: PlassRgb): PlassHsv;
|
|
55
|
+
export declare function rgbToHsl({ r, g, b }: PlassRgb): PlassHsl;
|
|
56
|
+
export declare function hslToRgb({ h, s, l }: PlassHsl): PlassRgb;
|
|
57
|
+
/**
|
|
58
|
+
* A CSS colour string, or `null` if it is not one this understands.
|
|
59
|
+
*
|
|
60
|
+
* Hex in all four lengths, `rgb()`/`rgba()` and `hsl()`/`hsla()` in both the
|
|
61
|
+
* comma and the space syntax. Named colours and `color()` are deliberately out:
|
|
62
|
+
* a picker has to be able to write every value it can read, and there is no
|
|
63
|
+
* honest way back from `rebeccapurple` to a point on the panel.
|
|
64
|
+
*/
|
|
65
|
+
export declare function parseColor(input: string): PlassColorValue | null;
|
|
66
|
+
export declare function rgbToHex({ r, g, b }: PlassRgb, alpha?: number): string;
|
|
67
|
+
/**
|
|
68
|
+
* The value the component hands back, in whichever notation was asked for.
|
|
69
|
+
*
|
|
70
|
+
* `hex` drops the alpha pair when the colour is opaque, and the two functional
|
|
71
|
+
* forms drop the fourth argument for the same reason — a caller who never
|
|
72
|
+
* turned `alpha` on should never see `rgba(…, 1)` come out of a control they
|
|
73
|
+
* only used three channels of.
|
|
74
|
+
*/
|
|
75
|
+
export declare function formatColor(hsv: PlassHsv, alpha: number, format: PlColorFormat): string;
|
|
76
|
+
/** A plain `rgb()` for the swatches and rails, where alpha is drawn separately. */
|
|
77
|
+
export declare function cssColor(hsv: PlassHsv, alpha?: number): string;
|
|
78
|
+
/**
|
|
79
|
+
* Black or white, whichever can be read on top of this colour.
|
|
80
|
+
*
|
|
81
|
+
* The tick on a chosen swatch is the only thing the picker draws *on* an
|
|
82
|
+
* arbitrary colour, and a fixed white tick disappears on yellow. The threshold
|
|
83
|
+
* is relative luminance rather than plain lightness, because the eye weighs
|
|
84
|
+
* green about six times as heavily as blue and a colour model that pretends
|
|
85
|
+
* otherwise puts the tick the wrong way round on both.
|
|
86
|
+
*/
|
|
87
|
+
export declare function readableInk(hsv: PlassHsv): string;
|
|
88
|
+
/**
|
|
89
|
+
* The swatches a picker shows when it was given none.
|
|
90
|
+
*
|
|
91
|
+
* Deliberately **not** the library's own six families: those are semantic roles
|
|
92
|
+
* and a picker is asked for a colour, not for a meaning. This is a plain
|
|
93
|
+
* spectrum plus the greys — the row somebody reaches for when they are
|
|
94
|
+
* labelling a calendar, a tag or a project, which is what a colour picker in an
|
|
95
|
+
* application is nearly always for.
|
|
96
|
+
*/
|
|
97
|
+
export declare const defaultSwatches: readonly string[];
|
|
98
|
+
/**
|
|
99
|
+
* The chequerboard behind a translucent colour, as a background shorthand.
|
|
100
|
+
*
|
|
101
|
+
* Two conic gradients would be one declaration fewer, but a chequer drawn with
|
|
102
|
+
* conic gradients has a seam down the middle of every tile on a fractional
|
|
103
|
+
* device pixel ratio. Four linear stops at 45° do not.
|
|
104
|
+
*/
|
|
105
|
+
export declare const checkerBackground: {
|
|
106
|
+
readonly backgroundImage: "linear-gradient(45deg, var(--plass-border) 25%, transparent 25%), linear-gradient(-45deg, var(--plass-border) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--plass-border) 75%), linear-gradient(-45deg, transparent 75%, var(--plass-border) 75%)";
|
|
107
|
+
readonly backgroundSize: "8px 8px";
|
|
108
|
+
readonly backgroundPosition: "0 0, 0 4px, 4px -4px, -4px 0";
|
|
109
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function clamp(r,n,t){return r<n?n:r>t?t:r}function wrapHue(r){const n=r%360;return n<0?n+360:n}function round(r){return Math.round(r)}export function hsvToRgb({h:r,s:n,v:t}){const e=wrapHue(r)/60,o=clamp(n,0,100)/100,a=clamp(t,0,100)/100,s=a*o,u=s*(1-Math.abs(e%2-1)),c=a-s,l=Math.floor(e)%6,[g,h,i]=[[s,u,0],[u,s,0],[0,s,u],[0,u,s],[u,0,s],[s,0,u]][l];return{r:round(255*(g+c)),g:round(255*(h+c)),b:round(255*(i+c))}}export function rgbToHsv({r,g:n,b:t}){const e=clamp(r,0,255)/255,o=clamp(n,0,255)/255,a=clamp(t,0,255)/255,s=Math.max(e,o,a),u=s-Math.min(e,o,a);let c=0;return 0!==u&&(c=s===e?(o-a)/u%6:s===o?(a-e)/u+2:(e-o)/u+4),{h:wrapHue(60*c),s:0===s?0:u/s*100,v:100*s}}export function rgbToHsl({r,g:n,b:t}){const{h:e,s:o,v:a}=rgbToHsv({r,g:n,b:t}),s=a/100,u=s*(1-o/100/2),c=Math.min(u,1-u);return{h:e,s:0===c?0:(s-u)/c*100,l:100*u}}export function hslToRgb({h:r,s:n,l:t}){const e=clamp(t,0,100)/100,o=e+clamp(n,0,100)/100*Math.min(e,1-e);return hsvToRgb({h:r,s:0===o?0:2*(1-e/o)*100,v:100*o})}const r=/^#?([0-9a-f]{3,8})$/i;export function parseColor(n){const t=n.trim().toLowerCase();if(!t)return null;if(t.startsWith("#")||r.test(t))return function hexToRgba(n){const t=r.exec(n.trim());if(!t)return null;const e=t[1],o=3===e.length||4===e.length?[...e].map(r=>r+r).join(""):e;if(6!==o.length&&8!==o.length)return null;const channel=r=>parseInt(o.slice(2*r,2*r+2),16);return{hsv:rgbToHsv({r:channel(0),g:channel(1),b:channel(2)}),alpha:8===o.length?channel(3)/255:1}}(t);const e=/^(rgba?|hsla?)\((.*)\)$/.exec(t);if(!e)return null;const[,o,a]=e,s=function numbersIn(r){return(r.match(/-?[\d.]+%?/g)??[]).map(r=>parseFloat(r))}(a);if(s.length<3||s.some(Number.isNaN))return null;const u=function alphaOf(r,n,t){if(n.length<=t)return 1;const e=r.match(/-?[\d.]+%?/g)??[];return clamp(e[t]?.endsWith("%")?n[t]/100:n[t],0,1)}(a,s,3);return o.startsWith("rgb")?{hsv:rgbToHsv({r:s[0],g:s[1],b:s[2]}),alpha:u}:{hsv:rgbToHsv(hslToRgb({h:s[0],s:s[1],l:s[2]})),alpha:u}}function hexPair(r){return clamp(round(r),0,255).toString(16).padStart(2,"0")}export function rgbToHex({r,g:n,b:t},e=1){const o=`#${hexPair(r)}${hexPair(n)}${hexPair(t)}`;return e>=1?o:`${o}${hexPair(255*e)}`}function alphaText(r){return String(Math.round(100*clamp(r,0,1))/100)}export function formatColor(r,n,t){const e=hsvToRgb(r);if("hex"===t)return rgbToHex(e,n);if("rgb"===t){const r=`${round(e.r)}, ${round(e.g)}, ${round(e.b)}`;return n>=1?`rgb(${r})`:`rgba(${r}, ${alphaText(n)})`}const{h:o,s:a,l:s}=rgbToHsl(e),u=`${round(o)}, ${round(a)}%, ${round(s)}%`;return n>=1?`hsl(${u})`:`hsla(${u}, ${alphaText(n)})`}export function cssColor(r,n=1){const{r:t,g:e,b:o}=hsvToRgb(r);return n>=1?`rgb(${t}, ${e}, ${o})`:`rgba(${t}, ${e}, ${o}, ${alphaText(n)})`}export function readableInk(r){const{r:n,g:t,b:e}=hsvToRgb(r),channel=r=>{const n=r/255;return n<=.03928?n/12.92:((n+.055)/1.055)**2.4};return.2126*channel(n)+.7152*channel(t)+.0722*channel(e)>.42?"#000000":"#ffffff"}export const defaultSwatches=["#000000","#4b5563","#9ca3af","#ffffff","#ef4444","#f97316","#f59e0b","#84cc16","#22c55e","#14b8a6","#06b6d4","#3b82f6","#6366f1","#8b5cf6","#d946ef","#ec4899"];export const checkerBackground={backgroundImage:"linear-gradient(45deg, var(--plass-border) 25%, transparent 25%), linear-gradient(-45deg, var(--plass-border) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, var(--plass-border) 75%), linear-gradient(-45deg, transparent 75%, var(--plass-border) 75%)",backgroundSize:"8px 8px",backgroundPosition:"0 0, 0 4px, 4px -4px, -4px 0"};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one thing a `rel` must not lose.
|
|
3
|
+
*
|
|
4
|
+
* `noopener` is what stops a page opened in a new tab reaching back through
|
|
5
|
+
* `window.opener`; `noreferrer` sits beside it for the browsers that still need
|
|
6
|
+
* the pair. The common reason to write a `rel` by hand is `nofollow` or
|
|
7
|
+
* `sponsored`, which is an SEO decision — and spelled as a plain override it
|
|
8
|
+
* would silently take the protection off a link that still opens elsewhere.
|
|
9
|
+
*
|
|
10
|
+
* So the caller's value is **merged** rather than replaced: whatever was asked
|
|
11
|
+
* for is kept, with the two tokens added if they are not already there, and a
|
|
12
|
+
* link that stays in this tab keeps exactly the `rel` it was given.
|
|
13
|
+
*
|
|
14
|
+
* Here rather than in either component that needs it — `PlTextLink` and
|
|
15
|
+
* `PlNavigationMenu` — because two copies of a security default are two copies
|
|
16
|
+
* that can drift, and the one that drifts is the one nobody reads.
|
|
17
|
+
*/
|
|
18
|
+
export declare function safeRel(target: string | undefined, rel: string | undefined): string | undefined;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export function safeRel(e,n){return void 0===e||""===e||"_self"===e?n:[...new Set([...(n??"").split(/\s+/).filter(Boolean),"noopener","noreferrer"])].join(" ")}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import type { PlassBreakpoint, PlassSide } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The vocabulary a page's structure is written in, and the context the four
|
|
5
|
+
* components that build one share.
|
|
6
|
+
*
|
|
7
|
+
* It lives here for the reason `menu.ts` does rather than the reason
|
|
8
|
+
* `button-group.ts` does: five components read it — `PlPageLayout`, `PlHeader`,
|
|
9
|
+
* `PlFooter`, `PlSidebar` and `PlSidebarTrigger` — and every one of them is
|
|
10
|
+
* also usable on its own. Keeping the context in the layout's own file would
|
|
11
|
+
* make a header import a layout it may never be inside.
|
|
12
|
+
*
|
|
13
|
+
* Nothing here draws anything. The arrangement is flexbox and media queries,
|
|
14
|
+
* both of which CSS states better than JavaScript can; what needs a context is
|
|
15
|
+
* the handful of facts a slot cannot work out from where it sits — how wide the
|
|
16
|
+
* window has to be before a sidebar stops being a column, and whether a drawer
|
|
17
|
+
* is open.
|
|
18
|
+
*/
|
|
19
|
+
/** Which end of the band a sidebar takes. Logical, so it flips under RTL. */
|
|
20
|
+
export type PlassSidebarSide = 'start' | 'end';
|
|
21
|
+
/** The two slots a layout measures, because a sidebar has to start below them. */
|
|
22
|
+
export type PlPageLayoutSlot = 'header' | 'footer';
|
|
23
|
+
/**
|
|
24
|
+
* How far across a header or a footer reaches.
|
|
25
|
+
*
|
|
26
|
+
* - `full` — the whole width, with the sidebars beginning underneath it. The
|
|
27
|
+
* arrangement of a website: one bar across the top, and the page below it.
|
|
28
|
+
* - `content` — only the column between the sidebars, which run the full height
|
|
29
|
+
* of the window beside it. The arrangement of an application: the navigation
|
|
30
|
+
* is the outermost thing on the screen and the bar belongs to the view.
|
|
31
|
+
*
|
|
32
|
+
* There is no third value, because there is no third arrangement: what is being
|
|
33
|
+
* decided is which of the two takes the corner.
|
|
34
|
+
*/
|
|
35
|
+
export type PlPageLayoutSpan = 'full' | 'content';
|
|
36
|
+
/**
|
|
37
|
+
* What scrolls.
|
|
38
|
+
*
|
|
39
|
+
* - `page` — the document does, the way a website does. The header and the
|
|
40
|
+
* sidebars hold their place with `position: sticky`, the browser's own
|
|
41
|
+
* address bar hides on a phone, and the scroll position is restored on a back
|
|
42
|
+
* navigation. This is the default, and it is what almost every page wants.
|
|
43
|
+
* - `content` — the layout takes exactly the height of the window and only the
|
|
44
|
+
* region between the header and the footer scrolls, the way an application
|
|
45
|
+
* does. Reach for it when the page is a workspace rather than a document.
|
|
46
|
+
*/
|
|
47
|
+
export type PlPageLayoutScroll = 'page' | 'content';
|
|
48
|
+
/**
|
|
49
|
+
* The width below which a sidebar stops being part of the layout and becomes a
|
|
50
|
+
* drawer that is opened, or `none` to keep it a column at every width.
|
|
51
|
+
*
|
|
52
|
+
* `xs` is the breakpoint whose floor is `0`, so nothing is ever below it — it
|
|
53
|
+
* means the same as `none`, and is accepted only because `PlassBreakpoint` has
|
|
54
|
+
* five values everywhere else in the library.
|
|
55
|
+
*/
|
|
56
|
+
export type PlPageLayoutCollapse = PlassBreakpoint | 'none';
|
|
57
|
+
export interface PlPageLayoutContextValue {
|
|
58
|
+
/**
|
|
59
|
+
* Whether there is a `PlPageLayout` above at all.
|
|
60
|
+
*
|
|
61
|
+
* A header, a footer and a sidebar all render perfectly well without one —
|
|
62
|
+
* they are a bar, a bar and a panel. What they cannot do on their own is
|
|
63
|
+
* agree with each other about where they sit, which is the whole of what a
|
|
64
|
+
* layout adds and the reason a component has to be able to tell.
|
|
65
|
+
*/
|
|
66
|
+
present: boolean;
|
|
67
|
+
/**
|
|
68
|
+
* Hands the layout the element filling one of its slots.
|
|
69
|
+
*
|
|
70
|
+
* The layout measures it and writes its height onto its own root as a custom
|
|
71
|
+
* property, because a sidebar that holds its place has to start below a
|
|
72
|
+
* header whose height only the header knows. A callback rather than a
|
|
73
|
+
* `querySelector`, so a bar rendered through `render={<MyBar />}` is found as
|
|
74
|
+
* reliably as one that is not.
|
|
75
|
+
*/
|
|
76
|
+
register: (slot: PlPageLayoutSlot, node: HTMLElement | null) => void;
|
|
77
|
+
/** Where the sidebars stop being columns. */
|
|
78
|
+
collapseBelow: PlPageLayoutCollapse;
|
|
79
|
+
/** Whether each sidebar's drawer is open. Only meaningful while it is collapsed. */
|
|
80
|
+
open: Record<PlassSidebarSide, boolean>;
|
|
81
|
+
setOpen: (side: PlassSidebarSide, open: boolean) => void;
|
|
82
|
+
/** How the page scrolls, which decides how a sidebar holds its place. */
|
|
83
|
+
scroll: PlPageLayoutScroll;
|
|
84
|
+
}
|
|
85
|
+
export declare const PlPageLayoutContext: React.Context<PlPageLayoutContextValue>;
|
|
86
|
+
/**
|
|
87
|
+
* Which end of the band the sidebar being rendered right now takes.
|
|
88
|
+
*
|
|
89
|
+
* A second, one-value context rather than a field on the one above, because it
|
|
90
|
+
* is the one fact that differs *between* two sidebars in the same layout: the
|
|
91
|
+
* layout wraps each slot in its own provider, so a sidebar handed to the
|
|
92
|
+
* trailing slot needs no `side` prop of its own to know where it is. `null` is
|
|
93
|
+
* "nobody said", which a standalone sidebar reads as `start`.
|
|
94
|
+
*/
|
|
95
|
+
export declare const PlassSidebarSideContext: React.Context<PlassSidebarSide | null>;
|
|
96
|
+
/**
|
|
97
|
+
* The same five widths as Tailwind variants, for the parts of this that are
|
|
98
|
+
* decided in CSS rather than in JavaScript.
|
|
99
|
+
*
|
|
100
|
+
* Written out per breakpoint because Tailwind only ever sees class names that
|
|
101
|
+
* appear literally in the source — the same reason every table in
|
|
102
|
+
* `internal/styles.ts` is a `Record` of complete strings.
|
|
103
|
+
*
|
|
104
|
+
* `collapsedOnlyClasses` hides something at and above the breakpoint, which is
|
|
105
|
+
* what a sidebar's own trigger wants: the hamburger exists exactly while the
|
|
106
|
+
* column does not. `expandedOnlyClasses` hides it below, which is what the
|
|
107
|
+
* column wants for the one paint between the server's HTML arriving and
|
|
108
|
+
* JavaScript finding out how wide the window is — without it a phone draws the
|
|
109
|
+
* sidebar full width and then throws it away.
|
|
110
|
+
*/
|
|
111
|
+
export declare const collapsedOnlyClasses: Record<PlPageLayoutCollapse, string>;
|
|
112
|
+
export declare const expandedOnlyClasses: Record<PlPageLayoutCollapse, string>;
|
|
113
|
+
/**
|
|
114
|
+
* Whether the window is currently narrower than the breakpoint a sidebar
|
|
115
|
+
* collapses at.
|
|
116
|
+
*
|
|
117
|
+
* `useSyncExternalStore` rather than an effect and a `useState`, for the one
|
|
118
|
+
* reason that matters here: it has a server snapshot, and the server's answer
|
|
119
|
+
* has to be "not collapsed". A collapsed sidebar is a `PlDrawer`, a drawer is a
|
|
120
|
+
* portal, and a portal rendered into `document.body` on the server is not a
|
|
121
|
+
* thing — so the markup that ships is the column, and the classes above are
|
|
122
|
+
* what keep that column off a narrow screen until this hook can say otherwise.
|
|
123
|
+
*/
|
|
124
|
+
export declare function useCollapsed(breakpoint: PlPageLayoutCollapse): boolean;
|
|
125
|
+
/**
|
|
126
|
+
* `start` and `end` as the two sides a `PlDrawer` speaks.
|
|
127
|
+
*
|
|
128
|
+
* A sidebar says which end of the band it takes, because that is a layout
|
|
129
|
+
* question and a layout flips under RTL on its own. A drawer is attached to an
|
|
130
|
+
* edge of the *window*, which `PlassSide` names physically for the same reason
|
|
131
|
+
* a tooltip above a button is above it in every writing direction — so the two
|
|
132
|
+
* have to be translated, and the document's own direction is what translates
|
|
133
|
+
* them.
|
|
134
|
+
*
|
|
135
|
+
* Read during render rather than in an effect, which is safe here for a
|
|
136
|
+
* narrower reason than it looks: the only caller is a sidebar that has already
|
|
137
|
+
* collapsed, and collapsing is a client-side answer. There is no server render
|
|
138
|
+
* of this to disagree with.
|
|
139
|
+
*/
|
|
140
|
+
export declare function drawerSide(side: PlassSidebarSide): PlassSide;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use client";import*as e from"react";export const PlPageLayoutContext=/* @__PURE__ */e.createContext({present:!1,register:()=>{},collapseBelow:"none",open:{start:!1,end:!1},setOpen:()=>{},scroll:"page"});export const PlassSidebarSideContext=/* @__PURE__ */e.createContext(null);const n={xs:null,sm:"(width < 40rem)",md:"(width < 48rem)",lg:"(width < 64rem)",xl:"(width < 80rem)"};export const collapsedOnlyClasses={none:"hidden",xs:"hidden",sm:"sm:hidden",md:"md:hidden",lg:"lg:hidden",xl:"xl:hidden"};export const expandedOnlyClasses={none:"",xs:"",sm:"max-sm:hidden",md:"max-md:hidden",lg:"max-lg:hidden",xl:"max-xl:hidden"};export function useCollapsed(t){const d="none"===t?null:n[t],o=e.useCallback(e=>{if(!d||"undefined"==typeof window||!window.matchMedia)return()=>{};const n=window.matchMedia(d);return n.addEventListener("change",e),()=>n.removeEventListener("change",e)},[d]),i=e.useCallback(()=>!(!d||"undefined"==typeof window||!window.matchMedia)&&window.matchMedia(d).matches,[d]);return e.useSyncExternalStore(o,i,()=>!1)}export function drawerSide(e){const n="undefined"!=typeof document&&"rtl"===getComputedStyle(document.documentElement).direction;return"start"===e?n?"right":"left":n?"left":"right"}
|