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.
Files changed (101) hide show
  1. package/CHANGELOG.md +169 -0
  2. package/README.md +2 -0
  3. package/dist/components/avatar/PlAvatar.js +1 -1
  4. package/dist/components/avatar-group/PlAvatarGroup.d.ts +47 -0
  5. package/dist/components/avatar-group/PlAvatarGroup.js +1 -0
  6. package/dist/components/avatar-group/index.d.ts +2 -0
  7. package/dist/components/avatar-group/index.js +1 -0
  8. package/dist/components/checkbox/PlCheckbox.js +1 -1
  9. package/dist/components/color-picker/PlColorPicker.d.ts +88 -0
  10. package/dist/components/color-picker/PlColorPicker.js +1 -0
  11. package/dist/components/color-picker/index.d.ts +2 -0
  12. package/dist/components/color-picker/index.js +1 -0
  13. package/dist/components/combobox/PlCombobox.js +1 -1
  14. package/dist/components/command-palette/PlCommandPalette.d.ts +83 -0
  15. package/dist/components/command-palette/PlCommandPalette.js +1 -0
  16. package/dist/components/command-palette/index.d.ts +2 -0
  17. package/dist/components/command-palette/index.js +1 -0
  18. package/dist/components/divider/PlDivider.js +1 -1
  19. package/dist/components/fieldset/PlFieldset.d.ts +35 -0
  20. package/dist/components/fieldset/PlFieldset.js +1 -0
  21. package/dist/components/fieldset/index.d.ts +2 -0
  22. package/dist/components/fieldset/index.js +1 -0
  23. package/dist/components/footer/PlFooter.d.ts +90 -0
  24. package/dist/components/footer/PlFooter.js +1 -0
  25. package/dist/components/footer/index.d.ts +2 -0
  26. package/dist/components/footer/index.js +1 -0
  27. package/dist/components/form/PlForm.d.ts +61 -0
  28. package/dist/components/form/PlForm.js +1 -0
  29. package/dist/components/form/index.d.ts +2 -0
  30. package/dist/components/form/index.js +1 -0
  31. package/dist/components/header/PlHeader.d.ts +124 -0
  32. package/dist/components/header/PlHeader.js +1 -0
  33. package/dist/components/header/index.d.ts +2 -0
  34. package/dist/components/header/index.js +1 -0
  35. package/dist/components/menubar/PlMenubar.d.ts +56 -0
  36. package/dist/components/menubar/PlMenubar.js +1 -0
  37. package/dist/components/menubar/index.d.ts +2 -0
  38. package/dist/components/menubar/index.js +1 -0
  39. package/dist/components/navigation-menu/PlNavigationMenu.d.ts +99 -0
  40. package/dist/components/navigation-menu/PlNavigationMenu.js +1 -0
  41. package/dist/components/navigation-menu/index.d.ts +2 -0
  42. package/dist/components/navigation-menu/index.js +1 -0
  43. package/dist/components/number-field/PlNumberField.js +1 -1
  44. package/dist/components/otp-field/PlOtpField.js +1 -1
  45. package/dist/components/page-layout/PlPageLayout.d.ts +139 -0
  46. package/dist/components/page-layout/PlPageLayout.js +1 -0
  47. package/dist/components/page-layout/index.d.ts +2 -0
  48. package/dist/components/page-layout/index.js +1 -0
  49. package/dist/components/radio-group/PlRadioGroup.js +1 -1
  50. package/dist/components/scroll-zone/PlScrollZone.d.ts +35 -15
  51. package/dist/components/scroll-zone/PlScrollZone.js +1 -1
  52. package/dist/components/select/PlSelect.js +1 -1
  53. package/dist/components/sidebar/PlSidebar.d.ts +141 -0
  54. package/dist/components/sidebar/PlSidebar.js +1 -0
  55. package/dist/components/sidebar/PlSidebarTrigger.d.ts +34 -0
  56. package/dist/components/sidebar/PlSidebarTrigger.js +1 -0
  57. package/dist/components/sidebar/index.d.ts +4 -0
  58. package/dist/components/sidebar/index.js +1 -0
  59. package/dist/components/switch/PlSwitch.js +1 -1
  60. package/dist/components/text-field/PlTextField.js +1 -1
  61. package/dist/components/text-link/PlTextLink.d.ts +11 -2
  62. package/dist/components/text-link/PlTextLink.js +1 -1
  63. package/dist/components/toggle/PlToggle.d.ts +55 -0
  64. package/dist/components/toggle/PlToggle.js +1 -0
  65. package/dist/components/toggle/PlToggleGroup.d.ts +48 -0
  66. package/dist/components/toggle/PlToggleGroup.js +1 -0
  67. package/dist/components/toggle/index.d.ts +4 -0
  68. package/dist/components/toggle/index.js +1 -0
  69. package/dist/components/transfer/PlTransfer.d.ts +55 -0
  70. package/dist/components/transfer/PlTransfer.js +1 -0
  71. package/dist/components/transfer/index.d.ts +2 -0
  72. package/dist/components/transfer/index.js +1 -0
  73. package/dist/css/avatar-group.css +2 -0
  74. package/dist/css/color-picker.css +2 -0
  75. package/dist/css/command-palette.css +2 -0
  76. package/dist/css/fieldset.css +2 -0
  77. package/dist/css/footer.css +2 -0
  78. package/dist/css/form.css +2 -0
  79. package/dist/css/header.css +2 -0
  80. package/dist/css/menubar.css +2 -0
  81. package/dist/css/navigation-menu.css +2 -0
  82. package/dist/css/page-layout.css +2 -0
  83. package/dist/css/sidebar.css +2 -0
  84. package/dist/css/toggle.css +2 -0
  85. package/dist/css/transfer.css +2 -0
  86. package/dist/index.d.ts +13 -0
  87. package/dist/index.js +1 -1
  88. package/dist/internal/avatar-group.d.ts +25 -0
  89. package/dist/internal/avatar-group.js +2 -0
  90. package/dist/internal/color.d.ts +109 -0
  91. package/dist/internal/color.js +1 -0
  92. package/dist/internal/link.d.ts +18 -0
  93. package/dist/internal/link.js +1 -0
  94. package/dist/internal/page-layout.d.ts +140 -0
  95. package/dist/internal/page-layout.js +1 -0
  96. package/dist/internal/search.d.ts +31 -0
  97. package/dist/internal/search.js +1 -0
  98. package/dist/internal/styles.d.ts +9 -0
  99. package/dist/internal/styles.js +1 -1
  100. package/dist/styles.css +1 -1
  101. package/package.json +3 -3
@@ -0,0 +1,83 @@
1
+ import * as React from 'react';
2
+ import type { PlassStyleProps } from '../../types.js';
3
+ /** One thing the palette can do. */
4
+ export interface PlCommandItem {
5
+ /** What identifies the command. */
6
+ value: string;
7
+ /** What the row says, and what the query is matched against. */
8
+ label: string;
9
+ /** A second line under it — where the command goes, or what it changes. */
10
+ description?: React.ReactNode;
11
+ /** A glyph before the label. */
12
+ icon?: React.ReactNode;
13
+ /**
14
+ * The keystroke that does the same thing, set at the end of the row. Written
15
+ * the way `PlHotKeys` writes them, so `Mod` resolves per platform. The palette
16
+ * **does not bind it** — the application does.
17
+ */
18
+ shortcut?: string;
19
+ /**
20
+ * The heading this command sits under. Commands are drawn in the order they
21
+ * are given, and a heading is drawn each time the group changes — so a
22
+ * group's commands have to be listed together.
23
+ */
24
+ group?: string;
25
+ /**
26
+ * Extra words the query is matched against but that are never drawn — the
27
+ * name somebody else's product gives the same command, an abbreviation, the
28
+ * word a reader would have searched for.
29
+ */
30
+ keywords?: readonly string[];
31
+ /** In the list but not runnable. */
32
+ disabled?: boolean;
33
+ /** What running it does. */
34
+ onSelect?: () => void;
35
+ }
36
+ export interface PlCommandPaletteProps extends Pick<PlassStyleProps, 'size' | 'color' | 'density'> {
37
+ /** Everything the palette can do. */
38
+ items: readonly PlCommandItem[];
39
+ /** Whether the palette is open. Use with `onOpenChange` for a controlled one. */
40
+ open?: boolean;
41
+ /** Whether it starts open, for an uncontrolled one. @default false */
42
+ defaultOpen?: boolean;
43
+ onOpenChange?: (open: boolean) => void;
44
+ /**
45
+ * Called when a command is run, after its own `onSelect`. The palette closes
46
+ * either way.
47
+ */
48
+ onSelect?: (item: PlCommandItem) => void;
49
+ /**
50
+ * The keystroke that opens the palette, bound on the window. Written the way
51
+ * `PlHotKeys` writes them, so `Mod` is Command on a Mac and Control everywhere
52
+ * else. `false` binds nothing.
53
+ * @default 'Mod+K'
54
+ */
55
+ shortcut?: string | false;
56
+ /** How wide the sheet may get. A number of pixels or any CSS length. */
57
+ width?: number | string;
58
+ /** How tall the list may get before it scrolls. @default 320 */
59
+ maxHeight?: number | string;
60
+ /** The placeholder in the field. @default 'Search commands' */
61
+ placeholder?: string;
62
+ /** The line where the rows would be, when nothing matched. @default 'No commands found' */
63
+ emptyMessage?: React.ReactNode;
64
+ /** The accessible name of the dialog, which has no visible title. @default 'Command palette' */
65
+ label?: string;
66
+ }
67
+ /**
68
+ * Everything an application can do, behind one field.
69
+ *
70
+ * The shape a keyboard-first product takes once it has more actions than a menu
71
+ * bar can hold: a reader types what they want instead of remembering where it
72
+ * was put.
73
+ *
74
+ * It is not a `PlMenu` — a menu is a short list in one place, and every row is
75
+ * visible before you look for it. It is not a `PlCombobox` either: what comes
76
+ * back is not a value, it is *something happening*.
77
+ *
78
+ * Base UI's Autocomplete owns the list — the highlight the pointer and the arrow
79
+ * keys share, `aria-activedescendant`, Enter running the highlighted row — and
80
+ * its Dialog owns the sheet, the scrim, the focus trap and returning the focus
81
+ * to wherever the reader was.
82
+ */
83
+ export declare function PlCommandPalette({ items, open, defaultOpen, onOpenChange, onSelect, shortcut, width, maxHeight, placeholder, emptyMessage, label, size, color, density }: PlCommandPaletteProps): React.ReactElement;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{Autocomplete as s}from"@base-ui/react/autocomplete";import{Dialog as l}from"@base-ui/react/dialog";import{PlHotKeys as o}from"../hot-keys/PlHotKeys.js";import{searchHaystack as r,searchText as n}from"../../internal/search.js";import{controlTextLeadingClasses as i,cx as c,glassClasses as p,hasContent as d,metaTextClasses as m,radiusClasses as u,surfaceSlots as h,toLength as f}from"../../internal/styles.js";const x=/* @__PURE__ */["fixed inset-0 z-(--plass-z-portal) bg-(--plass-scrim)","[backdrop-filter:blur(2px)] [-webkit-backdrop-filter:blur(2px)]","[transition:opacity_var(--plass-duration)_var(--plass-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),g=/* @__PURE__ */[p,"relative flex w-full flex-col overflow-hidden","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"].join(" "),y={xs:"max-w-sm",sm:"max-w-md",md:"max-w-xl",lg:"max-w-2xl",xl:"max-w-3xl"},b={xs:"h-9",sm:"h-10",md:"h-12",lg:"h-14",xl:"h-16"},v={xs:"py-1",sm:"py-1.5",md:"py-2",lg:"py-2.5",xl:"py-3"},w={xs:"px-2.5",sm:"px-3",md:"px-3.5",lg:"px-4",xl:"px-5"},k=/* @__PURE__ */["flex cursor-pointer items-center gap-3 select-none","[transition:background-color_var(--plass-duration)_var(--plass-ease)]","data-[highlighted]:bg-(--p-soft) data-[highlighted]:text-(--p-accent)","data-[disabled]:cursor-not-allowed data-[disabled]:opacity-50","data-[disabled]:saturate-[0.35]"].join(" ");function haystackOf(e){return r([e.label,e.group,...e.keywords??[]])}export function PlCommandPalette({items:r,open:p,defaultOpen:N=!1,onOpenChange:j,onSelect:C,shortcut:K="Mod+K",width:z,maxHeight:S=320,placeholder:_="Search commands",emptyMessage:L="No commands found",label:O="Command palette",size:P="md",color:E="primary",density:M="default"}){const[H,V]=t.useState(N),[D,F]=t.useState(""),I=p??H,R=t.useCallback(e=>{void 0===p&&V(e),j?.(e)},[p,j]);t.useEffect(()=>{if(!1===K)return;const onKeyDown=e=>{(function pressed(e,a){const t=a.toLowerCase().split("+"),s=t[t.length-1],l=new Set(t.slice(0,-1)),o=/mac|iphone|ipad/i.test("undefined"==typeof navigator?"":navigator.platform||navigator.userAgent)?e.metaKey:e.ctrlKey;return!(l.has("mod")!==o||l.has("shift")!==e.shiftKey||l.has("alt")!==e.altKey||!l.has("mod")&&l.has("ctrl")!==e.ctrlKey||!l.has("mod")&&l.has("meta")!==e.metaKey||e.key.toLowerCase()!==s)})(e,K)&&(e.preventDefault(),R(!0))};return window.addEventListener("keydown",onKeyDown),()=>window.removeEventListener("keydown",onKeyDown)},[K,R]);const A=t.useMemo(()=>r.map(haystackOf),[r]),B=t.useMemo(()=>{const e=n(D);return""===e?r:r.filter((a,t)=>A[t].includes(e))},[r,A,D]),T=f(z),W=f(S);return e(l.Root,{open:I,onOpenChange:e=>{e||F(""),R(e)},children:a(l.Portal,{children:[e(l.Backdrop,{className:c("plass-portal",x)}),e(l.Viewport,{className:"plass-portal fixed inset-0 z-(--plass-z-portal) flex justify-center p-4 pt-[12vh]",children:e(l.Popup,{"aria-label":O,className:c(g,u[P],i[P],void 0===T?y[P]:"","self-start"),style:{...h(E,3),...void 0===T?null:{maxWidth:T}},children:a(s.Root,{open:!0,mode:"list",items:B,filter:null,value:D,onValueChange:e=>F(e),itemToStringValue:e=>e.label,children:[e("div",{className:c("flex shrink-0 items-center border-b [border-color:var(--plass-glass-line)]",w[P]),children:e(s.Input,{autoFocus:!0,placeholder:_,className:c("min-w-0 flex-1 bg-transparent [font:inherit] text-inherit [outline:none]","placeholder:text-(--plass-muted-fg) caret-(--p-accent)","selection:bg-(--p-soft-press)",b[P])})}),e(s.List,{className:"min-h-0 flex-1 overflow-y-auto overscroll-contain p-1",style:{maxHeight:W},children:(l,r)=>a(t.Fragment,{children:[l.group&&l.group!==B[r-1]?.group?e("div",{role:"presentation",className:c(w[P],"pt-2 pb-1 font-medium text-(--plass-muted-fg)",m[P]),children:l.group}):null,a(s.Item,{index:r,value:l,disabled:l.disabled,onClick:()=>(e=>{e.disabled||(e.onSelect?.(),C?.(e),R(!1))})(l),className:c(k,u[P],w[P],v["compact"===M?"xs":P]),children:[d(l.icon)?e("span",{className:"flex h-[1lh] shrink-0 items-center [&_svg]:size-[1.15em]",children:l.icon}):null,a("span",{className:"flex min-w-0 flex-1 flex-col",children:[e("span",{className:"truncate",children:l.label}),d(l.description)?e("span",{className:c("truncate text-(--plass-muted-fg)",m[P]),children:l.description}):null]}),l.shortcut?e(o,{size:"xs",keys:l.shortcut,className:"shrink-0"}):null]})]},l.value)}),e(s.Empty,{className:c(w[P],"py-6 text-center text-(--plass-muted-fg)",m[P]),children:L})]})})})]})})}
@@ -0,0 +1,2 @@
1
+ export { PlCommandPalette } from './PlCommandPalette.js';
2
+ export type { PlCommandPaletteProps, PlCommandItem } from './PlCommandPalette.js';
@@ -0,0 +1 @@
1
+ export{PlCommandPalette}from"./PlCommandPalette.js";
@@ -1 +1 @@
1
- "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{Separator as l}from"@base-ui/react/separator";import{metaTextClasses as o}from"../../internal/styles.js";const a="[border-color:var(--p-rule-color)]";function toLength(e){return"number"==typeof e?`${e}px`:e}const i={horizontal:{start:["w-4 shrink-0","flex-1"],center:["flex-1","flex-1"],end:["flex-1","w-4 shrink-0"]},vertical:{start:["h-4 shrink-0","flex-1"],center:["flex-1","flex-1"],end:["flex-1","h-4 shrink-0"]}},n={xs:"gap-1.5",sm:"gap-2",md:"gap-3",lg:"gap-3.5",xl:"gap-4"};export const PlDivider=/* @__PURE__ */t.forwardRef(function PlDivider({orientation:t="horizontal",color:s,size:c="md",length:d,thickness:f,textAlign:p="center",className:h,style:u,children:m,...x},v){const w="vertical"===t,g=null!=m&&!1!==m&&""!==m,b={"--p-rule-color":s?`var(--plass-${s}-line)`:"var(--plass-border)","--p-rule":toLength(f)??"1px"},$=toLength(d),j={...b,...void 0===$?null:w?{height:$}:{width:$},...u};if(!g)return e(l,{ref:v,orientation:t,className:[w?"w-0 border-l [border-left-width:var(--p-rule)] "+(void 0===$?"self-stretch":""):"h-0 w-full border-t [border-top-width:var(--p-rule)]",a,h??""].filter(Boolean).join(" "),style:j,...x});const[k,y]=i[t][p],N=w?"w-0 border-l [border-left-width:var(--p-rule)]":"h-0 border-t [border-top-width:var(--p-rule)]";return r(l,{ref:v,orientation:t,"aria-label":"string"==typeof m?m:void 0,className:["flex items-center",w?"w-auto flex-col "+(void 0===$?"self-stretch":""):"w-full",n[c],h??""].filter(Boolean).join(" "),style:j,...x,children:[e("span",{"aria-hidden":"true",className:`${N} ${k} ${a}`}),e("span",{className:["shrink-0 whitespace-nowrap text-(--plass-muted-fg)",o[c],w?"[writing-mode:vertical-rl]":""].filter(Boolean).join(" "),children:m}),e("span",{"aria-hidden":"true",className:`${N} ${y} ${a}`})]})});
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{Separator as l}from"@base-ui/react/separator";import{metaTextClasses as a,toLength as o}from"../../internal/styles.js";const i="[border-color:var(--p-rule-color)]",s={horizontal:{start:["w-4 shrink-0","flex-1"],center:["flex-1","flex-1"],end:["flex-1","w-4 shrink-0"]},vertical:{start:["h-4 shrink-0","flex-1"],center:["flex-1","flex-1"],end:["flex-1","h-4 shrink-0"]}},n={xs:"gap-1.5",sm:"gap-2",md:"gap-3",lg:"gap-3.5",xl:"gap-4"};export const PlDivider=/* @__PURE__ */t.forwardRef(function PlDivider({orientation:t="horizontal",color:d,size:c="md",length:f,thickness:p,textAlign:h="center",className:m,style:u,children:x,...v},w){const b="vertical"===t,g=null!=x&&!1!==x&&""!==x,j={"--p-rule-color":d?`var(--plass-${d}-line)`:"var(--plass-border)","--p-rule":o(p)??"1px"},$=o(f),k={...j,...void 0===$?null:b?{height:$}:{width:$},...u};if(!g)return e(l,{ref:w,orientation:t,className:[b?"w-0 border-l [border-left-width:var(--p-rule)] "+(void 0===$?"self-stretch":""):"h-0 w-full border-t [border-top-width:var(--p-rule)]",i,m??""].filter(Boolean).join(" "),style:k,...v});const[N,y]=s[t][h],z=b?"w-0 border-l [border-left-width:var(--p-rule)]":"h-0 border-t [border-top-width:var(--p-rule)]";return r(l,{ref:w,orientation:t,"aria-label":"string"==typeof x?x:void 0,className:["flex items-center",b?"w-auto flex-col "+(void 0===$?"self-stretch":""):"w-full",n[c],m??""].filter(Boolean).join(" "),style:k,...v,children:[e("span",{"aria-hidden":"true",className:`${z} ${N} ${i}`}),e("span",{className:["shrink-0 whitespace-nowrap text-(--plass-muted-fg)",a[c],b?"[writing-mode:vertical-rl]":""].filter(Boolean).join(" "),children:x}),e("span",{"aria-hidden":"true",className:`${z} ${y} ${i}`})]})});
@@ -0,0 +1,35 @@
1
+ import * as React from 'react';
2
+ import type { PlassSize } from '../../types.js';
3
+ export interface PlFieldsetProps extends Omit<React.ComponentPropsWithoutRef<'fieldset'>, 'color'> {
4
+ /**
5
+ * What the group is called.
6
+ *
7
+ * It becomes part of the accessible name of every control inside, so it has
8
+ * to be a phrase that still reads correctly in front of each of them —
9
+ * "Billing address", not "Where should we send it?".
10
+ */
11
+ legend?: React.ReactNode;
12
+ /** A line under the legend. */
13
+ description?: React.ReactNode;
14
+ /** Disables every control inside at once, the way a `<fieldset>` always has. */
15
+ disabled?: boolean;
16
+ /** The type scale of the legend and the gap between the controls. @default 'md' */
17
+ size?: PlassSize;
18
+ children?: React.ReactNode;
19
+ }
20
+ /**
21
+ * A group of controls that answer one question together, with a name on it.
22
+ *
23
+ * It draws **no surface**, and that is deliberate: a group of fields is a
24
+ * *grouping* and not a sheet, and the sheet already exists — put this inside a
25
+ * `PlCard` or a `PlBox` when one is wanted. What it owns is the legend, the gap
26
+ * the controls stand at, and the one thing only a real `<fieldset>` can do:
27
+ * `disabled` reaches every control inside it, including ones a component three
28
+ * levels down rendered and never heard of it.
29
+ *
30
+ * The legend is a `<div>` pointed at by `aria-labelledby` rather than a
31
+ * `<legend>` — Base UI's decision, and the one that makes the group a normal
32
+ * flex container: a real rendered legend is lifted out of its fieldset's
33
+ * content box by every browser, so a `gap` would put no space under it at all.
34
+ */
35
+ export declare const PlFieldset: React.ForwardRefExoticComponent<PlFieldsetProps & React.RefAttributes<HTMLFieldSetElement>>;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as s}from"react/jsx-runtime";import*as l from"react";import{Fieldset as r}from"@base-ui/react/fieldset";import{cx as i,hasContent as t,metaTextClasses as a,sheetHeaderGapClasses as n,sheetSectionGapClasses as d,sheetTitleClasses as o}from"../../internal/styles.js";export const PlFieldset=/* @__PURE__ */l.forwardRef(function PlFieldset({legend:l,description:c,disabled:m=!1,size:f="md",className:p,children:u,...x},b){const h=t(l)||t(c);return s(r.Root,{ref:b,disabled:m,className:i("m-0 flex min-w-0 flex-col border-0 p-0",d[f],p),...x,children:[h?s(r.Legend,{className:i("flex min-w-0 flex-col p-0",n[f]),children:[t(l)?e("span",{className:i("font-semibold",o[f]),children:l}):null,t(c)?e("span",{className:i("text-(--plass-muted-fg)",a[f]),children:c}):null]}):null,u]})});
@@ -0,0 +1,2 @@
1
+ export { PlFieldset } from './PlFieldset.js';
2
+ export type { PlFieldsetProps } from './PlFieldset.js';
@@ -0,0 +1 @@
1
+ export{PlFieldset}from"./PlFieldset.js";
@@ -0,0 +1,90 @@
1
+ import * as React from 'react';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import type { PlassColor, PlassDensity, PlassElevation, PlassPosition, PlassSize, PlassVariant } from '../../types.js';
4
+ /** How wide the content inside the sheet is allowed to get. */
5
+ export type PlFooterWidth = PlassSize | 'none';
6
+ export interface PlFooterProps extends Omit<React.ComponentPropsWithoutRef<'footer'>, 'color' | 'title'> {
7
+ /**
8
+ * How the bar sits in the page's scroll.
9
+ *
10
+ * `static` — the default, and the opposite of `PlHeader`'s — is what a footer
11
+ * is: the thing at the end of the document, reached by scrolling to it.
12
+ * `sticky` and `fixed` are for the bar that has to stay in reach — a form's
13
+ * save row, a cookie notice — and a `PlPageLayout` reserves the height a
14
+ * `fixed` one takes out of the flow.
15
+ * @default 'static'
16
+ */
17
+ position?: PlassPosition;
18
+ /**
19
+ * What the sheet is made of, said the way a **container** says it: the bar is
20
+ * never dyed, because what is on it arrives with colours of its own.
21
+ * @default 'glass'
22
+ */
23
+ variant?: PlassVariant;
24
+ /**
25
+ * The bar's scale — its gutter and the air above and below its content. As on
26
+ * `PlBox`, `size` here is the size of the *sheet*.
27
+ * @default 'md'
28
+ */
29
+ size?: PlassSize;
30
+ /** @default 'primary' */
31
+ color?: PlassColor;
32
+ /** @default 'default' */
33
+ density?: PlassDensity;
34
+ /** Drop shadow depth. `0` — the default — is flat. @default 0 */
35
+ elevation?: PlassElevation;
36
+ /**
37
+ * Draws a hairline along the top edge. On by default: a footer is the one
38
+ * sheet on the page with content directly above it and nothing below, so the
39
+ * line is the whole of what says the document ended.
40
+ * @default true
41
+ */
42
+ divider?: boolean;
43
+ /**
44
+ * Holds the content to a measure and centres it, while the sheet itself still
45
+ * spans the window. The same ladder `PlContainer`'s `maxWidth` uses.
46
+ * @default 'none'
47
+ */
48
+ maxWidth?: PlFooterWidth;
49
+ /** The gutter and the air above and below. @default true */
50
+ padded?: boolean;
51
+ /**
52
+ * The name the bar is announced by. Worth writing when a page has more than
53
+ * one `<footer>` in it — an article's own and the site's.
54
+ */
55
+ label?: string;
56
+ /**
57
+ * Renders something other than a `<footer>`. Base UI's own escape hatch, and
58
+ * rarely what you want: at the top level of a document that tag is the
59
+ * `contentinfo` landmark, and it is what says "this is the site's own
60
+ * information" rather than "this is more of the article".
61
+ */
62
+ render?: useRender.RenderProp;
63
+ /**
64
+ * Everything in it. A footer's content is columns of links, a copyright line,
65
+ * a logo — all of it the caller's, none of it something a component could
66
+ * guess at, which is why this one has slots for nothing and space for
67
+ * anything.
68
+ */
69
+ children?: React.ReactNode;
70
+ }
71
+ /**
72
+ * The sheet at the end of a page.
73
+ *
74
+ * A real `<footer>`, which is the whole reason it is a component rather than a
75
+ * `<div>`: at the top level of a document that tag is the `contentinfo`
76
+ * landmark — the region a screen reader offers as "the site's own information"
77
+ * and a search engine reads the copyright, the address and the site map out of.
78
+ *
79
+ * **It has no slots on purpose**, which is the difference between it and
80
+ * `PlHeader`. A header's three regions are a fixed arrangement worth writing
81
+ * once; a footer's content is four columns on one site and one line on the
82
+ * next, and a component that guessed at the arrangement would be a component
83
+ * every second site fights. What it decides is the sheet: the surface, the
84
+ * gutter, the hairline that says the document ended, and whether it stays in
85
+ * reach.
86
+ *
87
+ * Inside a `PlPageLayout` it also registers itself, so a `fixed` footer's
88
+ * height is reserved rather than sitting on top of the last paragraph.
89
+ */
90
+ export declare const PlFooter: React.ForwardRefExoticComponent<PlFooterProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e}from"react/jsx-runtime";import*as r from"react";import{useRender as t}from"@base-ui/react/use-render";import{PlPageLayoutContext as o}from"../../internal/page-layout.js";import{cx as a,sheetPaddingXClasses as s,sheetPaddingYClasses as i,sheetRestClasses as l,surfaceSlots as m,transitionClasses as n}from"../../internal/styles.js";const d=l,c={static:"",sticky:"sticky bottom-0 z-20",fixed:"fixed inset-x-0 bottom-0 z-30"},f={xs:"max-w-[30rem]",sm:"max-w-[40rem]",md:"max-w-[48rem]",lg:"max-w-[64rem]",xl:"max-w-[80rem]"};export const PlFooter=/* @__PURE__ */r.forwardRef(function PlFooter({position:l="static",variant:x="glass",size:u="md",color:p="primary",density:w="default",elevation:y=0,divider:b=!0,maxWidth:v="none",padded:g=!0,label:h,render:j,className:k,style:z,children:N,...C},F){const{register:P}=r.useContext(o),R=r.useCallback(e=>{P("footer",e),"function"==typeof F?F(e):F&&(F.current=e)},[P,F]),W=a("w-full min-w-0",d[x],b?"border-t [border-color:var(--plass-divider)]":"",c[l],n,k);return t({render:j??e("footer",{}),ref:R,props:{"aria-label":h,className:W,style:{...m(p,y),...z},children:e("div",{className:a("w-full",g?a(s[w][u],i[w][u]):"","none"===v?"":a(f[v],"mx-auto")),children:N}),...C}})});
@@ -0,0 +1,2 @@
1
+ export { PlFooter } from './PlFooter.js';
2
+ export type { PlFooterProps, PlFooterWidth } from './PlFooter.js';
@@ -0,0 +1 @@
1
+ export{PlFooter}from"./PlFooter.js";
@@ -0,0 +1,61 @@
1
+ import * as React from 'react';
2
+ import type { PlassSize } from '../../types.js';
3
+ /**
4
+ * When a field decides whether it is valid.
5
+ *
6
+ * Base UI's own three, kept under its own spelling because they are what a
7
+ * caller will read about everywhere else and a nicer synonym would only be a
8
+ * word to translate back.
9
+ */
10
+ export type PlFormValidationMode = 'onSubmit' | 'onBlur' | 'onChange';
11
+ /** Errors that came from somewhere else, keyed by the field's `name`. */
12
+ export type PlFormErrors = Record<string, string | string[]>;
13
+ export interface PlFormProps extends Omit<React.ComponentPropsWithoutRef<'form'>, 'onSubmit'> {
14
+ /**
15
+ * When a field validates.
16
+ *
17
+ * - `onSubmit` — on submit, and on every change afterwards. The default, and
18
+ * the only one that does not tell somebody their email is wrong while they
19
+ * are still typing it.
20
+ * - `onBlur` — when a field loses focus.
21
+ * - `onChange` — on every keystroke.
22
+ * @default 'onSubmit'
23
+ */
24
+ validationMode?: PlFormValidationMode;
25
+ /**
26
+ * Errors from outside the browser's own validation — a server, a form action,
27
+ * a schema — keyed by the `name` of the field each belongs to. They are shown
28
+ * on the field, and cleared as soon as that field changes.
29
+ */
30
+ errors?: PlFormErrors;
31
+ /**
32
+ * Called on a valid submit, with the form's values. The native submit event is
33
+ * prevented, so nothing navigates.
34
+ */
35
+ onSubmit?: (values: Record<string, unknown>) => void;
36
+ /**
37
+ * The gap between the form's children. A form is a stack, and this is which
38
+ * rung of the ladder it stacks on.
39
+ * @default 'md'
40
+ */
41
+ size?: PlassSize;
42
+ children?: React.ReactNode;
43
+ }
44
+ /**
45
+ * A `<form>` that knows which of its fields is wrong.
46
+ *
47
+ * On its own, a page of `PlTextField`s validates one field at a time and a
48
+ * failed submit leaves the reader to find the red one. What this adds is the
49
+ * part that has to be owned *above* the fields: a submit collects every field's
50
+ * validity at once, focuses the first one that failed, and `errors` puts a
51
+ * server's answer back on the field it belongs to rather than in a banner at
52
+ * the top.
53
+ *
54
+ * It is **not a form library**. There is no schema, no resolver and no field
55
+ * array here — a project that wants those keeps them and hands the result to
56
+ * `errors`, which is the seam this is built around.
57
+ *
58
+ * It draws no surface either. A form is a stack of controls, and the sheet it
59
+ * sits on is a `PlCard` or a `PlBox` when one is wanted.
60
+ */
61
+ export declare const PlForm: React.ForwardRefExoticComponent<PlFormProps & React.RefAttributes<HTMLFormElement>>;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as r}from"react/jsx-runtime";import*as o from"react";import{Form as e}from"@base-ui/react/form";import{cx as m,sheetSectionGapClasses as t}from"../../internal/styles.js";export const PlForm=/* @__PURE__ */o.forwardRef(function PlForm({validationMode:o="onSubmit",errors:i,onSubmit:s,size:a="md",className:n,children:l,...c},f){return r(e,{ref:f,validationMode:o,errors:i,onFormSubmit:r=>s?.(r),className:m("flex flex-col",t[a],n),...c,children:l})});
@@ -0,0 +1,2 @@
1
+ export { PlForm } from './PlForm.js';
2
+ export type { PlFormProps, PlFormErrors, PlFormValidationMode } from './PlForm.js';
@@ -0,0 +1 @@
1
+ export{PlForm}from"./PlForm.js";
@@ -0,0 +1,124 @@
1
+ import * as React from 'react';
2
+ import { useRender } from '@base-ui/react/use-render';
3
+ import type { PlassAlign, PlassColor, PlassDensity, PlassElevation, PlassPosition, PlassSize, PlassVariant } from '../../types.js';
4
+ /** How wide the row inside the bar is allowed to get. */
5
+ export type PlHeaderWidth = PlassSize | 'none';
6
+ export interface PlHeaderProps extends Omit<React.ComponentPropsWithoutRef<'header'>, 'color' | 'title'> {
7
+ /**
8
+ * The leading slot: the logo, the product's name, the thing that is the same
9
+ * on every page.
10
+ *
11
+ * It is a slot rather than the first of `children` because the three regions
12
+ * of a bar are laid out against each other — the middle can only be centred
13
+ * in the bar if the two ends are measured — and a caller writing three
14
+ * wrappers by hand is a caller whose header drifts from the next one.
15
+ */
16
+ brand?: React.ReactNode;
17
+ /**
18
+ * The trailing slot: the account menu, the theme switch, the call to action.
19
+ * Laid out end-aligned, so a row of buttons needs no wrapper of its own.
20
+ */
21
+ actions?: React.ReactNode;
22
+ /**
23
+ * Where the middle slot sits.
24
+ *
25
+ * - `start` — packed against the brand, taking whatever is left. The
26
+ * arrangement of an application's bar, and the default.
27
+ * - `center` — centred in the bar itself, not in the space left over. The two
28
+ * ends are given equal shares for this, so the middle stays on the bar's
29
+ * own midline however wide the brand is.
30
+ * - `end` — packed against the actions.
31
+ * @default 'start'
32
+ */
33
+ align?: PlassAlign;
34
+ /**
35
+ * How the bar sits in the page's scroll, spelled the way CSS spells it.
36
+ *
37
+ * `sticky` — the default — holds it against the top of the window once the
38
+ * page has scrolled to it, while leaving it in the flow so nothing has to be
39
+ * padded out of its way. `fixed` takes it out of the flow entirely, which a
40
+ * `PlPageLayout` answers by reserving its height. `static` lets it scroll
41
+ * away.
42
+ * @default 'sticky'
43
+ */
44
+ position?: PlassPosition;
45
+ /**
46
+ * What the sheet is made of, said the way a **container** says it: the bar is
47
+ * never dyed, because what is on it arrives with colours of its own.
48
+ * @default 'glass'
49
+ */
50
+ variant?: PlassVariant;
51
+ /**
52
+ * The bar's scale — its height floor, its gutter and the air around its
53
+ * slots. As on `PlBox`, `size` here is the size of the *sheet*.
54
+ * @default 'md'
55
+ */
56
+ size?: PlassSize;
57
+ /** @default 'primary' */
58
+ color?: PlassColor;
59
+ /** @default 'default' */
60
+ density?: PlassDensity;
61
+ /**
62
+ * Drop shadow depth. `0` — the default — is flat: a header is attached to the
63
+ * top of the window rather than floating over the middle of it, and `divider`
64
+ * is what separates it from the content.
65
+ * @default 0
66
+ */
67
+ elevation?: PlassElevation;
68
+ /**
69
+ * Draws a hairline along the bottom edge, against the content the bar is
70
+ * over. On by default: a bar pinned over a scrolling page has content passing
71
+ * underneath it at every moment, and a translucent sheet with nothing marking
72
+ * its edge reads as part of that.
73
+ * @default true
74
+ */
75
+ divider?: boolean;
76
+ /**
77
+ * Holds the row of slots to a measure and centres it, while the sheet itself
78
+ * still spans the window. The same ladder `PlContainer`'s `maxWidth` uses, so
79
+ * a header and the container under it line up on the same edge.
80
+ * @default 'none'
81
+ */
82
+ maxWidth?: PlHeaderWidth;
83
+ /** The gutter down each side of the row. @default true */
84
+ padded?: boolean;
85
+ /**
86
+ * The name the bar is announced by. Worth writing when a page has more than
87
+ * one `<header>` in it — an article's own header and the site's — because
88
+ * "banner" twice tells a reader which is which not at all.
89
+ */
90
+ label?: string;
91
+ /**
92
+ * Renders something other than a `<header>`. Base UI's own escape hatch, and
93
+ * rarely what you want: the bar at the top of a page is a banner, and the tag
94
+ * is what says so to a search engine and to a screen reader's landmark list.
95
+ */
96
+ render?: useRender.RenderProp;
97
+ /** The middle slot. */
98
+ children?: React.ReactNode;
99
+ }
100
+ /**
101
+ * The bar across the top of a page.
102
+ *
103
+ * A real `<header>`, which is the whole reason it is a component rather than a
104
+ * row of `<div>`s: at the top level of a document that tag is the `banner`
105
+ * landmark, and it is what a screen reader's landmark list, a reader mode and a
106
+ * search engine's understanding of the page are all built out of.
107
+ *
108
+ * Its three slots are props rather than compound sub-components, for `PlCard`'s
109
+ * reason: the arrangement is fixed — brand, middle, actions — and what a caller
110
+ * wants to decide is what goes in each. That the middle can be centred on the
111
+ * bar's own midline is only possible because the ends are the component's to
112
+ * measure.
113
+ *
114
+ * Inside a `PlPageLayout` it also registers itself, so a sidebar that holds its
115
+ * place knows how far down the window to start. Outside one it is simply a bar,
116
+ * and everything above still works.
117
+ *
118
+ * It is not a `PlToolbar` with a tag on it. A toolbar is a row of controls
119
+ * anywhere on a screen and takes a height from its padding alone; a header is
120
+ * the page's banner, and it has a height floor, a measure, a brand slot and a
121
+ * place in a layout — none of which mean anything on a row of controls beside a
122
+ * table.
123
+ */
124
+ export declare const PlHeader: React.ForwardRefExoticComponent<PlHeaderProps & React.RefAttributes<HTMLElement>>;
@@ -0,0 +1 @@
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as s from"react";import{useRender as i}from"@base-ui/react/use-render";import{PlPageLayoutContext as t}from"../../internal/page-layout.js";import{cx as a,hasContent as n,sheetPaddingXClasses as l,sheetRestClasses as m,sheetSectionGapClasses as d,surfaceSlots as c,transitionClasses as o}from"../../internal/styles.js";const x={xs:"min-h-10",sm:"min-h-12",md:"min-h-16",lg:"min-h-20",xl:"min-h-24"},f={xs:"py-2",sm:"py-2",md:"py-3",lg:"py-4",xl:"py-5"},p={xs:"gap-3",sm:"gap-4",md:"gap-6",lg:"gap-7",xl:"gap-8"},u={xs:"max-w-[30rem]",sm:"max-w-[40rem]",md:"max-w-[48rem]",lg:"max-w-[64rem]",xl:"max-w-[80rem]"},h=m,y={static:"",sticky:"sticky top-0 z-20",fixed:"fixed inset-x-0 top-0 z-30"},w={start:"shrink-0",center:"flex-1 basis-0",end:"shrink-0"},g={start:"flex min-w-0 flex-1 items-center justify-start",center:"flex min-w-0 shrink items-center justify-center",end:"flex min-w-0 flex-1 items-center justify-end"};export const PlHeader=/* @__PURE__ */s.forwardRef(function PlHeader({brand:m,actions:v,align:b="start",position:j="sticky",variant:N="glass",size:k="md",color:z="primary",density:C="default",elevation:H=0,divider:P=!0,maxWidth:R="none",padded:W=!0,label:q,render:A,className:B,style:D,children:E,...F},G){const{register:I}=s.useContext(t),J=s.useCallback(e=>{I("header",e),"function"==typeof G?G(e):G&&(G.current=e)},[I,G]),K=a("w-full min-w-0",h[N],P?"border-b [border-color:var(--plass-divider)]":"",y[j],o,B);return i({render:A??e("header",{}),ref:J,props:{"aria-label":q,className:K,style:{...c(z,H),...D},children:r("div",{className:a("flex w-full items-center",x[k],f[k],p[k],W?l[C][k]:"","none"===R?"":a(u[R],"mx-auto")),children:[n(m)?e("div",{className:a("flex min-w-0 items-center",w[b],d[k]),children:m}):"center"===b?e("div",{"aria-hidden":"true",className:w[b]}):null,n(E)?e("div",{className:a(g[b],d[k]),children:E}):null,n(v)?e("div",{className:a("flex min-w-0 items-center justify-end",w[b],d[k]),children:v}):"center"===b?e("div",{"aria-hidden":"true",className:w[b]}):null]}),...F}})});
@@ -0,0 +1,2 @@
1
+ export { PlHeader } from './PlHeader.js';
2
+ export type { PlHeaderProps, PlHeaderWidth } from './PlHeader.js';
@@ -0,0 +1 @@
1
+ export{PlHeader}from"./PlHeader.js";
@@ -0,0 +1,56 @@
1
+ import * as React from 'react';
2
+ import type { PlassOrientation, PlassStyleProps } from '../../types.js';
3
+ export interface PlMenubarProps extends Pick<PlassStyleProps, 'size' | 'color' | 'density'>, Omit<React.ComponentPropsWithoutRef<'div'>, 'color'> {
4
+ /**
5
+ * Which way the bar runs. `vertical` is the shape a side rail of menus takes;
6
+ * the arrow keys follow it either way.
7
+ * @default 'horizontal'
8
+ */
9
+ orientation?: PlassOrientation;
10
+ /**
11
+ * Whether an open menu takes the page away. On — the default, and Base UI's —
12
+ * an open menu is what the pointer is talking to.
13
+ * @default true
14
+ */
15
+ modal?: boolean;
16
+ /** Whether the arrow keys wrap around at the ends of the bar. @default true */
17
+ loopFocus?: boolean;
18
+ /** Disables every menu on the bar at once. */
19
+ disabled?: boolean;
20
+ /** The menus. */
21
+ children?: React.ReactNode;
22
+ }
23
+ export interface PlMenubarMenuProps {
24
+ /** The word on the bar. */
25
+ label: React.ReactNode;
26
+ /** Content before the label. Sized in `em`, so it tracks it. */
27
+ startIcon?: React.ReactNode;
28
+ /** Unavailable. The word stays on the bar and opens nothing. */
29
+ disabled?: boolean;
30
+ /** The rows, written exactly as they are inside a `PlMenu`. */
31
+ children?: React.ReactNode;
32
+ }
33
+ /**
34
+ * One menu on the bar: the word, and the rows behind it.
35
+ *
36
+ * It has no `size`, `color` or `density` of its own — all three belong to the
37
+ * bar, which is the only place they can be set once and hold for every menu on
38
+ * it. The rows inside are the same `PlMenuItem`, `PlMenuSeparator`,
39
+ * `PlMenuGroup` and `PlMenuSubmenu` a `PlMenu` takes, because it *is* the same
40
+ * menu.
41
+ */
42
+ export declare function PlMenubarMenu({ label, startIcon, disabled, children }: PlMenubarMenuProps): React.ReactElement;
43
+ /**
44
+ * The strip of words at the top of an application — File, Edit, View — each of
45
+ * which opens a menu.
46
+ *
47
+ * What makes it a bar rather than a row of separate menus is what happens once
48
+ * one is open: moving along the strip walks through the others instead of
49
+ * closing the one you left, and the arrow keys move between the menus as well
50
+ * as inside them. Base UI owns all of that, along with the `menubar` role.
51
+ *
52
+ * It draws **no surface of its own**. A menu bar sits *on* something — a
53
+ * `PlToolbar`, a `PlHeader` — and a sheet under a strip that is already on a
54
+ * sheet is two sheets.
55
+ */
56
+ export declare const PlMenubar: React.ForwardRefExoticComponent<PlMenubarProps & React.RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ "use client";import{jsxs as e,jsx as t}from"react/jsx-runtime";import*as o from"react";import{Menubar as s}from"@base-ui/react/menubar";import{PlMenu as r}from"../menu/PlMenu.js";import{MenuContext as n}from"../../internal/menu.js";import{controlTextClasses as a,cx as i,gapClasses as l,hasContent as c,iconClasses as p,paddingXClasses as d,radiusClasses as u,transitionClasses as m}from"../../internal/styles.js";const f={xs:"h-4.5",sm:"h-5.5",md:"h-6.5",lg:"h-8",xl:"h-10"},b=/* @__PURE__ */["inline-flex shrink-0 cursor-pointer select-none items-center justify-center","whitespace-nowrap font-medium leading-none","text-(--plass-fg) bg-transparent","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",m,p,"hover:bg-(--p-soft)","data-[popup-open]:bg-(--p-soft-hover) data-[popup-open]:text-(--p-accent)","focus-visible:[outline:2px_solid_var(--p-ring)] focus-visible:[outline-offset:-2px]","disabled:cursor-not-allowed disabled:opacity-50 disabled:saturate-[0.35]","disabled:hover:bg-transparent"].join(" ");export function PlMenubarMenu({label:s,startIcon:p,disabled:m=!1,children:h}){const{size:v,color:x,density:g}=o.useContext(n);return t(r,{size:v,color:x,density:g,disabled:m,openOnHover:!0,sideOffset:4,trigger:e("button",{type:"button",disabled:m,className:i(b,f[v],a[v],l[v],d["default"===g?"compact":g][v],u[v]),children:[c(p)?p:null,s]}),children:h})}export const PlMenubar=/* @__PURE__ */o.forwardRef(function PlMenubar({size:e="md",color:r="primary",density:a="default",orientation:c="horizontal",modal:p=!0,loopFocus:d=!0,disabled:u=!1,className:m,style:f,children:b,...h},v){const x=o.useMemo(()=>({size:e,color:r,density:a}),[e,r,a]);return t(n.Provider,{value:x,children:t(s,{ref:v,orientation:c,modal:p,loopFocus:d,disabled:u,className:i("flex items-center","vertical"===c?"flex-col items-stretch":"flex-row",l[e],m),style:{"--p-soft":`var(--plass-${r}-soft)`,"--p-soft-hover":`var(--plass-${r}-soft-hover)`,"--p-accent":`var(--plass-${r}-accent)`,"--p-ring":`var(--plass-${r}-ring)`,...f},...h,children:b})})});
@@ -0,0 +1,2 @@
1
+ export { PlMenubar, PlMenubarMenu } from './PlMenubar.js';
2
+ export type { PlMenubarProps, PlMenubarMenuProps } from './PlMenubar.js';
@@ -0,0 +1 @@
1
+ export{PlMenubar,PlMenubarMenu}from"./PlMenubar.js";