plass-ui 1.0.3 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/CHANGELOG.md +189 -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.d.ts +3 -1
  9. package/dist/components/checkbox/PlCheckbox.js +1 -1
  10. package/dist/components/color-picker/PlColorPicker.d.ts +88 -0
  11. package/dist/components/color-picker/PlColorPicker.js +1 -0
  12. package/dist/components/color-picker/index.d.ts +2 -0
  13. package/dist/components/color-picker/index.js +1 -0
  14. package/dist/components/combobox/PlCombobox.d.ts +4 -2
  15. package/dist/components/combobox/PlCombobox.js +1 -1
  16. package/dist/components/command-palette/PlCommandPalette.d.ts +89 -0
  17. package/dist/components/command-palette/PlCommandPalette.js +1 -0
  18. package/dist/components/command-palette/index.d.ts +2 -0
  19. package/dist/components/command-palette/index.js +1 -0
  20. package/dist/components/divider/PlDivider.js +1 -1
  21. package/dist/components/drawer/PlDrawer.d.ts +4 -2
  22. package/dist/components/drawer/PlDrawer.js +1 -1
  23. package/dist/components/fieldset/PlFieldset.d.ts +35 -0
  24. package/dist/components/fieldset/PlFieldset.js +1 -0
  25. package/dist/components/fieldset/index.d.ts +2 -0
  26. package/dist/components/fieldset/index.js +1 -0
  27. package/dist/components/footer/PlFooter.d.ts +90 -0
  28. package/dist/components/footer/PlFooter.js +1 -0
  29. package/dist/components/footer/index.d.ts +2 -0
  30. package/dist/components/footer/index.js +1 -0
  31. package/dist/components/form/PlForm.d.ts +61 -0
  32. package/dist/components/form/PlForm.js +1 -0
  33. package/dist/components/form/index.d.ts +2 -0
  34. package/dist/components/form/index.js +1 -0
  35. package/dist/components/header/PlHeader.d.ts +124 -0
  36. package/dist/components/header/PlHeader.js +1 -0
  37. package/dist/components/header/index.d.ts +2 -0
  38. package/dist/components/header/index.js +1 -0
  39. package/dist/components/menu/PlMenu.d.ts +4 -2
  40. package/dist/components/menu/PlMenu.js +1 -1
  41. package/dist/components/menubar/PlMenubar.d.ts +60 -0
  42. package/dist/components/menubar/PlMenubar.js +1 -0
  43. package/dist/components/menubar/index.d.ts +2 -0
  44. package/dist/components/menubar/index.js +1 -0
  45. package/dist/components/modal/PlModal.d.ts +4 -2
  46. package/dist/components/modal/PlModal.js +1 -1
  47. package/dist/components/navigation-menu/PlNavigationMenu.d.ts +103 -0
  48. package/dist/components/navigation-menu/PlNavigationMenu.js +1 -0
  49. package/dist/components/navigation-menu/index.d.ts +2 -0
  50. package/dist/components/navigation-menu/index.js +1 -0
  51. package/dist/components/number-field/PlNumberField.d.ts +4 -2
  52. package/dist/components/number-field/PlNumberField.js +1 -1
  53. package/dist/components/otp-field/PlOtpField.d.ts +3 -1
  54. package/dist/components/otp-field/PlOtpField.js +1 -1
  55. package/dist/components/overlay/PlOverlay.d.ts +4 -2
  56. package/dist/components/overlay/PlOverlay.js +1 -1
  57. package/dist/components/page-layout/PlPageLayout.d.ts +139 -0
  58. package/dist/components/page-layout/PlPageLayout.js +1 -0
  59. package/dist/components/page-layout/index.d.ts +2 -0
  60. package/dist/components/page-layout/index.js +1 -0
  61. package/dist/components/radio-group/PlRadioGroup.d.ts +3 -1
  62. package/dist/components/radio-group/PlRadioGroup.js +1 -1
  63. package/dist/components/scroll-zone/PlScrollZone.d.ts +35 -15
  64. package/dist/components/scroll-zone/PlScrollZone.js +1 -1
  65. package/dist/components/select/PlSelect.d.ts +3 -1
  66. package/dist/components/select/PlSelect.js +1 -1
  67. package/dist/components/sidebar/PlSidebar.d.ts +141 -0
  68. package/dist/components/sidebar/PlSidebar.js +1 -0
  69. package/dist/components/sidebar/PlSidebarTrigger.d.ts +34 -0
  70. package/dist/components/sidebar/PlSidebarTrigger.js +1 -0
  71. package/dist/components/sidebar/index.d.ts +4 -0
  72. package/dist/components/sidebar/index.js +1 -0
  73. package/dist/components/switch/PlSwitch.d.ts +3 -1
  74. package/dist/components/switch/PlSwitch.js +1 -1
  75. package/dist/components/text-field/PlTextField.d.ts +3 -1
  76. package/dist/components/text-field/PlTextField.js +1 -1
  77. package/dist/components/text-link/PlTextLink.d.ts +11 -2
  78. package/dist/components/text-link/PlTextLink.js +1 -1
  79. package/dist/components/toast/PlToast.d.ts +10 -0
  80. package/dist/components/toast/PlToast.js +1 -1
  81. package/dist/components/toggle/PlToggle.d.ts +55 -0
  82. package/dist/components/toggle/PlToggle.js +1 -0
  83. package/dist/components/toggle/PlToggleGroup.d.ts +48 -0
  84. package/dist/components/toggle/PlToggleGroup.js +1 -0
  85. package/dist/components/toggle/index.d.ts +4 -0
  86. package/dist/components/toggle/index.js +1 -0
  87. package/dist/components/transfer/PlTransfer.d.ts +55 -0
  88. package/dist/components/transfer/PlTransfer.js +1 -0
  89. package/dist/components/transfer/index.d.ts +2 -0
  90. package/dist/components/transfer/index.js +1 -0
  91. package/dist/css/avatar-group.css +2 -0
  92. package/dist/css/color-picker.css +2 -0
  93. package/dist/css/command-palette.css +2 -0
  94. package/dist/css/fieldset.css +2 -0
  95. package/dist/css/footer.css +2 -0
  96. package/dist/css/form.css +2 -0
  97. package/dist/css/header.css +2 -0
  98. package/dist/css/menubar.css +2 -0
  99. package/dist/css/navigation-menu.css +2 -0
  100. package/dist/css/page-layout.css +2 -0
  101. package/dist/css/sidebar.css +2 -0
  102. package/dist/css/toggle.css +2 -0
  103. package/dist/css/transfer.css +2 -0
  104. package/dist/index.d.ts +13 -0
  105. package/dist/index.js +1 -1
  106. package/dist/internal/avatar-group.d.ts +25 -0
  107. package/dist/internal/avatar-group.js +2 -0
  108. package/dist/internal/color.d.ts +109 -0
  109. package/dist/internal/color.js +1 -0
  110. package/dist/internal/link.d.ts +18 -0
  111. package/dist/internal/link.js +1 -0
  112. package/dist/internal/page-layout.d.ts +140 -0
  113. package/dist/internal/page-layout.js +1 -0
  114. package/dist/internal/picker.d.ts +4 -2
  115. package/dist/internal/picker.js +1 -1
  116. package/dist/internal/search.d.ts +31 -0
  117. package/dist/internal/search.js +1 -0
  118. package/dist/internal/styles.d.ts +9 -0
  119. package/dist/internal/styles.js +1 -1
  120. package/dist/styles.css +1 -1
  121. package/dist/types.d.ts +72 -0
  122. package/package.json +3 -3
@@ -0,0 +1,55 @@
1
+ import * as React from 'react';
2
+ import type { PlassElevation, PlassStyleProps, PlassVariant } from '../../types.js';
3
+ export interface PlToggleProps extends PlassStyleProps, Omit<React.ComponentPropsWithoutRef<'button'>, 'color' | 'value'> {
4
+ /**
5
+ * What the key is made of while it is **off**. On is always the colour family
6
+ * asserting itself, whichever material was asked for.
7
+ *
8
+ * - `solid` — the densest clear glass, which fills with the family's gradient
9
+ * when it goes on. The loudest, for a toggle a screen is steered by.
10
+ * - `glass` — the canonical sheet with a hairline round it. The default.
11
+ * - `ghost` — nothing at all until the pointer arrives or it goes on. What a
12
+ * toolbar wants.
13
+ * @default 'glass'
14
+ */
15
+ variant?: PlassVariant;
16
+ /** Whether it is on. Use with `onPressedChange` for a controlled toggle. */
17
+ pressed?: boolean;
18
+ /** Whether it starts on, for an uncontrolled one. @default false */
19
+ defaultPressed?: boolean;
20
+ onPressedChange?: (pressed: boolean) => void;
21
+ /** Identifies the toggle inside a `PlToggleGroup`. */
22
+ value?: string;
23
+ /**
24
+ * Drop shadow depth. `0` — the default, and one below a `PlButton`'s — is
25
+ * flat: a toggle is a state rather than an action, and a state does not float
26
+ * off the page waiting to be taken.
27
+ * @default 0
28
+ */
29
+ elevation?: PlassElevation;
30
+ /** Content placed before the label. Sized in `em`, so it tracks the label. */
31
+ startIcon?: React.ReactNode;
32
+ /** Content placed after the label. */
33
+ endIcon?: React.ReactNode;
34
+ /** Stretches to the width of the container. */
35
+ fullWidth?: boolean;
36
+ /**
37
+ * The label. Left out, the toggle goes square around whatever icon it was
38
+ * given — which is what a toolbar toggle is. An icon-only toggle still needs
39
+ * an `aria-label`.
40
+ */
41
+ children?: React.ReactNode;
42
+ }
43
+ /**
44
+ * A button that stays down.
45
+ *
46
+ * The difference from a `PlSwitch` is what the press *is*: a switch changes a
47
+ * setting and the change is the point; a toggle changes the state of the thing
48
+ * beside it — bold on the selected words, the grid on the canvas, the filter on
49
+ * the list. The difference from a `PlCheckbox` is that this one is a control
50
+ * rather than an answer, so it never goes in a form.
51
+ *
52
+ * Base UI's Toggle owns `aria-pressed` and the controlled/uncontrolled pair.
53
+ * What is left here is the surface, and the rule that off is neutral.
54
+ */
55
+ export declare const PlToggle: React.ForwardRefExoticComponent<PlToggleProps & React.RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1 @@
1
+ "use client";import{jsxs as s}from"react/jsx-runtime";import*as e from"react";import{Toggle as o}from"@base-ui/react/toggle";import{ButtonGroupContext as a}from"../../internal/button-group.js";import{controlHeightClasses as l,controlSlots as r,controlSquareClasses as t,controlTextClasses as p,disabledClasses as i,focusRingClasses as n,gapClasses as v,glassClasses as g,hasContent as d,iconClasses as h,paddingXClasses as x,radiusClasses as c,transitionClasses as f}from"../../internal/styles.js";const b={xs:`${l.xs} ${v.xs} ${c.xs} ${p.xs}`,sm:`${l.sm} ${v.sm} ${c.sm} ${p.sm}`,md:`${l.md} ${v.md} ${c.md} ${p.md}`,lg:`${l.lg} ${v.lg} ${c.lg} ${p.lg}`,xl:`${l.xl} ${v.xl} ${c.xl} ${p.xl}`},m={xs:`${t.xs} px-0`,sm:`${t.sm} px-0`,md:`${t.md} px-0`,lg:`${t.lg} px-0`,xl:`${t.xl} px-0`},$=/* @__PURE__ */["relative inline-flex shrink-0 select-none items-center justify-center","whitespace-nowrap align-middle font-semibold leading-none","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",f,n,h].join(" "),u={solid:/* @__PURE__ */[g,"text-(--plass-muted-fg) bg-(--plass-glass-hover)","[box-shadow:var(--p-elev),var(--plass-gloss-glass)]"].join(" "),glass:/* @__PURE__ */[g,"border text-(--plass-muted-fg) bg-(--plass-glass)","[border-color:var(--plass-glass-line)]","[box-shadow:var(--p-elev),var(--plass-gloss-glass)]"].join(" "),ghost:"text-(--plass-muted-fg) bg-transparent"},w={solid:/* @__PURE__ */["hover:bg-(--plass-glass-press) hover:text-(--plass-fg)","hover:[box-shadow:var(--p-elev-hover),var(--plass-gloss-glass)]","active:[box-shadow:var(--p-elev-press),var(--plass-gloss-glass)]"].join(" "),glass:/* @__PURE__ */["hover:bg-(--plass-glass-hover) hover:text-(--plass-fg) hover:[border-color:var(--p-line)]","hover:[box-shadow:var(--p-elev-hover),var(--plass-gloss-glass)]","active:bg-(--plass-glass-press)","active:[box-shadow:var(--p-elev-press),var(--plass-gloss-glass)]"].join(" "),ghost:"hover:bg-(--p-soft) hover:text-(--plass-fg) active:bg-(--p-soft-hover)"},j={solid:/* @__PURE__ */["text-(--p-on-solid) [background-image:var(--p-fill)]","[box-shadow:var(--p-elev),var(--p-lift)]"].join(" "),glass:/* @__PURE__ */[g,"border text-(--p-accent) bg-(--p-soft)","[border-color:var(--p-line-hover)]","[box-shadow:var(--p-elev),var(--plass-gloss-glass)]"].join(" "),ghost:"text-(--p-accent) bg-(--p-soft)"},y={solid:/* @__PURE__ */["hover:brightness-105 hover:[box-shadow:var(--p-elev-hover),var(--p-lift-hover)]","active:brightness-95 active:[box-shadow:var(--p-elev-press),var(--p-lift-press)]"].join(" "),glass:"hover:bg-(--p-soft-hover) active:bg-(--p-soft-press)",ghost:"hover:bg-(--p-soft-hover) active:bg-(--p-soft-press)"};export const PlToggle=/* @__PURE__ */e.forwardRef(function PlToggle({variant:l,size:t,color:p,density:n,elevation:v,pressed:g,defaultPressed:h,onPressedChange:c,value:f,startIcon:P,endIcon:T,fullWidth:k=!1,disabled:C,className:z,style:E,children:I,onPointerMove:M,...N},B){const R=e.useContext(a),W=l??R?.variant??"glass",X=t??R?.size??"md",Y=p??R?.color??"primary",q=n??R?.density??"default",A=v??R?.elevation??0,D=C??R?.disabled??!1,F=!d(I);return s(o,{ref:B,value:f,pressed:g,defaultPressed:h,onPressedChange:s=>c?.(s),disabled:D,className:s=>[$,b[X],F?m[X]:x[q][X],D?i[W]:s.pressed?`${j[W]} ${y[W]}`:`${u[W]} ${w[W]}`,D?"":"plass-glow cursor-pointer",k?"w-full":"",z??""].filter(Boolean).join(" "),style:{...r(Y,A,W),...E},onPointerMove:s=>{const e=s.currentTarget;e.style.setProperty("--p-mx",`${s.nativeEvent.offsetX}px`),e.style.setProperty("--p-my",`${s.nativeEvent.offsetY}px`),M?.(s)},...N,children:[P,I,T]})});
@@ -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,4 @@
1
+ export { PlToggle } from './PlToggle.js';
2
+ export type { PlToggleProps } from './PlToggle.js';
3
+ export { PlToggleGroup } from './PlToggleGroup.js';
4
+ export type { PlToggleGroupProps } from './PlToggleGroup.js';
@@ -0,0 +1 @@
1
+ export{PlToggle}from"./PlToggle.js";export{PlToggleGroup}from"./PlToggleGroup.js";
@@ -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,2 @@
1
+ export { PlTransfer } from './PlTransfer.js';
2
+ export type { PlTransferProps, PlTransferItem } from './PlTransfer.js';
@@ -0,0 +1 @@
1
+ export{PlTransfer}from"./PlTransfer.js";
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <avatar-group>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/avatar-group';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <color-picker>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/color-picker';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <command-palette>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/command-palette';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <fieldset>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/fieldset';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <footer>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/footer';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <form>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/form';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <header>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/header';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <menubar>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/menubar';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <navigation-menu>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/navigation-menu';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <page-layout>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/page-layout';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <sidebar>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/sidebar';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <toggle>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/toggle';
@@ -0,0 +1,2 @@
1
+ /* Scan manifest for <transfer>. Needs `plass-ui/css/base.css` first. */
2
+ @source '../components/transfer';
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,2 @@
1
+ import*as t from"react";export const AvatarGroupContext=
2
+ /* @__PURE__ */t.createContext(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(" ")}