plass-ui 1.0.0 → 1.0.2

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 (165) hide show
  1. package/README.md +165 -0
  2. package/dist/components/accordion/PlAccordion.js +1 -131
  3. package/dist/components/accordion/index.js +1 -1
  4. package/dist/components/alert/PlAlert.js +1 -109
  5. package/dist/components/alert/index.js +1 -1
  6. package/dist/components/animate-appear/PlAnimateAppear.js +1 -71
  7. package/dist/components/animate-appear/index.js +1 -1
  8. package/dist/components/animate-blink/PlAnimateBlink.js +1 -47
  9. package/dist/components/animate-blink/index.js +1 -1
  10. package/dist/components/animate-fade/PlAnimateFade.js +1 -48
  11. package/dist/components/animate-fade/index.js +1 -1
  12. package/dist/components/animate-grow/PlAnimateGrow.js +1 -49
  13. package/dist/components/animate-grow/index.js +1 -1
  14. package/dist/components/animate-headline/PlAnimateHeadline.js +1 -120
  15. package/dist/components/animate-headline/index.js +1 -1
  16. package/dist/components/animate-lighting/PlAnimateLighting.js +1 -65
  17. package/dist/components/animate-lighting/index.js +1 -1
  18. package/dist/components/animate-marquee/PlAnimateMarquee.js +1 -94
  19. package/dist/components/animate-marquee/index.js +1 -1
  20. package/dist/components/animate-rotate/PlAnimateRotate.js +1 -50
  21. package/dist/components/animate-rotate/index.js +1 -1
  22. package/dist/components/animate-slide/PlAnimateSlide.js +1 -49
  23. package/dist/components/animate-slide/index.js +1 -1
  24. package/dist/components/animate-typing/PlAnimateTyping.js +1 -177
  25. package/dist/components/animate-typing/index.js +1 -1
  26. package/dist/components/animate-zoom/PlAnimateZoom.js +1 -45
  27. package/dist/components/animate-zoom/index.js +1 -1
  28. package/dist/components/aspect-ratio/PlAspectRatio.js +1 -58
  29. package/dist/components/aspect-ratio/index.js +1 -1
  30. package/dist/components/avatar/PlAvatar.js +1 -121
  31. package/dist/components/avatar/index.js +1 -1
  32. package/dist/components/badge/PlBadge.js +1 -168
  33. package/dist/components/badge/index.js +1 -1
  34. package/dist/components/blockquote/PlBlockquote.js +1 -112
  35. package/dist/components/blockquote/index.js +1 -1
  36. package/dist/components/bottom-navigation/PlBottomNavigation.js +1 -141
  37. package/dist/components/bottom-navigation/index.js +1 -1
  38. package/dist/components/box/PlBox.js +1 -46
  39. package/dist/components/box/index.js +1 -1
  40. package/dist/components/breadcrumb/PlBreadcrumb.js +1 -201
  41. package/dist/components/breadcrumb/index.js +1 -1
  42. package/dist/components/button/PlButton.js +1 -196
  43. package/dist/components/button/index.js +1 -1
  44. package/dist/components/button-group/PlButtonGroup.js +1 -64
  45. package/dist/components/button-group/index.js +1 -1
  46. package/dist/components/card/PlCard.js +1 -102
  47. package/dist/components/card/index.js +1 -1
  48. package/dist/components/carousel/PlCarousel.js +1 -177
  49. package/dist/components/carousel/index.js +1 -1
  50. package/dist/components/chat-bubble/PlChatBubble.js +1 -206
  51. package/dist/components/chat-bubble/index.js +1 -1
  52. package/dist/components/checkbox/PlCheckbox.js +1 -100
  53. package/dist/components/checkbox/index.js +1 -1
  54. package/dist/components/chip/PlChip.js +1 -144
  55. package/dist/components/chip/index.js +1 -1
  56. package/dist/components/collapsible/PlCollapsible.js +1 -65
  57. package/dist/components/collapsible/index.js +1 -1
  58. package/dist/components/combobox/PlCombobox.js +1 -199
  59. package/dist/components/combobox/index.js +1 -1
  60. package/dist/components/container/PlContainer.js +1 -47
  61. package/dist/components/container/index.js +1 -1
  62. package/dist/components/date-picker/PlDatePicker.js +1 -87
  63. package/dist/components/date-picker/index.js +1 -1
  64. package/dist/components/date-range-picker/PlDateRangePicker.js +1 -152
  65. package/dist/components/date-range-picker/index.js +1 -1
  66. package/dist/components/date-time-picker/PlDateTimePicker.js +1 -106
  67. package/dist/components/date-time-picker/index.js +1 -1
  68. package/dist/components/divider/PlDivider.js +1 -107
  69. package/dist/components/divider/index.js +1 -1
  70. package/dist/components/drawer/PlDrawer.js +1 -190
  71. package/dist/components/drawer/index.js +1 -1
  72. package/dist/components/file-picker/PlFilePicker.js +1 -274
  73. package/dist/components/file-picker/index.js +1 -1
  74. package/dist/components/floating-bottom-navigation/PlFloatingBottomNavigation.js +1 -291
  75. package/dist/components/floating-bottom-navigation/index.js +1 -1
  76. package/dist/components/grid/PlGrid.js +1 -51
  77. package/dist/components/grid/PlGridItem.js +1 -34
  78. package/dist/components/grid/index.js +1 -2
  79. package/dist/components/highlight/PlHighlight.js +1 -185
  80. package/dist/components/highlight/index.js +1 -1
  81. package/dist/components/hot-keys/PlHotKeys.js +1 -294
  82. package/dist/components/hot-keys/index.js +1 -1
  83. package/dist/components/icon/PlIcon.js +1 -58
  84. package/dist/components/icon/index.js +1 -1
  85. package/dist/components/icon-button/PlIconButton.js +1 -37
  86. package/dist/components/icon-button/index.js +1 -1
  87. package/dist/components/list/PlList.js +1 -160
  88. package/dist/components/list/index.js +1 -1
  89. package/dist/components/menu/PlMenu.js +1 -209
  90. package/dist/components/menu/index.js +1 -1
  91. package/dist/components/modal/PlModal.js +1 -150
  92. package/dist/components/modal/index.js +1 -1
  93. package/dist/components/number-field/PlNumberField.js +1 -111
  94. package/dist/components/number-field/index.js +1 -1
  95. package/dist/components/otp-field/PlOtpField.js +1 -109
  96. package/dist/components/otp-field/index.js +1 -1
  97. package/dist/components/overlay/PlOverlay.js +1 -77
  98. package/dist/components/overlay/index.js +1 -1
  99. package/dist/components/pagination/PlPagination.js +1 -159
  100. package/dist/components/pagination/index.js +1 -1
  101. package/dist/components/panes/PlPanes.js +1 -324
  102. package/dist/components/panes/index.js +1 -1
  103. package/dist/components/pill/PlPill.js +1 -154
  104. package/dist/components/pill/index.js +1 -1
  105. package/dist/components/popover/PlPopover.js +1 -113
  106. package/dist/components/popover/index.js +1 -1
  107. package/dist/components/progress-box/PlProgressBox.js +1 -34
  108. package/dist/components/progress-box/index.js +1 -1
  109. package/dist/components/progress-circular/PlProgressCircular.js +1 -47
  110. package/dist/components/progress-circular/index.js +1 -1
  111. package/dist/components/progress-linear/PlProgressLinear.js +1 -40
  112. package/dist/components/progress-linear/index.js +1 -1
  113. package/dist/components/radio-group/PlRadioGroup.js +1 -99
  114. package/dist/components/radio-group/index.js +1 -1
  115. package/dist/components/rating/PlRating.js +1 -101
  116. package/dist/components/rating/index.js +1 -1
  117. package/dist/components/scroll-zone/PlScrollZone.js +1 -411
  118. package/dist/components/scroll-zone/index.js +1 -1
  119. package/dist/components/segmented-button/PlSegmentedButton.js +1 -206
  120. package/dist/components/segmented-button/index.js +1 -1
  121. package/dist/components/select/PlSelect.js +1 -115
  122. package/dist/components/select/index.js +1 -1
  123. package/dist/components/skeleton/PlSkeleton.js +1 -142
  124. package/dist/components/skeleton/index.js +1 -1
  125. package/dist/components/slider/PlSlider.js +1 -132
  126. package/dist/components/slider/index.js +1 -1
  127. package/dist/components/spoiler/PlSpoiler.js +1 -74
  128. package/dist/components/spoiler/index.js +1 -1
  129. package/dist/components/switch/PlSwitch.js +1 -131
  130. package/dist/components/switch/index.js +1 -1
  131. package/dist/components/table/PlTable.js +1 -210
  132. package/dist/components/table/index.js +1 -1
  133. package/dist/components/tabs/PlTabs.js +1 -182
  134. package/dist/components/tabs/index.js +1 -1
  135. package/dist/components/text-field/PlTextField.js +1 -126
  136. package/dist/components/text-field/index.js +1 -1
  137. package/dist/components/text-link/PlTextLink.js +1 -136
  138. package/dist/components/text-link/index.js +1 -1
  139. package/dist/components/time-picker/PlTimePicker.js +1 -97
  140. package/dist/components/time-picker/index.js +1 -1
  141. package/dist/components/timeline/PlTimeline.js +1 -207
  142. package/dist/components/timeline/index.js +1 -1
  143. package/dist/components/toast/PlToast.js +1 -174
  144. package/dist/components/toast/index.js +1 -1
  145. package/dist/components/toolbar/PlToolbar.js +1 -65
  146. package/dist/components/toolbar/index.js +1 -1
  147. package/dist/components/tooltip/PlTooltip.js +1 -117
  148. package/dist/components/tooltip/index.js +1 -1
  149. package/dist/components/typography/PlTypography.js +1 -143
  150. package/dist/components/typography/index.js +1 -1
  151. package/dist/index.js +1 -75
  152. package/dist/internal/animate.js +1 -318
  153. package/dist/internal/button-group.js +2 -19
  154. package/dist/internal/calendar.js +1 -501
  155. package/dist/internal/date.js +1 -353
  156. package/dist/internal/format.js +1 -41
  157. package/dist/internal/grid.js +1 -143
  158. package/dist/internal/icons.js +1 -138
  159. package/dist/internal/menu.js +1 -18
  160. package/dist/internal/picker.js +1 -139
  161. package/dist/internal/progress.js +1 -167
  162. package/dist/internal/sizer.js +1 -35
  163. package/dist/internal/styles.js +1 -636
  164. package/dist/types.js +0 -8
  165. package/package.json +5 -3
@@ -1,34 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { Progress } from '@base-ui/react/progress';
4
- import { fillTransitionClasses, plateGapClasses, plateRadiusClasses, plateSizeClasses, progressAriaText, progressFraction, progressSlots, progressText, trackClasses } from '../../internal/progress.js';
5
- import { cx, metaTextClasses, stackGapClasses } from '../../internal/styles.js';
6
- /**
7
- * A row of small glass plates that light up.
8
- *
9
- * The third shape, and the one that is about the material rather than about the
10
- * quantity. A bar and a ring both say "this much of it is done"; a row of
11
- * plates says "this is working" in the library's own vocabulary — the same
12
- * groove, the same corner, the same gradient — which is what makes it the right
13
- * one for a loading state inside a Plass surface, where a foreign grey spinner
14
- * would look borrowed.
15
- *
16
- * It answers a value when it has one: the plates fill in order, the leading one
17
- * partially, so four plates read as a four-segment bar rather than as four
18
- * quarters. Without a value they cycle, each held back by its own index — and
19
- * what cycles is the fill's **opacity**, because a gradient has no interpolation
20
- * between itself and nothing.
21
- */
22
- export const PlProgressBox = /* @__PURE__ */ React.forwardRef(function PlProgressBox({ size = 'md', color = 'primary', count = 4, value = null, min = 0, max = 100, label, showValue = false, format, className, style, ...props }, ref) {
23
- const fraction = progressFraction(value, min, max);
24
- const indeterminate = fraction === null;
25
- const hasFormat = format !== undefined;
26
- // A row of no plates is not a loading indicator, and a fractional count is a
27
- // caller who divided something. Both land on one plate rather than on none.
28
- const plates = Math.max(1, Math.floor(count));
29
- return (_jsxs(Progress.Root, { ref: ref, value: value ?? null, min: min, max: max, format: format, getAriaValueText: progressAriaText(fraction, hasFormat), className: cx('inline-flex flex-col', stackGapClasses[size], className), style: { ...progressSlots(color), ...style }, ...props, children: [label || showValue ? (_jsxs("div", { className: cx('flex items-baseline gap-2', label ? 'justify-between' : 'justify-end', metaTextClasses[size]), children: [label ? (_jsx(Progress.Label, { className: "min-w-0 truncate text-(--plass-fg)", children: label })) : null, showValue ? (_jsx(Progress.Value, { className: "shrink-0 tabular-nums text-(--plass-muted-fg)", children: (formatted) => progressText(fraction, formatted, hasFormat) })) : null] })) : null, _jsx(Progress.Track, { className: cx('flex', plateGapClasses[size]), children: Array.from({ length: plates }, (_, index) => (_jsx("span", { className: cx('relative overflow-hidden', trackClasses, plateSizeClasses[size], plateRadiusClasses[size]), children: _jsx("span", { "aria-hidden": "true", className: cx('absolute inset-y-0 start-0 [background-image:var(--p-fill)]', indeterminate ? 'plass-plate-wave w-full' : fillTransitionClasses), style: indeterminate
30
- ? { '--p-i': index }
31
- : {
32
- width: `${Math.min(100, Math.max(0, (fraction * plates - index) * 100))}%`
33
- } }) }, index))) })] }));
34
- });
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as l from"react";import{Progress as s}from"@base-ui/react/progress";import{fillTransitionClasses as r,plateGapClasses as t,plateRadiusClasses as n,plateSizeClasses as i,progressAriaText as o,progressFraction as m,progressSlots as c,progressText as u,trackClasses as f}from"../../internal/progress.js";import{cx as d,metaTextClasses as p,stackGapClasses as x}from"../../internal/styles.js";export const PlProgressBox=/* @__PURE__ */l.forwardRef(function PlProgressBox({size:l="md",color:h="primary",count:g=4,value:y=null,min:b=0,max:v=100,label:w,showValue:N=!1,format:j,className:M,style:P,...k},V){const A=m(y,b,v),B=null===A,R=void 0!==j,T=Math.max(1,Math.floor(g));return a(s.Root,{ref:V,value:y??null,min:b,max:v,format:j,getAriaValueText:o(A,R),className:d("inline-flex flex-col",x[l],M),style:{...c(h),...P},...k,children:[w||N?a("div",{className:d("flex items-baseline gap-2",w?"justify-between":"justify-end",p[l]),children:[w?e(s.Label,{className:"min-w-0 truncate text-(--plass-fg)",children:w}):null,N?e(s.Value,{className:"shrink-0 tabular-nums text-(--plass-muted-fg)",children:e=>u(A,e,R)}):null]}):null,e(s.Track,{className:d("flex",t[l]),children:Array.from({length:T},(a,s)=>e("span",{className:d("relative overflow-hidden",f,i[l],n[l]),children:e("span",{"aria-hidden":"true",className:d("absolute inset-y-0 start-0 [background-image:var(--p-fill)]",B?"plass-plate-wave w-full":r),style:B?{"--p-i":s}:{width:`${Math.min(100,Math.max(0,100*(A*T-s)))}%`}})},s))})]})});
@@ -1 +1 @@
1
- export { PlProgressBox } from './PlProgressBox.js';
1
+ export{PlProgressBox}from"./PlProgressBox.js";
@@ -1,47 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { Progress } from '@base-ui/react/progress';
4
- import { progressAriaText, progressFraction, progressSlots, progressText, ringDiameters, ringStrokes } from '../../internal/progress.js';
5
- import { cx, gapClasses, metaTextClasses } from '../../internal/styles.js';
6
- /**
7
- * A ring that fills, and the one to reach for where there is no room for a bar
8
- * — inside a button, at the end of a table row, next to a field.
9
- *
10
- * The arc is the family's gradient rather than a flat colour, which takes a
11
- * `<linearGradient>` of its own: an SVG stroke cannot be given a CSS gradient,
12
- * so the two ends of the fill are lifted out of the slots and rebuilt at 135°.
13
- * It is worth the extra element — a flat ring beside a swept bar is two
14
- * materials for one idea.
15
- *
16
- * The value and the label sit *beside* the ring rather than inside it. A number
17
- * in the middle of a dial is the picture everyone has of this component, and it
18
- * only works at two of the five sizes: at `xs` the ring is fourteen pixels
19
- * across and there is nowhere for "40%" to go. Beside it, every size reads.
20
- */
21
- export const PlProgressCircular = /* @__PURE__ */ React.forwardRef(function PlProgressCircular({ size = 'md', color = 'primary', value = null, min = 0, max = 100, label, showValue = false, format, className, style, ...props }, ref) {
22
- const fraction = progressFraction(value, min, max);
23
- const indeterminate = fraction === null;
24
- const hasFormat = format !== undefined;
25
- const gradientId = `${React.useId()}-fill`;
26
- const diameter = ringDiameters[size];
27
- const stroke = ringStrokes[size];
28
- const centre = diameter / 2;
29
- // The stroke straddles the path, so the radius has to come in by half of it
30
- // or the ring is clipped by its own viewBox.
31
- const radius = centre - stroke / 2;
32
- const circumference = 2 * Math.PI * radius;
33
- // Indeterminate draws a fixed quarter-arc and turns; determinate holds still
34
- // and lets the gap close. Both are one dash pattern on one circle.
35
- const dashArray = indeterminate ? `${circumference * 0.28} ${circumference}` : `${circumference}`;
36
- const dashOffset = indeterminate ? 0 : circumference * (1 - fraction);
37
- return (_jsxs(Progress.Root, { ref: ref, value: value ?? null, min: min, max: max, format: format, getAriaValueText: progressAriaText(fraction, hasFormat), className: cx('inline-flex items-center', gapClasses[size], metaTextClasses[size], className), style: { ...progressSlots(color), ...style }, ...props, children: [_jsxs("svg", {
38
- // The rotation is on the whole `<svg>` and not on a group inside it:
39
- // `transform-origin: center` resolves against an element's border box,
40
- // which an SVG child does not have one of unless `transform-box` is set
41
- // as well. One element, one rule, no surprises across browsers.
42
- className: cx('shrink-0', indeterminate && 'plass-ring-spin'), width: diameter, height: diameter, viewBox: `0 0 ${diameter} ${diameter}`, fill: "none", "aria-hidden": "true", children: [_jsx("defs", { children: _jsxs("linearGradient", { id: gradientId, x1: "0", y1: "0", x2: "1", y2: "1", children: [_jsx("stop", { offset: "0%", stopColor: "var(--p-solid)" }), _jsx("stop", { offset: "100%", stopColor: "var(--p-solid-to)" })] }) }), _jsx("circle", { cx: centre, cy: centre, r: radius, stroke: "var(--plass-track)", strokeWidth: stroke }), _jsx("circle", { cx: centre, cy: centre, r: radius, stroke: `url(#${gradientId})`, strokeWidth: stroke, strokeLinecap: "round", strokeDasharray: dashArray, strokeDashoffset: dashOffset,
43
- // An SVG geometry attribute rather than a CSS transform: this is where
44
- // the arc starts, not something the ring does when its state changes.
45
- // Without it a determinate ring would fill from three o'clock.
46
- transform: `rotate(-90 ${centre} ${centre})`, className: "[transition:stroke-dashoffset_var(--plass-duration-slow)_var(--plass-ease)]" })] }), label ? (_jsx(Progress.Label, { className: "min-w-0 truncate text-(--plass-fg)", children: label })) : null, showValue ? (_jsx(Progress.Value, { className: "shrink-0 tabular-nums text-(--plass-muted-fg)", children: (formatted) => progressText(fraction, formatted, hasFormat) })) : null] }));
47
- });
1
+ "use client";import{jsx as r,jsxs as s}from"react/jsx-runtime";import*as e from"react";import{Progress as a}from"@base-ui/react/progress";import{progressAriaText as t,progressFraction as l,progressSlots as o,progressText as i,ringDiameters as n,ringStrokes as c}from"../../internal/progress.js";import{cx as m,gapClasses as f,metaTextClasses as u}from"../../internal/styles.js";export const PlProgressCircular=/* @__PURE__ */e.forwardRef(function PlProgressCircular({size:d="md",color:p="primary",value:h=null,min:x=0,max:k=100,label:g,showValue:v=!1,format:y,className:$,style:w,...N},j){const P=l(h,x,k),b=null===P,C=void 0!==y,V=`${e.useId()}-fill`,D=n[d],I=c[d],L=D/2,R=L-I/2,W=2*Math.PI*R,_=b?`${.28*W} ${W}`:`${W}`,z=b?0:W*(1-P);return s(a.Root,{ref:j,value:h??null,min:x,max:k,format:y,getAriaValueText:t(P,C),className:m("inline-flex items-center",f[d],u[d],$),style:{...o(p),...w},...N,children:[s("svg",{className:m("shrink-0",b&&"plass-ring-spin"),width:D,height:D,viewBox:`0 0 ${D} ${D}`,fill:"none","aria-hidden":"true",children:[r("defs",{children:s("linearGradient",{id:V,x1:"0",y1:"0",x2:"1",y2:"1",children:[r("stop",{offset:"0%",stopColor:"var(--p-solid)"}),r("stop",{offset:"100%",stopColor:"var(--p-solid-to)"})]})}),r("circle",{cx:L,cy:L,r:R,stroke:"var(--plass-track)",strokeWidth:I}),r("circle",{cx:L,cy:L,r:R,stroke:`url(#${V})`,strokeWidth:I,strokeLinecap:"round",strokeDasharray:_,strokeDashoffset:z,transform:`rotate(-90 ${L} ${L})`,className:"[transition:stroke-dashoffset_var(--plass-duration-slow)_var(--plass-ease)]"})]}),g?r(a.Label,{className:"min-w-0 truncate text-(--plass-fg)",children:g}):null,v?r(a.Value,{className:"shrink-0 tabular-nums text-(--plass-muted-fg)",children:r=>i(P,r,C)}):null]})});
@@ -1 +1 @@
1
- export { PlProgressCircular } from './PlProgressCircular.js';
1
+ export{PlProgressCircular}from"./PlProgressCircular.js";
@@ -1,40 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { Progress } from '@base-ui/react/progress';
4
- import { barThicknessClasses, fillTransitionClasses, progressAriaText, progressFraction, progressSlots, progressText, trackClasses } from '../../internal/progress.js';
5
- import { cx, metaTextClasses, stackGapClasses } from '../../internal/styles.js';
6
- /**
7
- * A bar that fills.
8
- *
9
- * The workhorse of the three: it is the only one that can show *how much* is
10
- * left at a glance, because length is the one quantity a reader can compare
11
- * without counting.
12
- *
13
- * The groove is `--plass-track`, the same neutral ink a PlSlider's rail and a
14
- * PlSwitch's off state are cut in, and the segment over it is the family's
15
- * gradient — so the filled part of the run is made of exactly the same material
16
- * as the button that submits the form it is in. Which is also why the movement
17
- * is on `width`: a gradient cannot be transitioned, and a length can.
18
- *
19
- * Both the groove and the segment are fully rounded, and that is the one place
20
- * the library's rule about pills does not apply. The rule protects the flat run
21
- * along a control's edge that a line of text sits on; at six pixels tall there
22
- * is no flat run left to protect, and a square-ended bar reads as a rendering
23
- * fault rather than as a cut edge.
24
- *
25
- * Base UI owns the semantics — `role="progressbar"`, the value and range
26
- * attributes, `aria-valuetext`, and dropping the value entirely when the bar is
27
- * indeterminate — and it computes the fill width too, so the determinate case
28
- * here is a class list and nothing else.
29
- */
30
- export const PlProgressLinear = /* @__PURE__ */ React.forwardRef(function PlProgressLinear({ size = 'md', color = 'primary', value = null, min = 0, max = 100, label, showValue = false, format, className, style, ...props }, ref) {
31
- const fraction = progressFraction(value, min, max);
32
- const indeterminate = fraction === null;
33
- const hasFormat = format !== undefined;
34
- return (_jsxs(Progress.Root, { ref: ref, value: value ?? null, min: min, max: max, format: format, getAriaValueText: progressAriaText(fraction, hasFormat), className: cx('flex w-full flex-col', stackGapClasses[size], className), style: { ...progressSlots(color), ...style }, ...props, children: [label || showValue ? (_jsxs("div", { className: cx('flex items-baseline gap-2', label ? 'justify-between' : 'justify-end', metaTextClasses[size]), children: [label ? (_jsx(Progress.Label, { className: "min-w-0 truncate text-(--plass-fg)", children: label })) : null, showValue ? (_jsx(Progress.Value, { className: "shrink-0 tabular-nums text-(--plass-muted-fg)", children: (formatted) => progressText(fraction, formatted, hasFormat) })) : null] })) : null, _jsx(Progress.Track, { className: cx('relative w-full overflow-hidden rounded-full', trackClasses, barThicknessClasses[size]), children: _jsx(Progress.Indicator, { className: cx('rounded-full [background-image:var(--p-fill)]',
35
- // `plass-progress-sweep` supplies the position, the width and the
36
- // animation; with a value Base UI supplies the width instead and
37
- // this transition is what makes it travel rather than jump. Both
38
- // change an inline size, never a transform.
39
- indeterminate ? 'plass-progress-sweep' : `absolute top-0 ${fillTransitionClasses}`) }) })] }));
40
- });
1
+ "use client";import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as s from"react";import{Progress as r}from"@base-ui/react/progress";import{barThicknessClasses as a,fillTransitionClasses as t,progressAriaText as n,progressFraction as o,progressSlots as i,progressText as m,trackClasses as u}from"../../internal/progress.js";import{cx as c,metaTextClasses as f,stackGapClasses as d}from"../../internal/styles.js";export const PlProgressLinear=/* @__PURE__ */s.forwardRef(function PlProgressLinear({size:s="md",color:p="primary",value:x=null,min:g=0,max:b=100,label:h,showValue:w=!1,format:j,className:v,style:N,...y},P){const k=o(x,g,b),L=null===k,V=void 0!==j;return l(r.Root,{ref:P,value:x??null,min:g,max:b,format:j,getAriaValueText:n(k,V),className:c("flex w-full flex-col",d[s],v),style:{...i(p),...N},...y,children:[h||w?l("div",{className:c("flex items-baseline gap-2",h?"justify-between":"justify-end",f[s]),children:[h?e(r.Label,{className:"min-w-0 truncate text-(--plass-fg)",children:h}):null,w?e(r.Value,{className:"shrink-0 tabular-nums text-(--plass-muted-fg)",children:e=>m(k,e,V)}):null]}):null,e(r.Track,{className:c("relative w-full overflow-hidden rounded-full",u,a[s]),children:e(r.Indicator,{className:c("rounded-full [background-image:var(--p-fill)]",L?"plass-progress-sweep":`absolute top-0 ${t}`)})})]})});
@@ -1 +1 @@
1
- export { PlProgressLinear } from './PlProgressLinear.js';
1
+ export{PlProgressLinear}from"./PlProgressLinear.js";
@@ -1,99 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { Radio as BaseUIRadio } from '@base-ui/react/radio';
4
- import { RadioGroup as BaseUIRadioGroup } from '@base-ui/react/radio-group';
5
- import { Field } from '@base-ui/react/field';
6
- import { controlSlots, focusRingClasses, glassClasses, hasContent, metaTextClasses, tickDotClasses, tickRowTextClasses, tickSizeClasses, transitionClasses } from '../../internal/styles.js';
7
- const RadioGroupContext = /* @__PURE__ */ React.createContext({
8
- size: 'md',
9
- color: 'primary',
10
- readOnly: false
11
- });
12
- /**
13
- * The dot. Round, and one of the two things in the library allowed to be —
14
- * roundness is exactly what tells a reader "one of these" rather than "any of
15
- * these", and it is the one convention old enough that breaking it would cost
16
- * more than it bought.
17
- */
18
- const dotBaseClasses = /* @__PURE__ */ [
19
- 'relative inline-flex shrink-0 items-center justify-center rounded-full border',
20
- '[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]',
21
- transitionClasses,
22
- focusRingClasses
23
- ].join(' ');
24
- /**
25
- * No gloss line and no tinted lift, for the reason a PlCheckbox's tick has
26
- * neither: a 1px white edge is light on a cut edge at 40px and a grey smudge at
27
- * 18px, and a `0 6px 16px` shadow under an 18px circle is bigger than the
28
- * circle. The glass stays; only the two decorations go.
29
- *
30
- * The edge is `--plass-border` rather than the sheet's own `--plass-glass-line`,
31
- * and that is not a slip. The glass hairline is white light on a translucent
32
- * pane, which is invisible the moment the tick is set on a light card rather
33
- * than on the page wash — and a tick nobody can see is a control nobody can
34
- * find. A neutral hairline reads on both.
35
- */
36
- const restDotClasses = /* @__PURE__ */ [
37
- glassClasses,
38
- 'cursor-pointer bg-(--plass-glass) [border-color:var(--plass-border)]',
39
- 'hover:bg-(--plass-glass-hover) hover:[border-color:var(--p-line)]',
40
- 'data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)',
41
- 'data-[checked]:[border-color:transparent] data-[checked]:hover:brightness-105'
42
- ].join(' ');
43
- const readOnlyDotClasses = /* @__PURE__ */ [
44
- glassClasses,
45
- 'cursor-default bg-(--plass-glass) [border-color:var(--plass-border)]',
46
- 'saturate-[0.55]',
47
- 'data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)',
48
- 'data-[checked]:[border-color:transparent]'
49
- ].join(' ');
50
- const disabledDotClasses = /* @__PURE__ */ [
51
- glassClasses,
52
- 'cursor-not-allowed bg-(--plass-glass) [border-color:var(--plass-border)]',
53
- 'opacity-50 saturate-[0.35]',
54
- 'data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)',
55
- 'data-[checked]:[border-color:transparent]'
56
- ].join(' ');
57
- /** The inner dot: `currentColor`, so it inherits the on-fill ink. */
58
- const indicatorClasses = 'rounded-full bg-current';
59
- /**
60
- * One option in a `PlRadioGroup`.
61
- *
62
- * It has no `size` and no `color` of its own — both come from the group, which
63
- * is the only place they can be set once and mean the same thing for every
64
- * option in the set.
65
- */
66
- export const PlRadio = /* @__PURE__ */ React.forwardRef(function PlRadio({ label, description, disabled = false, className, style, ...props }, ref) {
67
- const group = React.useContext(RadioGroupContext);
68
- const readOnly = props.readOnly ?? group.readOnly;
69
- return (_jsx(Field.Root, { disabled: disabled, className: ['flex flex-col', className ?? ''].filter(Boolean).join(' '), style: style, children: _jsxs("div", { className: `flex items-start gap-2 ${tickRowTextClasses[group.size]}`, children: [_jsx("span", { className: "flex h-[1lh] shrink-0 items-center", children: _jsx(BaseUIRadio.Root, { ref: ref, className: [
70
- dotBaseClasses,
71
- tickSizeClasses[group.size],
72
- disabled ? disabledDotClasses : readOnly ? readOnlyDotClasses : restDotClasses
73
- ].join(' '), disabled: disabled, ...props, children: _jsx(BaseUIRadio.Indicator, { className: `${indicatorClasses} ${tickDotClasses[group.size]}` }) }) }), label || description ? (_jsxs("span", { className: "flex min-w-0 flex-col gap-0.5", children: [label ? (_jsx(Field.Label, { className: disabled ? 'text-(--plass-muted-fg)' : 'cursor-pointer text-(--plass-fg)', children: label })) : null, description ? (_jsx(Field.Description, { className: `${metaTextClasses[group.size]} text-(--plass-muted-fg)`, children: description })) : null] })) : null] }) }));
74
- });
75
- /**
76
- * A set of options where exactly one is chosen.
77
- *
78
- * Base UI owns the roving tab index and the arrow-key navigation, which is the
79
- * whole reason a radio group is a component at all rather than a `<div>` full of
80
- * inputs: the set takes one tab stop, and the arrows move within it.
81
- */
82
- export const PlRadioGroup = /* @__PURE__ */ React.forwardRef(function PlRadioGroup({ size = 'md', color = 'primary', orientation = 'vertical', label, description, error, invalid, disabled = false, readOnly = false, className, style, children, ...props }, ref) {
83
- const hasError = hasContent(error);
84
- const isInvalid = invalid ?? hasError;
85
- // Invalid re-points the whole slot family at `danger`, so every dot, the
86
- // ring and the message all turn over together.
87
- const family = isInvalid ? 'danger' : color;
88
- const context = React.useMemo(() => ({ size, color: family, readOnly }), [size, family, readOnly]);
89
- return (_jsx(RadioGroupContext.Provider, { value: context, children: _jsxs(Field.Root, { disabled: disabled, invalid: isInvalid, className: ['flex flex-col gap-1.5', className ?? ''].filter(Boolean).join(' '),
90
- // `solid`, because a checked dot *is* the coloured thing.
91
- style: { ...controlSlots(family, 0, 'solid'), ...style }, children: [label ? (_jsx(Field.Label, { className: [
92
- metaTextClasses[size],
93
- 'font-semibold',
94
- disabled ? 'text-(--plass-muted-fg)' : 'text-(--plass-fg)'
95
- ].join(' '), children: label })) : null, description ? (_jsx(Field.Description, { className: `${metaTextClasses[size]} text-(--plass-muted-fg)`, children: description })) : null, _jsx(BaseUIRadioGroup, { ref: ref, disabled: disabled, readOnly: readOnly, className: [
96
- 'flex',
97
- orientation === 'horizontal' ? 'flex-row flex-wrap gap-x-5 gap-y-2' : 'flex-col gap-2'
98
- ].join(' '), ...props, children: children }), hasError ? (_jsx(Field.Error, { match: true, className: `${metaTextClasses[size]} text-(--p-accent)`, children: error })) : null] }) }));
99
- });
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as r from"react";import{Radio as l}from"@base-ui/react/radio";import{RadioGroup as o}from"@base-ui/react/radio-group";import{Field as s}from"@base-ui/react/field";import{controlSlots as t,focusRingClasses as i,glassClasses as d,hasContent as n,metaTextClasses as c,tickDotClasses as p,tickRowTextClasses as m,tickSizeClasses as f,transitionClasses as u}from"../../internal/styles.js";const h=/* @__PURE__ */r.createContext({size:"md",color:"primary",readOnly:!1}),b=/* @__PURE__ */["relative inline-flex shrink-0 items-center justify-center rounded-full border","[-webkit-tap-highlight-color:transparent] [touch-action:manipulation]",u,i].join(" "),g=/* @__PURE__ */[d,"cursor-pointer bg-(--plass-glass) [border-color:var(--plass-border)]","hover:bg-(--plass-glass-hover) hover:[border-color:var(--p-line)]","data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent] data-[checked]:hover:brightness-105"].join(" "),x=/* @__PURE__ */[d,"cursor-default bg-(--plass-glass) [border-color:var(--plass-border)]","saturate-[0.55]","data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]"].join(" "),v=/* @__PURE__ */[d,"cursor-not-allowed bg-(--plass-glass) [border-color:var(--plass-border)]","opacity-50 saturate-[0.35]","data-[checked]:[background-image:var(--p-fill)] data-[checked]:text-(--p-on-solid)","data-[checked]:[border-color:transparent]"].join(" ");export const PlRadio=/* @__PURE__ */r.forwardRef(function PlRadio({label:o,description:t,disabled:i=!1,className:d,style:n,...u},k){const y=r.useContext(h),N=u.readOnly??y.readOnly;return e(s.Root,{disabled:i,className:["flex flex-col",d??""].filter(Boolean).join(" "),style:n,children:a("div",{className:`flex items-start gap-2 ${m[y.size]}`,children:[e("span",{className:"flex h-[1lh] shrink-0 items-center",children:e(l.Root,{ref:k,className:[b,f[y.size],i?v:N?x:g].join(" "),disabled:i,...u,children:e(l.Indicator,{className:`rounded-full bg-current ${p[y.size]}`})})}),o||t?a("span",{className:"flex min-w-0 flex-col gap-0.5",children:[o?e(s.Label,{className:i?"text-(--plass-muted-fg)":"cursor-pointer text-(--plass-fg)",children:o}):null,t?e(s.Description,{className:`${c[y.size]} text-(--plass-muted-fg)`,children:t}):null]}):null]})})});export const PlRadioGroup=/* @__PURE__ */r.forwardRef(function PlRadioGroup({size:l="md",color:i="primary",orientation:d="vertical",label:p,description:m,error:f,invalid:u,disabled:b=!1,readOnly:g=!1,className:x,style:v,children:k,...y},N){const j=n(f),R=u??j,z=R?"danger":i,w=r.useMemo(()=>({size:l,color:z,readOnly:g}),[l,z,g]);return e(h.Provider,{value:w,children:a(s.Root,{disabled:b,invalid:R,className:["flex flex-col gap-1.5",x??""].filter(Boolean).join(" "),style:{...t(z,0,"solid"),...v},children:[p?e(s.Label,{className:[c[l],"font-semibold",b?"text-(--plass-muted-fg)":"text-(--plass-fg)"].join(" "),children:p}):null,m?e(s.Description,{className:`${c[l]} text-(--plass-muted-fg)`,children:m}):null,e(o,{ref:N,disabled:b,readOnly:g,className:["flex","horizontal"===d?"flex-row flex-wrap gap-x-5 gap-y-2":"flex-col gap-2"].join(" "),...y,children:k}),j?e(s.Error,{match:!0,className:`${c[l]} text-(--p-accent)`,children:f}):null]})})});
@@ -1 +1 @@
1
- export { PlRadio, PlRadioGroup } from './PlRadioGroup.js';
1
+ export{PlRadio,PlRadioGroup}from"./PlRadioGroup.js";
@@ -1,101 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { StarIcon, StarOutlineIcon } from '../../internal/icons.js';
4
- import { controlSlots, cx, focusWithinRingClasses, gapClasses, iconSizeClasses, radiusClasses, srOnlyClasses, transitionClasses } from '../../internal/styles.js';
5
- /**
6
- * The box one copy of the glyph is drawn in. Both copies get exactly this, or
7
- * the clipped one would not line up with the outline underneath it.
8
- */
9
- const starClasses = 'flex items-center justify-center';
10
- /** The default accessible name of a score. */
11
- function defaultValueLabel(value, count) {
12
- return value <= 0 ? 'No rating' : `${value} out of ${count}`;
13
- }
14
- /**
15
- * A score out of five, as a row of stars.
16
- *
17
- * Underneath an interactive rating is a radio group of real `<input>`s, one per
18
- * choosable score, each visually hidden under the fraction of a star it stands
19
- * for. That is the whole accessibility argument: a rating *is* "exactly one of
20
- * these", so it gets one tab stop for the row, arrow keys within it,
21
- * `aria-checked` on the one that is taken, and a value in a form submission —
22
- * none of which a row of `<button>`s or a `<div>` with a click handler would
23
- * have.
24
- *
25
- * The fraction is drawn by laying the filled star over the empty one and
26
- * clipping it to a percentage of the width. Nothing is transformed and no glyph
27
- * is scaled, so a half star is the left half of exactly the star beside it —
28
- * which is also the no-transform rule holding on a component whose whole job is
29
- * a partial shape. The clip runs from the inline start, so it fills from the
30
- * right under RTL without anything being told to.
31
- *
32
- * `readOnly` is a different component in the same clothes: no inputs, no radio
33
- * group, and one `role="img"` carrying the score as a sentence. A star display
34
- * that kept twenty focusable radios would be twenty tab stops on a page that
35
- * was only reporting a number.
36
- */
37
- export const PlRating = /* @__PURE__ */ React.forwardRef(function PlRating({ value: valueProp, defaultValue = 0, onValueChange, count = 5, precision = 1, icon, emptyIcon, clearable = true, readOnly = false, disabled = false, name: nameProp, required = false, size = 'md', color = 'warning', label = 'Rating', valueLabel = defaultValueLabel, className, style, onPointerLeave, ...props }, ref) {
38
- const generatedName = React.useId();
39
- const name = nameProp ?? generatedName;
40
- const [uncontrolled, setUncontrolled] = React.useState(defaultValue);
41
- const controlled = valueProp !== undefined;
42
- const value = controlled ? valueProp : uncontrolled;
43
- // What the pointer is currently promising, which is not the value until it is
44
- // clicked. `null` is "the pointer is not on the row", not "zero stars".
45
- const [hovered, setHovered] = React.useState(null);
46
- const stars = Math.max(1, Math.floor(count));
47
- const step = precision > 0 && precision <= 1 ? precision : 1;
48
- const stepsPerStar = Math.round(1 / step);
49
- const shown = Math.max(0, Math.min(stars, hovered ?? value));
50
- const change = (next) => {
51
- if (!controlled) {
52
- setUncontrolled(next);
53
- }
54
- onValueChange?.(next);
55
- };
56
- const marks = Array.from({ length: stars }, (_, index) => {
57
- // How much of *this* star is filled, from 0 to 1.
58
- const fill = Math.max(0, Math.min(1, shown - index));
59
- return (_jsxs("span", { className: cx('relative inline-flex shrink-0', iconSizeClasses[size], radiusClasses.xs, readOnly || disabled ? '' : focusWithinRingClasses), children: [_jsx("span", { className: cx(starClasses, iconSizeClasses[size], 'text-(--p-empty)'), children: emptyIcon ?? _jsx(StarOutlineIcon, {}) }), _jsx("span", { "aria-hidden": "true", className: "pointer-events-none absolute inset-y-0 start-0 overflow-hidden", style: { width: `${fill * 100}%` }, children: _jsx("span", { className: cx(starClasses, iconSizeClasses[size], 'text-(--p-accent)', transitionClasses), children: icon ?? _jsx(StarIcon, {}) }) }), readOnly
60
- ? null
61
- : Array.from({ length: stepsPerStar }, (_, part) => {
62
- const score = Number((index + (part + 1) * step).toFixed(4));
63
- return (_jsx("label", { className: cx('absolute inset-y-0', disabled ? 'cursor-not-allowed' : 'cursor-pointer'), style: {
64
- insetInlineStart: `${(part * 100) / stepsPerStar}%`,
65
- width: `${100 / stepsPerStar}%`
66
- }, onPointerEnter: () => {
67
- if (!disabled) {
68
- setHovered(score);
69
- }
70
- }, children: _jsx("input", { type: "radio", className: srOnlyClasses, name: name, value: score, checked: value === score, disabled: disabled, required: required, "aria-label": valueLabel(score, stars), onChange: () => change(score),
71
- // Clearing cannot ride on `change`: clicking a radio that is
72
- // already checked fires a click and no change at all, and
73
- // that click is exactly the gesture being listened for.
74
- onClick: () => {
75
- if (clearable && value === score) {
76
- change(0);
77
- }
78
- } }) }, score));
79
- })] }, index));
80
- });
81
- const classNames = cx('inline-flex items-center align-middle', gapClasses[size],
82
- // The house treatment, not a grey token: the light goes out of the row and
83
- // the page shows through it, which is what unavailable looks like
84
- // everywhere else in the library.
85
- disabled ? 'cursor-not-allowed opacity-50 saturate-[0.35]' : '', className);
86
- const styles = {
87
- ...controlSlots(color, 0, 'solid'),
88
- // An empty star is not a disabled one and not a hairline: it is the ghost of
89
- // the star beside it, so it takes the muted ink at enough strength to read
90
- // as a shape and not enough to compete with the ones that are filled.
91
- '--p-empty': 'color-mix(in oklab, var(--plass-muted-fg) 40%, transparent)',
92
- ...style
93
- };
94
- if (readOnly) {
95
- return (_jsx("div", { ref: ref, role: "img", "aria-label": valueLabel(Math.max(0, Math.min(stars, value)), stars), className: classNames, style: styles, onPointerLeave: onPointerLeave, ...props, children: marks }));
96
- }
97
- return (_jsx("div", { ref: ref, role: "radiogroup", "aria-label": label, "aria-disabled": disabled || undefined, "aria-required": required || undefined, className: classNames, style: styles, onPointerLeave: (event) => {
98
- setHovered(null);
99
- onPointerLeave?.(event);
100
- }, ...props, children: marks }));
101
- });
1
+ "use client";import{jsx as e,jsxs as a}from"react/jsx-runtime";import*as t from"react";import{StarIcon as n,StarOutlineIcon as r}from"../../internal/icons.js";import{controlSlots as l,cx as i,focusWithinRingClasses as s,gapClasses as o,iconSizeClasses as c,radiusClasses as d,srOnlyClasses as u,transitionClasses as m}from"../../internal/styles.js";const h="flex items-center justify-center";function defaultValueLabel(e,a){return e<=0?"No rating":`${e} out of ${a}`}export const PlRating=/* @__PURE__ */t.forwardRef(function PlRating({value:p,defaultValue:f=0,onValueChange:y,count:b=5,precision:x=1,icon:v,emptyIcon:g,clearable:N=!0,readOnly:M=!1,disabled:w=!1,name:j,required:L=!1,size:P="md",color:k="warning",label:R="Rating",valueLabel:V=defaultValueLabel,className:q,style:C,onPointerLeave:I,...S},A){const $=t.useId(),z=j??$,[E,F]=t.useState(f),O=void 0!==p,B=O?p:E,[D,G]=t.useState(null),H=Math.max(1,Math.floor(b)),J=x>0&&x<=1?x:1,K=Math.round(1/J),Q=Math.max(0,Math.min(H,D??B)),change=e=>{O||F(e),y?.(e)},T=Array.from({length:H},(t,l)=>{const o=Math.max(0,Math.min(1,Q-l));return a("span",{className:i("relative inline-flex shrink-0",c[P],d.xs,M||w?"":s),children:[e("span",{className:i(h,c[P],"text-(--p-empty)"),children:g??e(r,{})}),e("span",{"aria-hidden":"true",className:"pointer-events-none absolute inset-y-0 start-0 overflow-hidden",style:{width:100*o+"%"},children:e("span",{className:i(h,c[P],"text-(--p-accent)",m),children:v??e(n,{})})}),M?null:Array.from({length:K},(a,t)=>{const n=Number((l+(t+1)*J).toFixed(4));return e("label",{className:i("absolute inset-y-0",w?"cursor-not-allowed":"cursor-pointer"),style:{insetInlineStart:100*t/K+"%",width:100/K+"%"},onPointerEnter:()=>{w||G(n)},children:e("input",{type:"radio",className:u,name:z,value:n,checked:B===n,disabled:w,required:L,"aria-label":V(n,H),onChange:()=>change(n),onClick:()=>{N&&B===n&&change(0)}})},n)})]},l)}),U=i("inline-flex items-center align-middle",o[P],w?"cursor-not-allowed opacity-50 saturate-[0.35]":"",q),W={...l(k,0,"solid"),"--p-empty":"color-mix(in oklab, var(--plass-muted-fg) 40%, transparent)",...C};return e("div",M?{ref:A,role:"img","aria-label":V(Math.max(0,Math.min(H,B)),H),className:U,style:W,onPointerLeave:I,...S,children:T}:{ref:A,role:"radiogroup","aria-label":R,"aria-disabled":w||void 0,"aria-required":L||void 0,className:U,style:W,onPointerLeave:e=>{G(null),I?.(e)},...S,children:T})});
@@ -1 +1 @@
1
- export { PlRating } from './PlRating.js';
1
+ export{PlRating}from"./PlRating.js";