plass-ui 1.0.0 → 1.0.1

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 (164) hide show
  1. package/dist/components/accordion/PlAccordion.js +1 -131
  2. package/dist/components/accordion/index.js +1 -1
  3. package/dist/components/alert/PlAlert.js +1 -109
  4. package/dist/components/alert/index.js +1 -1
  5. package/dist/components/animate-appear/PlAnimateAppear.js +1 -71
  6. package/dist/components/animate-appear/index.js +1 -1
  7. package/dist/components/animate-blink/PlAnimateBlink.js +1 -47
  8. package/dist/components/animate-blink/index.js +1 -1
  9. package/dist/components/animate-fade/PlAnimateFade.js +1 -48
  10. package/dist/components/animate-fade/index.js +1 -1
  11. package/dist/components/animate-grow/PlAnimateGrow.js +1 -49
  12. package/dist/components/animate-grow/index.js +1 -1
  13. package/dist/components/animate-headline/PlAnimateHeadline.js +1 -120
  14. package/dist/components/animate-headline/index.js +1 -1
  15. package/dist/components/animate-lighting/PlAnimateLighting.js +1 -65
  16. package/dist/components/animate-lighting/index.js +1 -1
  17. package/dist/components/animate-marquee/PlAnimateMarquee.js +1 -94
  18. package/dist/components/animate-marquee/index.js +1 -1
  19. package/dist/components/animate-rotate/PlAnimateRotate.js +1 -50
  20. package/dist/components/animate-rotate/index.js +1 -1
  21. package/dist/components/animate-slide/PlAnimateSlide.js +1 -49
  22. package/dist/components/animate-slide/index.js +1 -1
  23. package/dist/components/animate-typing/PlAnimateTyping.js +1 -177
  24. package/dist/components/animate-typing/index.js +1 -1
  25. package/dist/components/animate-zoom/PlAnimateZoom.js +1 -45
  26. package/dist/components/animate-zoom/index.js +1 -1
  27. package/dist/components/aspect-ratio/PlAspectRatio.js +1 -58
  28. package/dist/components/aspect-ratio/index.js +1 -1
  29. package/dist/components/avatar/PlAvatar.js +1 -121
  30. package/dist/components/avatar/index.js +1 -1
  31. package/dist/components/badge/PlBadge.js +1 -168
  32. package/dist/components/badge/index.js +1 -1
  33. package/dist/components/blockquote/PlBlockquote.js +1 -112
  34. package/dist/components/blockquote/index.js +1 -1
  35. package/dist/components/bottom-navigation/PlBottomNavigation.js +1 -141
  36. package/dist/components/bottom-navigation/index.js +1 -1
  37. package/dist/components/box/PlBox.js +1 -46
  38. package/dist/components/box/index.js +1 -1
  39. package/dist/components/breadcrumb/PlBreadcrumb.js +1 -201
  40. package/dist/components/breadcrumb/index.js +1 -1
  41. package/dist/components/button/PlButton.js +1 -196
  42. package/dist/components/button/index.js +1 -1
  43. package/dist/components/button-group/PlButtonGroup.js +1 -64
  44. package/dist/components/button-group/index.js +1 -1
  45. package/dist/components/card/PlCard.js +1 -102
  46. package/dist/components/card/index.js +1 -1
  47. package/dist/components/carousel/PlCarousel.js +1 -177
  48. package/dist/components/carousel/index.js +1 -1
  49. package/dist/components/chat-bubble/PlChatBubble.js +1 -206
  50. package/dist/components/chat-bubble/index.js +1 -1
  51. package/dist/components/checkbox/PlCheckbox.js +1 -100
  52. package/dist/components/checkbox/index.js +1 -1
  53. package/dist/components/chip/PlChip.js +1 -144
  54. package/dist/components/chip/index.js +1 -1
  55. package/dist/components/collapsible/PlCollapsible.js +1 -65
  56. package/dist/components/collapsible/index.js +1 -1
  57. package/dist/components/combobox/PlCombobox.js +1 -199
  58. package/dist/components/combobox/index.js +1 -1
  59. package/dist/components/container/PlContainer.js +1 -47
  60. package/dist/components/container/index.js +1 -1
  61. package/dist/components/date-picker/PlDatePicker.js +1 -87
  62. package/dist/components/date-picker/index.js +1 -1
  63. package/dist/components/date-range-picker/PlDateRangePicker.js +1 -152
  64. package/dist/components/date-range-picker/index.js +1 -1
  65. package/dist/components/date-time-picker/PlDateTimePicker.js +1 -106
  66. package/dist/components/date-time-picker/index.js +1 -1
  67. package/dist/components/divider/PlDivider.js +1 -107
  68. package/dist/components/divider/index.js +1 -1
  69. package/dist/components/drawer/PlDrawer.js +1 -190
  70. package/dist/components/drawer/index.js +1 -1
  71. package/dist/components/file-picker/PlFilePicker.js +1 -274
  72. package/dist/components/file-picker/index.js +1 -1
  73. package/dist/components/floating-bottom-navigation/PlFloatingBottomNavigation.js +1 -291
  74. package/dist/components/floating-bottom-navigation/index.js +1 -1
  75. package/dist/components/grid/PlGrid.js +1 -51
  76. package/dist/components/grid/PlGridItem.js +1 -34
  77. package/dist/components/grid/index.js +1 -2
  78. package/dist/components/highlight/PlHighlight.js +1 -185
  79. package/dist/components/highlight/index.js +1 -1
  80. package/dist/components/hot-keys/PlHotKeys.js +1 -294
  81. package/dist/components/hot-keys/index.js +1 -1
  82. package/dist/components/icon/PlIcon.js +1 -58
  83. package/dist/components/icon/index.js +1 -1
  84. package/dist/components/icon-button/PlIconButton.js +1 -37
  85. package/dist/components/icon-button/index.js +1 -1
  86. package/dist/components/list/PlList.js +1 -160
  87. package/dist/components/list/index.js +1 -1
  88. package/dist/components/menu/PlMenu.js +1 -209
  89. package/dist/components/menu/index.js +1 -1
  90. package/dist/components/modal/PlModal.js +1 -150
  91. package/dist/components/modal/index.js +1 -1
  92. package/dist/components/number-field/PlNumberField.js +1 -111
  93. package/dist/components/number-field/index.js +1 -1
  94. package/dist/components/otp-field/PlOtpField.js +1 -109
  95. package/dist/components/otp-field/index.js +1 -1
  96. package/dist/components/overlay/PlOverlay.js +1 -77
  97. package/dist/components/overlay/index.js +1 -1
  98. package/dist/components/pagination/PlPagination.js +1 -159
  99. package/dist/components/pagination/index.js +1 -1
  100. package/dist/components/panes/PlPanes.js +1 -324
  101. package/dist/components/panes/index.js +1 -1
  102. package/dist/components/pill/PlPill.js +1 -154
  103. package/dist/components/pill/index.js +1 -1
  104. package/dist/components/popover/PlPopover.js +1 -113
  105. package/dist/components/popover/index.js +1 -1
  106. package/dist/components/progress-box/PlProgressBox.js +1 -34
  107. package/dist/components/progress-box/index.js +1 -1
  108. package/dist/components/progress-circular/PlProgressCircular.js +1 -47
  109. package/dist/components/progress-circular/index.js +1 -1
  110. package/dist/components/progress-linear/PlProgressLinear.js +1 -40
  111. package/dist/components/progress-linear/index.js +1 -1
  112. package/dist/components/radio-group/PlRadioGroup.js +1 -99
  113. package/dist/components/radio-group/index.js +1 -1
  114. package/dist/components/rating/PlRating.js +1 -101
  115. package/dist/components/rating/index.js +1 -1
  116. package/dist/components/scroll-zone/PlScrollZone.js +1 -411
  117. package/dist/components/scroll-zone/index.js +1 -1
  118. package/dist/components/segmented-button/PlSegmentedButton.js +1 -206
  119. package/dist/components/segmented-button/index.js +1 -1
  120. package/dist/components/select/PlSelect.js +1 -115
  121. package/dist/components/select/index.js +1 -1
  122. package/dist/components/skeleton/PlSkeleton.js +1 -142
  123. package/dist/components/skeleton/index.js +1 -1
  124. package/dist/components/slider/PlSlider.js +1 -132
  125. package/dist/components/slider/index.js +1 -1
  126. package/dist/components/spoiler/PlSpoiler.js +1 -74
  127. package/dist/components/spoiler/index.js +1 -1
  128. package/dist/components/switch/PlSwitch.js +1 -131
  129. package/dist/components/switch/index.js +1 -1
  130. package/dist/components/table/PlTable.js +1 -210
  131. package/dist/components/table/index.js +1 -1
  132. package/dist/components/tabs/PlTabs.js +1 -182
  133. package/dist/components/tabs/index.js +1 -1
  134. package/dist/components/text-field/PlTextField.js +1 -126
  135. package/dist/components/text-field/index.js +1 -1
  136. package/dist/components/text-link/PlTextLink.js +1 -136
  137. package/dist/components/text-link/index.js +1 -1
  138. package/dist/components/time-picker/PlTimePicker.js +1 -97
  139. package/dist/components/time-picker/index.js +1 -1
  140. package/dist/components/timeline/PlTimeline.js +1 -207
  141. package/dist/components/timeline/index.js +1 -1
  142. package/dist/components/toast/PlToast.js +1 -174
  143. package/dist/components/toast/index.js +1 -1
  144. package/dist/components/toolbar/PlToolbar.js +1 -65
  145. package/dist/components/toolbar/index.js +1 -1
  146. package/dist/components/tooltip/PlTooltip.js +1 -117
  147. package/dist/components/tooltip/index.js +1 -1
  148. package/dist/components/typography/PlTypography.js +1 -143
  149. package/dist/components/typography/index.js +1 -1
  150. package/dist/index.js +1 -75
  151. package/dist/internal/animate.js +1 -318
  152. package/dist/internal/button-group.js +2 -19
  153. package/dist/internal/calendar.js +1 -501
  154. package/dist/internal/date.js +1 -353
  155. package/dist/internal/format.js +1 -41
  156. package/dist/internal/grid.js +1 -143
  157. package/dist/internal/icons.js +1 -138
  158. package/dist/internal/menu.js +1 -18
  159. package/dist/internal/picker.js +1 -139
  160. package/dist/internal/progress.js +1 -167
  161. package/dist/internal/sizer.js +1 -35
  162. package/dist/internal/styles.js +1 -636
  163. package/dist/types.js +0 -8
  164. package/package.json +3 -2
@@ -1,152 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { PlButton } from '../button/PlButton.js';
4
- import { Calendar, usePickerLabels } from '../../internal/calendar.js';
5
- import { ArrowRightIcon, CalendarIcon } from '../../internal/icons.js';
6
- import { PickerFooter, PickerShell } from '../../internal/picker.js';
7
- import { WidthSizer } from '../../internal/sizer.js';
8
- import { addMonths, compareDay, displaySamples, formatDate, isValidDate, localeWeekStart, startOfDay, startOfMonth, toISODate, today, withPlaceholder } from '../../internal/date.js';
9
- import { cx, gapClasses, metaTextClasses } from '../../internal/styles.js';
10
- const EMPTY = { start: null, end: null };
11
- /**
12
- * A span between two days.
13
- *
14
- * Two months side by side, because a range that crosses a month boundary is the
15
- * ordinary case and a one-month picker makes it a two-step navigation problem.
16
- * The two panels are one calendar in two halves: the left one has no forward
17
- * stepper, the right one has no back stepper, and either header's month and year
18
- * buttons move both.
19
- *
20
- * The band between the ends is drawn as the pointer moves, before the second
21
- * click lands. That preview is the whole affordance — without it the first click
22
- * has no visible consequence and the control looks broken for the second or so
23
- * between the two.
24
- */
25
- export const PlDateRangePicker = /* @__PURE__ */ React.forwardRef(function PlDateRangePicker({ value: valueProp, defaultValue, onValueChange, open: openProp, defaultOpen, onOpenChange, defaultMonth, minDate, maxDate, shouldDisableDate, locale, weekStartsOn, format = { dateStyle: 'medium' }, monthCount = 2, startPlaceholder, endPlaceholder, presets, clearable = false, closeOnSelect = true, labels: labelOverrides, name, size = 'md', color = 'primary', readOnly = false, disabled = false, startIcon, ...shell }, ref) {
26
- const labels = usePickerLabels(labelOverrides);
27
- const firstDay = weekStartsOn ?? localeWeekStart(locale);
28
- const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? EMPTY);
29
- const value = valueProp !== undefined ? (valueProp ?? EMPTY) : uncontrolledValue;
30
- const start = isValidDate(value.start) ? value.start : null;
31
- const end = isValidDate(value.end) ? value.end : null;
32
- const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false);
33
- const open = openProp ?? uncontrolledOpen;
34
- // The first of the two clicks. Held here rather than in `value` so a
35
- // controlled caller is never handed a range with only one end — half a
36
- // selection is this component's business, not the form's.
37
- const [anchor, setAnchor] = React.useState(null);
38
- const [preview, setPreview] = React.useState(null);
39
- const [month, setMonth] = React.useState(() => startOfMonth(start ?? defaultMonth ?? today()));
40
- React.useEffect(() => {
41
- if (open) {
42
- setMonth(startOfMonth(start ?? defaultMonth ?? today()));
43
- }
44
- else {
45
- // An abandoned half-selection does not survive the popup closing.
46
- setAnchor(null);
47
- setPreview(null);
48
- }
49
- // Only when the popup opens — following `start` here would drag the calendar
50
- // out from under someone typing into a form elsewhere.
51
- // eslint-disable-next-line react-hooks/exhaustive-deps
52
- }, [open]);
53
- const setOpen = (next) => {
54
- if (next && (readOnly || disabled)) {
55
- return;
56
- }
57
- if (openProp === undefined) {
58
- setUncontrolledOpen(next);
59
- }
60
- onOpenChange?.(next);
61
- };
62
- const commit = (next) => {
63
- if (valueProp === undefined) {
64
- setUncontrolledValue(next);
65
- }
66
- onValueChange?.(next);
67
- };
68
- const select = (date) => {
69
- const day = startOfDay(date);
70
- // The first click of a new selection — either there is no anchor, or the
71
- // range is already complete and this click starts over.
72
- if (anchor === null) {
73
- setAnchor(day);
74
- setPreview(day);
75
- commit({ start: day, end: null });
76
- return;
77
- }
78
- // The second. Clicking backwards is not a mistake to be rejected, it is the
79
- // same range typed in the other order.
80
- const [from, to] = compareDay(day, anchor) < 0 ? [day, anchor] : [anchor, day];
81
- setAnchor(null);
82
- setPreview(null);
83
- commit({ start: from, end: to });
84
- if (closeOnSelect) {
85
- setOpen(false);
86
- }
87
- };
88
- const applyPreset = (preset) => {
89
- const range = typeof preset.value === 'function' ? preset.value() : preset.value;
90
- setAnchor(null);
91
- setPreview(null);
92
- commit(range);
93
- if (isValidDate(range.start)) {
94
- setMonth(startOfMonth(range.start));
95
- }
96
- if (closeOnSelect) {
97
- setOpen(false);
98
- }
99
- };
100
- // What the band is drawn between: the finished range, or the anchor and
101
- // whatever the pointer is currently over.
102
- const bandStart = anchor ?? start;
103
- const bandEnd = anchor !== null ? preview : end;
104
- const write = (date, fallback) => isValidDate(date) ? (formatDate(date, locale, format)) : (_jsx("span", { className: "text-(--plass-muted-fg)", children: fallback ?? '' }));
105
- const secondMonth = addMonths(month, 1);
106
- const twoUp = monthCount === 2;
107
- // Every date either half could show, so neither end of the trigger changes
108
- // width as the range is filled in.
109
- const dateSamples = React.useMemo(() => displaySamples(locale, format), [locale, format]);
110
- // Which end the next click will fill. The trigger says the same thing with its
111
- // two halves, but the trigger is behind the popup while the popup is up, so
112
- // the footer is the only place that can say it where it will be read.
113
- const hint = anchor !== null ? labels.end : start === null ? labels.start : null;
114
- const calendarProps = {
115
- size,
116
- color,
117
- locale,
118
- weekStartsOn: firstDay,
119
- selected: [start, end, anchor],
120
- rangeStart: bandStart,
121
- rangeEnd: bandEnd,
122
- onSelect: select,
123
- onPreviewChange: (date) => {
124
- if (anchor !== null) {
125
- setPreview(date ?? anchor);
126
- }
127
- },
128
- minDate,
129
- maxDate,
130
- shouldDisableDate,
131
- // With both panels showing six full weeks, the 1st of August is a trailing
132
- // day of the July panel *and* the first day of the August one. Two cells
133
- // with the same name in one popup is ambiguous to a pointer and outright
134
- // broken to a screen reader.
135
- showOutsideDays: false,
136
- labels
137
- };
138
- return (_jsx(PickerShell, { ...shell, size: size, color: color, readOnly: readOnly, disabled: disabled, triggerRef: ref, startIcon: startIcon ?? _jsx(CalendarIcon, {}), display: _jsxs("span", { className: "flex min-w-0 items-center gap-1.5", children: [_jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate", children: write(start, startPlaceholder) }), _jsx(WidthSizer, { samples: withPlaceholder(dateSamples, startPlaceholder) })] }), _jsx("span", { "aria-hidden": "true", className: "flex shrink-0 items-center text-(--plass-muted-fg) rtl:rotate-180", children: _jsx(ArrowRightIcon, {}) }), _jsxs("span", { className: "flex min-w-0 flex-col", children: [_jsx("span", { className: "truncate", children: write(end, endPlaceholder) }), _jsx(WidthSizer, { samples: withPlaceholder(dateSamples, endPlaceholder) })] })] }), empty: start === null && end === null, clearable: clearable, onClear: () => commit(EMPTY), open: open, onOpenChange: setOpen, labels: labels, hiddenValues: name
139
- ? [
140
- { name, value: start ? toISODate(start) : '' },
141
- { name, value: end ? toISODate(end) : '' }
142
- ]
143
- : undefined, children: _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs("div", { className: cx('flex items-stretch', gapClasses[size]), children: [presets && presets.length > 0 ? (_jsx("div", { className: cx('flex max-h-[calc(var(--p-cell,2.5rem)*8)] flex-col overflow-y-auto border-e pe-1.5', '[border-color:var(--plass-divider)]'), children: presets.map((preset, index) => (_jsx(PlButton, { variant: "ghost", size: size, color: color, density: "compact", className: "justify-start whitespace-nowrap", onClick: () => applyPreset(preset), children: preset.label }, index))) })) : null, _jsx(Calendar, { ...calendarProps, month: month, onMonthChange: setMonth, showNextButton: !twoUp, autoFocus: true }), twoUp ? (_jsx(Calendar, { ...calendarProps, month: secondMonth,
144
- // The right panel is a month ahead, so moving it means moving the
145
- // pair. Both headers drive one number.
146
- onMonthChange: (next) => setMonth(addMonths(next, -1)), showPreviousButton: false })) : null] }), clearable || hint !== null ? (_jsxs(PickerFooter, { size: size, children: [hint !== null ? (_jsx("span", { className: cx('me-auto text-(--plass-muted-fg)', metaTextClasses[size]), children: hint })) : null, clearable ? (_jsx(PlButton, { variant: "ghost", size: size, color: color, density: "compact", onClick: () => {
147
- setAnchor(null);
148
- setPreview(null);
149
- commit(EMPTY);
150
- setOpen(false);
151
- }, children: labels.clear })) : null] })) : null] }) }));
152
- });
1
+ "use client";import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as a from"react";import{PlButton as n}from"../button/PlButton.js";import{Calendar as t,usePickerLabels as s}from"../../internal/calendar.js";import{ArrowRightIcon as r,CalendarIcon as o}from"../../internal/icons.js";import{PickerFooter as i,PickerShell as c}from"../../internal/picker.js";import{WidthSizer as u}from"../../internal/sizer.js";import{addMonths as d,compareDay as m,displaySamples as p,formatDate as h,isValidDate as f,localeWeekStart as v,startOfDay as x,startOfMonth as g,toISODate as b,today as w,withPlaceholder as y}from"../../internal/date.js";import{cx as N,gapClasses as j,metaTextClasses as D}from"../../internal/styles.js";const S={start:null,end:null};export const PlDateRangePicker=/* @__PURE__ */a.forwardRef(function PlDateRangePicker({value:C,defaultValue:O,onValueChange:P,open:k,defaultOpen:z,onOpenChange:M,defaultMonth:R,minDate:B,maxDate:V,shouldDisableDate:E,locale:I,weekStartsOn:F,format:q={dateStyle:"medium"},monthCount:A=2,startPlaceholder:G,endPlaceholder:H,presets:J,clearable:K=!1,closeOnSelect:L=!0,labels:Q,name:T,size:U="md",color:W="primary",readOnly:X=!1,disabled:Y=!1,startIcon:Z,...$},_){const ee=s(Q),le=F??v(I),[ae,ne]=a.useState(O??S),te=void 0!==C?C??S:ae,se=f(te.start)?te.start:null,re=f(te.end)?te.end:null,[oe,ie]=a.useState(z??!1),ce=k??oe,[ue,de]=a.useState(null),[me,pe]=a.useState(null),[he,fe]=a.useState(()=>g(se??R??w()));a.useEffect(()=>{ce?fe(g(se??R??w())):(de(null),pe(null))},[ce]);const setOpen=e=>{e&&(X||Y)||(void 0===k&&ie(e),M?.(e))},commit=e=>{void 0===C&&ne(e),P?.(e)},ve=ue??se,xe=null!==ue?me:re,write=(l,a)=>f(l)?h(l,I,q):e("span",{className:"text-(--plass-muted-fg)",children:a??""}),ge=d(he,1),be=2===A,we=a.useMemo(()=>p(I,q),[I,q]),ye=null!==ue?ee.end:null===se?ee.start:null,Ne={size:U,color:W,locale:I,weekStartsOn:le,selected:[se,re,ue],rangeStart:ve,rangeEnd:xe,onSelect:e=>{const l=x(e);if(null===ue)return de(l),pe(l),void commit({start:l,end:null});const[a,n]=m(l,ue)<0?[l,ue]:[ue,l];de(null),pe(null),commit({start:a,end:n}),L&&setOpen(!1)},onPreviewChange:e=>{null!==ue&&pe(e??ue)},minDate:B,maxDate:V,shouldDisableDate:E,showOutsideDays:!1,labels:ee};return e(c,{...$,size:U,color:W,readOnly:X,disabled:Y,triggerRef:_,startIcon:Z??e(o,{}),display:l("span",{className:"flex min-w-0 items-center gap-1.5",children:[l("span",{className:"flex min-w-0 flex-col",children:[e("span",{className:"truncate",children:write(se,G)}),e(u,{samples:y(we,G)})]}),e("span",{"aria-hidden":"true",className:"flex shrink-0 items-center text-(--plass-muted-fg) rtl:rotate-180",children:e(r,{})}),l("span",{className:"flex min-w-0 flex-col",children:[e("span",{className:"truncate",children:write(re,H)}),e(u,{samples:y(we,H)})]})]}),empty:null===se&&null===re,clearable:K,onClear:()=>commit(S),open:ce,onOpenChange:setOpen,labels:ee,hiddenValues:T?[{name:T,value:se?b(se):""},{name:T,value:re?b(re):""}]:void 0,children:l("div",{className:"flex flex-col gap-1.5",children:[l("div",{className:N("flex items-stretch",j[U]),children:[J&&J.length>0?e("div",{className:N("flex max-h-[calc(var(--p-cell,2.5rem)*8)] flex-col overflow-y-auto border-e pe-1.5","[border-color:var(--plass-divider)]"),children:J.map((l,a)=>e(n,{variant:"ghost",size:U,color:W,density:"compact",className:"justify-start whitespace-nowrap",onClick:()=>(e=>{const l="function"==typeof e.value?e.value():e.value;de(null),pe(null),commit(l),f(l.start)&&fe(g(l.start)),L&&setOpen(!1)})(l),children:l.label},a))}):null,e(t,{...Ne,month:he,onMonthChange:fe,showNextButton:!be,autoFocus:!0}),be?e(t,{...Ne,month:ge,onMonthChange:e=>fe(d(e,-1)),showPreviousButton:!1}):null]}),K||null!==ye?l(i,{size:U,children:[null!==ye?e("span",{className:N("me-auto text-(--plass-muted-fg)",D[U]),children:ye}):null,K?e(n,{variant:"ghost",size:U,color:W,density:"compact",onClick:()=>{de(null),pe(null),commit(S),setOpen(!1)},children:ee.clear}):null]}):null]})})});
@@ -1 +1 @@
1
- export { PlDateRangePicker } from './PlDateRangePicker.js';
1
+ export{PlDateRangePicker}from"./PlDateRangePicker.js";
@@ -1,106 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { PlButton } from '../button/PlButton.js';
4
- import { Calendar, TimeGrid, usePickerLabels } from '../../internal/calendar.js';
5
- import { CalendarIcon } from '../../internal/icons.js';
6
- import { PickerDivider, PickerFooter, PickerShell } from '../../internal/picker.js';
7
- import { displaySamples, formatDate, isDayOutside, isHour12, isValidDate, localeWeekStart, mergeDateAndTime, startOfDay, startOfMonth, timeUnitSpan, toISODateTime, today, withPlaceholder, withTime } from '../../internal/date.js';
8
- import { cx, gapClasses } from '../../internal/styles.js';
9
- /**
10
- * A day and a time, in one popup.
11
- *
12
- * Not a date picker that grew a clock and not a time picker that grew a
13
- * calendar: the two panels sit side by side at exactly the same height — seven
14
- * rows of cells each, which is why the calendar's grid and the clock's columns
15
- * share the `--p-cell` ladder — so the popup is one rectangle rather than two of
16
- * different sizes pushed together.
17
- *
18
- * The bounds do more work here than anywhere else. `minDate` is read at **full
19
- * precision**, so a minimum of 09:30 on the 27th leaves the 27th selectable in
20
- * the calendar and greys out the morning in the clock. That is the behaviour a
21
- * "not before now" rule needs, and it is the one a day-granular check cannot
22
- * give.
23
- */
24
- export const PlDateTimePicker = /* @__PURE__ */ React.forwardRef(function PlDateTimePicker({ value: valueProp, defaultValue, onValueChange, open: openProp, defaultOpen, onOpenChange, defaultMonth, minDate, maxDate, shouldDisableDate, shouldDisableTime, locale, weekStartsOn, format = { dateStyle: 'medium', timeStyle: 'short' }, hour12: hour12Prop, showSeconds = false, hourStep = 1, minuteStep = 1, secondStep = 1, placeholder, clearable = false, showNowButton = true, closeOnSelect = false, labels: labelOverrides, name, size = 'md', color = 'primary', density = 'default', readOnly = false, disabled = false, startIcon, ...shell }, ref) {
25
- const labels = usePickerLabels(labelOverrides);
26
- const firstDay = weekStartsOn ?? localeWeekStart(locale);
27
- const hour12 = hour12Prop ?? isHour12(locale);
28
- const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? null);
29
- const value = valueProp !== undefined ? valueProp : uncontrolledValue;
30
- const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false);
31
- const open = openProp ?? uncontrolledOpen;
32
- const [month, setMonth] = React.useState(() => startOfMonth(isValidDate(value) ? value : (defaultMonth ?? today())));
33
- React.useEffect(() => {
34
- if (open) {
35
- setMonth(startOfMonth(isValidDate(value) ? value : (defaultMonth ?? today())));
36
- }
37
- // Only when the popup opens — following `value` here would drag the calendar
38
- // out from under someone typing into a form elsewhere.
39
- // eslint-disable-next-line react-hooks/exhaustive-deps
40
- }, [open]);
41
- const setOpen = (next) => {
42
- if (next && (readOnly || disabled)) {
43
- return;
44
- }
45
- if (openProp === undefined) {
46
- setUncontrolledOpen(next);
47
- }
48
- onOpenChange?.(next);
49
- };
50
- const commit = (next) => {
51
- if (valueProp === undefined) {
52
- setUncontrolledValue(next);
53
- }
54
- onValueChange?.(next);
55
- };
56
- /**
57
- * Blocks a clock row whose whole span falls outside the bounds — the same span
58
- * test a `PlTimePicker` makes, moved onto the absolute timeline so the check
59
- * knows which day the columns are writing into.
60
- */
61
- const isTimeBlocked = React.useCallback((candidate, unit) => {
62
- const [from, to] = timeUnitSpan(unit, candidate);
63
- const midnight = startOfDay(candidate).getTime();
64
- if (isValidDate(minDate) && midnight + to * 1000 < minDate.getTime()) {
65
- return true;
66
- }
67
- if (isValidDate(maxDate) && midnight + from * 1000 > maxDate.getTime()) {
68
- return true;
69
- }
70
- return shouldDisableTime?.(candidate, unit) ?? false;
71
- }, [minDate, maxDate, shouldDisableTime]);
72
- const selectDay = (date) => {
73
- // The day changes, the clock does not. A picker that reset the time to
74
- // midnight every time the date was corrected would make choosing a moment an
75
- // ordered task, and nobody reads a popup in the order it was written.
76
- const next = isValidDate(value) ? mergeDateAndTime(date, value) : startOfDay(date);
77
- commit(next);
78
- setMonth(startOfMonth(next));
79
- if (closeOnSelect) {
80
- setOpen(false);
81
- }
82
- };
83
- const nowMoment = new Date();
84
- const nowValue = withTime(nowMoment, { seconds: showSeconds ? nowMoment.getSeconds() : 0 });
85
- const nowBlocked = isDayOutside(nowValue, minDate, maxDate) ||
86
- (shouldDisableDate?.(nowValue) ?? false) ||
87
- isTimeBlocked(nowValue, 'second');
88
- // Holds the trigger open at the width of the longest moment it could show, so
89
- // choosing an earlier one does not shrink the field.
90
- const samples = React.useMemo(() => withPlaceholder(displaySamples(locale, format), placeholder), [locale, format, placeholder]);
91
- return (_jsx(PickerShell, { ...shell, size: size, color: color, density: density, readOnly: readOnly, disabled: disabled, triggerRef: ref,
92
- // The calendar glyph alone, not both: a control cannot say two things at
93
- // once, and the date is the part a reader scans for.
94
- startIcon: startIcon ?? _jsx(CalendarIcon, {}), display: isValidDate(value) ? formatDate(value, locale, format) : (placeholder ?? ''), samples: samples, empty: !isValidDate(value), clearable: clearable, onClear: () => commit(null), open: open, onOpenChange: setOpen, labels: labels, hiddenValues: name
95
- ? [{ name, value: isValidDate(value) ? toISODateTime(value, showSeconds) : '' }]
96
- : undefined, children: _jsxs("div", { className: "flex flex-col gap-1.5", children: [_jsxs("div", { className: cx('flex items-stretch', gapClasses[size]), children: [_jsx(Calendar, { size: size, color: color, locale: locale, weekStartsOn: firstDay, month: month, onMonthChange: setMonth, selected: [value], onSelect: selectDay, minDate: minDate, maxDate: maxDate, shouldDisableDate: shouldDisableDate, labels: labels, autoFocus: true }), _jsx(PickerDivider, {}), _jsx(TimeGrid, { size: size, density: density, locale: locale, value: isValidDate(value) ? value : null,
97
- // With no day chosen yet the clock writes onto today, and picking a
98
- // day afterwards keeps whatever time was set.
99
- referenceDate: isValidDate(value) ? value : today(), onChange: commit, hour12: hour12, showSeconds: showSeconds, hourStep: hourStep, minuteStep: minuteStep, secondStep: secondStep, shouldDisableTime: isTimeBlocked, labels: labels })] }), _jsxs(PickerFooter, { size: size, children: [clearable ? (_jsx(PlButton, { variant: "ghost", size: size, color: color, density: "compact", onClick: () => {
100
- commit(null);
101
- setOpen(false);
102
- }, children: labels.clear })) : null, showNowButton ? (_jsx(PlButton, { variant: "ghost", size: size, color: color, density: "compact", disabled: nowBlocked, onClick: () => {
103
- commit(nowValue);
104
- setMonth(startOfMonth(nowValue));
105
- }, children: labels.now })) : null, _jsx(PlButton, { variant: "solid", size: size, color: color, density: "compact", onClick: () => setOpen(false), children: labels.done })] })] }) }));
106
- });
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as l from"react";import{PlButton as o}from"../button/PlButton.js";import{Calendar as n,TimeGrid as a,usePickerLabels as s}from"../../internal/calendar.js";import{CalendarIcon as i}from"../../internal/icons.js";import{PickerDivider as r,PickerFooter as c,PickerShell as d}from"../../internal/picker.js";import{displaySamples as m,formatDate as u,isDayOutside as h,isHour12 as p,isValidDate as f,localeWeekStart as S,mergeDateAndTime as b,startOfDay as g,startOfMonth as y,timeUnitSpan as D,toISODateTime as v,today as C,withPlaceholder as j,withTime as k}from"../../internal/date.js";import{cx as w,gapClasses as x}from"../../internal/styles.js";export const PlDateTimePicker=/* @__PURE__ */l.forwardRef(function PlDateTimePicker({value:z,defaultValue:O,onValueChange:T,open:P,defaultOpen:M,onOpenChange:N,defaultMonth:V,minDate:B,maxDate:I,shouldDisableDate:R,shouldDisableTime:E,locale:F,weekStartsOn:q,format:A={dateStyle:"medium",timeStyle:"short"},hour12:G,showSeconds:H=!1,hourStep:J=1,minuteStep:K=1,secondStep:L=1,placeholder:Q,clearable:U=!1,showNowButton:W=!0,closeOnSelect:X=!1,labels:Y,name:Z,size:$="md",color:_="primary",density:ee="default",readOnly:te=!1,disabled:le=!1,startIcon:oe,...ne},ae){const se=s(Y),ie=q??S(F),re=G??p(F),[ce,de]=l.useState(O??null),me=void 0!==z?z:ce,[ue,he]=l.useState(M??!1),pe=P??ue,[fe,Se]=l.useState(()=>y(f(me)?me:V??C()));l.useEffect(()=>{pe&&Se(y(f(me)?me:V??C()))},[pe]);const setOpen=e=>{e&&(te||le)||(void 0===P&&he(e),N?.(e))},commit=e=>{void 0===z&&de(e),T?.(e)},be=l.useCallback((e,t)=>{const[l,o]=D(t,e),n=g(e).getTime();return!!(f(B)&&n+1e3*o<B.getTime())||!!(f(I)&&n+1e3*l>I.getTime())||(E?.(e,t)??!1)},[B,I,E]),ge=new Date,ye=k(ge,{seconds:H?ge.getSeconds():0}),De=h(ye,B,I)||(R?.(ye)??!1)||be(ye,"second"),ve=l.useMemo(()=>j(m(F,A),Q),[F,A,Q]);return e(d,{...ne,size:$,color:_,density:ee,readOnly:te,disabled:le,triggerRef:ae,startIcon:oe??e(i,{}),display:f(me)?u(me,F,A):Q??"",samples:ve,empty:!f(me),clearable:U,onClear:()=>commit(null),open:pe,onOpenChange:setOpen,labels:se,hiddenValues:Z?[{name:Z,value:f(me)?v(me,H):""}]:void 0,children:t("div",{className:"flex flex-col gap-1.5",children:[t("div",{className:w("flex items-stretch",x[$]),children:[e(n,{size:$,color:_,locale:F,weekStartsOn:ie,month:fe,onMonthChange:Se,selected:[me],onSelect:e=>{const t=f(me)?b(e,me):g(e);commit(t),Se(y(t)),X&&setOpen(!1)},minDate:B,maxDate:I,shouldDisableDate:R,labels:se,autoFocus:!0}),e(r,{}),e(a,{size:$,density:ee,locale:F,value:f(me)?me:null,referenceDate:f(me)?me:C(),onChange:commit,hour12:re,showSeconds:H,hourStep:J,minuteStep:K,secondStep:L,shouldDisableTime:be,labels:se})]}),t(c,{size:$,children:[U?e(o,{variant:"ghost",size:$,color:_,density:"compact",onClick:()=>{commit(null),setOpen(!1)},children:se.clear}):null,W?e(o,{variant:"ghost",size:$,color:_,density:"compact",disabled:De,onClick:()=>{commit(ye),Se(y(ye))},children:se.now}):null,e(o,{variant:"solid",size:$,color:_,density:"compact",onClick:()=>setOpen(!1),children:se.done})]})]})})});
@@ -1 +1 @@
1
- export { PlDateTimePicker } from './PlDateTimePicker.js';
1
+ export{PlDateTimePicker}from"./PlDateTimePicker.js";
@@ -1,107 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { Separator } from '@base-ui/react/separator';
4
- import { metaTextClasses } from '../../internal/styles.js';
5
- /**
6
- * The hairline itself. A border rather than a filled 1px box, so it lands on
7
- * the device pixel grid the same way every other edge in the library does.
8
- *
9
- * Its thickness is read from a slot rather than from a `border-2`-style utility
10
- * because a labelled divider draws the rule twice — the two stubs either side
11
- * of the label — and one custom property set on the root keeps both the same
12
- * without threading a value through each.
13
- */
14
- const lineClasses = '[border-color:var(--p-rule-color)]';
15
- /** Turns `2` into `2px` and leaves `'0.5rem'` alone. */
16
- function toLength(value) {
17
- return typeof value === 'number' ? `${value}px` : value;
18
- }
19
- /**
20
- * How the line is split around an off-centre label: `[before, after]`. The short
21
- * side is a fixed stub rather than a small flex ratio, so the label sits the
22
- * same distance from the edge whatever the divider's length turns out to be.
23
- */
24
- const stubClasses = {
25
- horizontal: {
26
- start: ['w-4 shrink-0', 'flex-1'],
27
- center: ['flex-1', 'flex-1'],
28
- end: ['flex-1', 'w-4 shrink-0']
29
- },
30
- vertical: {
31
- start: ['h-4 shrink-0', 'flex-1'],
32
- center: ['flex-1', 'flex-1'],
33
- end: ['flex-1', 'h-4 shrink-0']
34
- }
35
- };
36
- /** Space between the label and the line on either side of it. */
37
- const labelGapClasses = {
38
- xs: 'gap-1.5',
39
- sm: 'gap-2',
40
- md: 'gap-3',
41
- lg: 'gap-3.5',
42
- xl: 'gap-4'
43
- };
44
- /**
45
- * A rule between two things.
46
- *
47
- * With no children it is Base UI's `Separator` and nothing else — a real
48
- * `role="separator"` with the right `aria-orientation`. With children the line
49
- * breaks around the label.
50
- *
51
- * `separator` is not a name-from-content role, so a visible label does *not*
52
- * become the accessible name on its own: a screen reader would announce a bare
53
- * "separator" and read the word "OR" as loose text somewhere nearby. A string
54
- * label is therefore copied into `aria-label`. Anything richer is left alone —
55
- * only the caller knows which part of it is the name.
56
- *
57
- * There is no `variant` and no `elevation`, because a divider is not a surface.
58
- * It is not made of glass, catches no light and casts no shadow — it is the
59
- * absence of a surface, drawn.
60
- */
61
- export const PlDivider = /* @__PURE__ */ React.forwardRef(function PlDivider({ orientation = 'horizontal', color, size = 'md', length, thickness, textAlign = 'center', className, style, children, ...props }, ref) {
62
- const vertical = orientation === 'vertical';
63
- const hasLabel = children !== undefined && children !== null && children !== false && children !== '';
64
- const slots = {
65
- '--p-rule-color': color ? `var(--plass-${color}-line)` : 'var(--plass-border)',
66
- '--p-rule': toLength(thickness) ?? '1px'
67
- };
68
- // The long axis, and only when it was asked for: left alone, a horizontal
69
- // divider is `w-full` and a vertical one stretches to its flex row, which are
70
- // the two things a rule between two things should already do.
71
- const span = toLength(length);
72
- const sizing = span === undefined ? null : vertical ? { height: span } : { width: span };
73
- const rootStyle = { ...slots, ...sizing, ...style };
74
- if (!hasLabel) {
75
- return (_jsx(Separator, { ref: ref, orientation: orientation, className: [
76
- // The line is a single border edge; the box itself has no thickness,
77
- // so a divider never adds a pixel of layout beyond the rule.
78
- vertical
79
- ? `w-0 border-l [border-left-width:var(--p-rule)] ${span === undefined ? 'self-stretch' : ''}`
80
- : 'h-0 w-full border-t [border-top-width:var(--p-rule)]',
81
- lineClasses,
82
- className ?? ''
83
- ]
84
- .filter(Boolean)
85
- .join(' '), style: rootStyle, ...props }));
86
- }
87
- const [before, after] = stubClasses[orientation][textAlign];
88
- const edgeClasses = vertical
89
- ? 'w-0 border-l [border-left-width:var(--p-rule)]'
90
- : 'h-0 border-t [border-top-width:var(--p-rule)]';
91
- return (_jsxs(Separator, { ref: ref, orientation: orientation, "aria-label": typeof children === 'string' ? children : undefined, className: [
92
- 'flex items-center',
93
- vertical ? `w-auto flex-col ${span === undefined ? 'self-stretch' : ''}` : 'w-full',
94
- labelGapClasses[size],
95
- className ?? ''
96
- ]
97
- .filter(Boolean)
98
- .join(' '), style: rootStyle, ...props, children: [_jsx("span", { "aria-hidden": "true", className: `${edgeClasses} ${before} ${lineClasses}` }), _jsx("span", { className: [
99
- 'shrink-0 whitespace-nowrap text-(--plass-muted-fg)',
100
- metaTextClasses[size],
101
- // A vertical rule's label has to turn with it, or the line grows to
102
- // the width of the word and stops being a hairline.
103
- vertical ? '[writing-mode:vertical-rl]' : ''
104
- ]
105
- .filter(Boolean)
106
- .join(' '), children: children }), _jsx("span", { "aria-hidden": "true", className: `${edgeClasses} ${after} ${lineClasses}` })] }));
107
- });
1
+ "use client";import{jsx as e,jsxs as r}from"react/jsx-runtime";import*as t from"react";import{Separator as l}from"@base-ui/react/separator";import{metaTextClasses as o}from"../../internal/styles.js";const a="[border-color:var(--p-rule-color)]";function toLength(e){return"number"==typeof e?`${e}px`:e}const i={horizontal:{start:["w-4 shrink-0","flex-1"],center:["flex-1","flex-1"],end:["flex-1","w-4 shrink-0"]},vertical:{start:["h-4 shrink-0","flex-1"],center:["flex-1","flex-1"],end:["flex-1","h-4 shrink-0"]}},n={xs:"gap-1.5",sm:"gap-2",md:"gap-3",lg:"gap-3.5",xl:"gap-4"};export const PlDivider=/* @__PURE__ */t.forwardRef(function PlDivider({orientation:t="horizontal",color:s,size:c="md",length:d,thickness:f,textAlign:p="center",className:h,style:u,children:m,...x},v){const w="vertical"===t,g=null!=m&&!1!==m&&""!==m,b={"--p-rule-color":s?`var(--plass-${s}-line)`:"var(--plass-border)","--p-rule":toLength(f)??"1px"},$=toLength(d),j={...b,...void 0===$?null:w?{height:$}:{width:$},...u};if(!g)return e(l,{ref:v,orientation:t,className:[w?"w-0 border-l [border-left-width:var(--p-rule)] "+(void 0===$?"self-stretch":""):"h-0 w-full border-t [border-top-width:var(--p-rule)]",a,h??""].filter(Boolean).join(" "),style:j,...x});const[k,y]=i[t][p],N=w?"w-0 border-l [border-left-width:var(--p-rule)]":"h-0 border-t [border-top-width:var(--p-rule)]";return r(l,{ref:v,orientation:t,"aria-label":"string"==typeof m?m:void 0,className:["flex items-center",w?"w-auto flex-col "+(void 0===$?"self-stretch":""):"w-full",n[c],h??""].filter(Boolean).join(" "),style:j,...x,children:[e("span",{"aria-hidden":"true",className:`${N} ${k} ${a}`}),e("span",{className:["shrink-0 whitespace-nowrap text-(--plass-muted-fg)",o[c],w?"[writing-mode:vertical-rl]":""].filter(Boolean).join(" "),children:m}),e("span",{"aria-hidden":"true",className:`${N} ${y} ${a}`})]})});
@@ -1 +1 @@
1
- export { PlDivider } from './PlDivider.js';
1
+ export{PlDivider}from"./PlDivider.js";
@@ -1,190 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Dialog as BaseUIDialog } from '@base-ui/react/dialog';
3
- import { CloseIcon } from '../../internal/icons.js';
4
- import { cx, focusRingClasses, glassClasses, hasContent, metaTextClasses, sheetBodyClasses, sheetHeaderGapClasses, sheetLineClasses, sheetPaddingXClasses, sheetPaddingYClasses, sheetSectionGapClasses, sheetTitleClasses, surfaceSlots } from '../../internal/styles.js';
5
- /**
6
- * How wide a `left` or `right` panel is when nothing says otherwise.
7
- *
8
- * Its own ladder rather than `PlModal`'s `maxWidth`, and deliberately narrower
9
- * at every step: a modal is measured by how long a line of text is comfortable
10
- * inside it, and a drawer is measured by how much of the window it is willing
11
- * to take away from what it is a drawer *for*.
12
- *
13
- * A `top` or `bottom` panel has no entry here on purpose — its extent is its
14
- * content, capped at 85% of the window, because a bottom sheet holding three
15
- * rows should be three rows tall.
16
- */
17
- const extentClasses = {
18
- xs: 'w-56',
19
- sm: 'w-64',
20
- md: 'w-80',
21
- lg: 'w-96',
22
- xl: 'w-[28rem]'
23
- };
24
- /**
25
- * The corners on the free edge, written out per side and per step because
26
- * Tailwind only ever sees class names that appear literally in the source.
27
- */
28
- const roundedClasses = {
29
- left: {
30
- xs: 'rounded-r-(--plass-radius-xs)',
31
- sm: 'rounded-r-(--plass-radius-sm)',
32
- md: 'rounded-r-(--plass-radius-md)',
33
- lg: 'rounded-r-(--plass-radius-lg)',
34
- xl: 'rounded-r-(--plass-radius-xl)'
35
- },
36
- right: {
37
- xs: 'rounded-l-(--plass-radius-xs)',
38
- sm: 'rounded-l-(--plass-radius-sm)',
39
- md: 'rounded-l-(--plass-radius-md)',
40
- lg: 'rounded-l-(--plass-radius-lg)',
41
- xl: 'rounded-l-(--plass-radius-xl)'
42
- },
43
- top: {
44
- xs: 'rounded-b-(--plass-radius-xs)',
45
- sm: 'rounded-b-(--plass-radius-sm)',
46
- md: 'rounded-b-(--plass-radius-md)',
47
- lg: 'rounded-b-(--plass-radius-lg)',
48
- xl: 'rounded-b-(--plass-radius-xl)'
49
- },
50
- bottom: {
51
- xs: 'rounded-t-(--plass-radius-xs)',
52
- sm: 'rounded-t-(--plass-radius-sm)',
53
- md: 'rounded-t-(--plass-radius-md)',
54
- lg: 'rounded-t-(--plass-radius-lg)',
55
- xl: 'rounded-t-(--plass-radius-xl)'
56
- }
57
- };
58
- /**
59
- * The hairline on the free edge only. A border all round would draw a line
60
- * along the window's own edge, where there is nothing on the other side of it
61
- * to be separated from.
62
- */
63
- const edgeClasses = {
64
- left: 'border-r',
65
- right: 'border-l',
66
- top: 'border-b',
67
- bottom: 'border-t'
68
- };
69
- /** Which end of the viewport the panel is pushed to, and along which axis. */
70
- const viewportClasses = {
71
- left: 'flex-row justify-start',
72
- right: 'flex-row justify-end',
73
- top: 'flex-col justify-start',
74
- bottom: 'flex-col justify-end'
75
- };
76
- /**
77
- * The sheet.
78
- *
79
- * Opacity only, exactly as on `PlModal`. A drawer that slid in would be
80
- * dragging its own text across the screen for the length of the transition, and
81
- * a panel is nothing but text and controls — this is the case the no-transform
82
- * rule was written for, not the exception to it. What says the panel came from
83
- * an edge is that it is *attached* to one: square against the window, cut on the
84
- * free side.
85
- */
86
- const panelClasses = /* @__PURE__ */ [
87
- glassClasses,
88
- 'relative flex flex-col overflow-hidden',
89
- 'text-(--plass-fg) bg-(--plass-glass-press)',
90
- '[border-color:var(--plass-glass-line)]',
91
- '[outline:none]'
92
- ].join(' ');
93
- const overlayShadowClasses = '[box-shadow:var(--plass-shadow-4),var(--plass-gloss-glass)]';
94
- const inlineShadowClasses = '[box-shadow:var(--plass-gloss-glass)]';
95
- const fadeClasses = /* @__PURE__ */ [
96
- '[transition:opacity_var(--plass-duration)_var(--plass-ease)]',
97
- 'data-[starting-style]:opacity-0 data-[ending-style]:opacity-0'
98
- ].join(' ');
99
- const backdropClasses = /* @__PURE__ */ [
100
- 'fixed inset-0 z-50 bg-(--plass-scrim)',
101
- '[backdrop-filter:blur(2px)] [-webkit-backdrop-filter:blur(2px)]',
102
- fadeClasses
103
- ].join(' ');
104
- /** The × in the corner, shared by both modes. */
105
- const closeButtonClasses = /* @__PURE__ */ [
106
- 'flex size-[1.6em] shrink-0 cursor-pointer items-center justify-center',
107
- 'rounded-full text-(--plass-muted-fg)',
108
- '[&_svg]:size-[1.1em] [&_svg]:shrink-0',
109
- '[transition:background-color_var(--plass-duration)_var(--plass-ease),color_var(--plass-duration)_var(--plass-ease)]',
110
- 'hover:bg-(--p-soft) hover:text-(--plass-fg)',
111
- focusRingClasses
112
- ].join(' ');
113
- /**
114
- * Closes the drawer it is inside.
115
- *
116
- * Exported for `PlModalClose`'s reason: an uncontrolled drawer has no `setOpen`
117
- * for its Cancel button to call. It is an `overlay` drawer's button — an
118
- * `inline` drawer is not a Base UI dialog and has nothing for this to talk to.
119
- *
120
- * `render` is Base UI's own escape hatch, so a real Plass button dismisses:
121
- * `<PlDrawerClose render={<PlButton variant="ghost">Cancel</PlButton>} />`.
122
- */
123
- export const PlDrawerClose = BaseUIDialog.Close;
124
- /**
125
- * A panel attached to one edge of the window.
126
- *
127
- * Two things in one component, because they are the same panel: `overlay` is the
128
- * drawer you open — a scrim, a focus trap, Escape — and `inline` is the drawer
129
- * that is simply part of the page. Everything else about them is identical,
130
- * which is exactly why they should not be two components a caller has to switch
131
- * between when a sidebar becomes a hamburger at a breakpoint.
132
- *
133
- * The sections are props rather than compound sub-components, as on `PlCard` and
134
- * `PlModal`: the arrangement is fixed — heading, description, body, actions —
135
- * and what a caller wants to decide is what goes in each slot. The body is the
136
- * only part that scrolls, so the heading and the actions stay put.
137
- *
138
- * In `overlay` mode Base UI owns everything hard about it: the focus trap, the
139
- * scroll lock, the `aria-labelledby` / `aria-describedby` wiring, restoring
140
- * focus to the trigger, and the inert page behind.
141
- */
142
- export function PlDrawer({ side = 'left', mode = 'overlay', size = 'md', color = 'primary', density = 'default', open, defaultOpen, onOpenChange, trigger, title, description, actions, dividers = false, showClose, closeLabel = 'Close', extent, rounded = true, modal = true, dismissible = true, className, style, children, ...props }) {
143
- const overlay = mode === 'overlay';
144
- const along = side === 'left' || side === 'right';
145
- const showCloseButton = showClose ?? overlay;
146
- const insetX = sheetPaddingXClasses[density][size];
147
- const insetY = sheetPaddingYClasses[density][size];
148
- // With dividers the lines have to reach both edges, so the sheet gives up its
149
- // padding and every section takes it on instead — the same trade PlCard makes.
150
- const sectionClasses = dividers ? `${insetX} ${insetY}` : insetX;
151
- const hasHeader = hasContent(title) || hasContent(description);
152
- const hasActions = hasContent(actions);
153
- const sizeStyle = extent === undefined
154
- ? null
155
- : { [along ? 'width' : 'height']: typeof extent === 'number' ? `${extent}px` : extent };
156
- const panel = cx(panelClasses, sheetBodyClasses[size], edgeClasses[side], rounded ? roundedClasses[side][size] : '', overlay ? overlayShadowClasses : inlineShadowClasses, overlay ? fadeClasses : '', along
157
- ? `h-full max-w-full ${extent === undefined ? extentClasses[size] : ''}`
158
- : `w-full ${extent === undefined ? 'max-h-[85%]' : ''}`, dividers ? '' : `${insetY} ${sheetSectionGapClasses[size]}`, className);
159
- // Base UI's parts carry the `aria-labelledby` / `aria-describedby` wiring an
160
- // overlay drawer needs. An inline one is not a dialog and needs none, so it
161
- // gets the plain tags rather than a dialog's parts outside a dialog.
162
- const TitleTag = overlay ? BaseUIDialog.Title : 'h2';
163
- const DescriptionTag = overlay ? BaseUIDialog.Description : 'p';
164
- const contents = (_jsxs(_Fragment, { children: [hasHeader || showCloseButton ? (_jsxs("div", { className: cx('flex shrink-0 items-start gap-3', sectionClasses), children: [_jsxs("div", { className: cx('flex min-w-0 flex-1 flex-col', sheetHeaderGapClasses[size]), children: [hasContent(title) ? (_jsx(TitleTag, { className: cx('m-0 font-semibold', sheetTitleClasses[size]), children: title })) : null, hasContent(description) ? (_jsx(DescriptionTag, { className: cx('m-0 text-(--plass-muted-fg)', metaTextClasses[size]), children: description })) : null] }), showCloseButton ? (overlay ? (_jsx(BaseUIDialog.Close, { "aria-label": closeLabel, className: closeButtonClasses, children: _jsx(CloseIcon, {}) })) : (_jsx("button", { type: "button", "aria-label": closeLabel, className: closeButtonClasses, onClick: () => onOpenChange?.(false), children: _jsx(CloseIcon, {}) }))) : null] })) : null, hasContent(children) ? (_jsx("div", { className: cx('min-h-0 flex-1 overflow-y-auto overscroll-contain', sectionClasses, dividers && (hasHeader || showCloseButton) ? sheetLineClasses : '',
165
- // A scroll container clips at its padding box and a focus ring is
166
- // drawn outside the control that owns it, so a field at the top or
167
- // bottom of an unruled body would have its ring sliced off. The
168
- // padding is room for the ring and the negative margin hands the
169
- // space straight back, so nothing on the sheet moves.
170
- dividers ? '' : '-my-1 py-1'), children: children })) : null, hasActions ? (_jsx("div", { className: cx('flex shrink-0 flex-wrap items-center justify-end gap-2', sectionClasses, dividers ? sheetLineClasses : ''), children: actions })) : null] }));
171
- if (!overlay) {
172
- // An inline drawer is in the flow, so "closed" is "not in the layout".
173
- // There is nothing to animate on the way out: the page around it is what
174
- // moves, and moving the page is not this component's to do.
175
- if (!(open ?? defaultOpen ?? true)) {
176
- return null;
177
- }
178
- return (_jsx("div", { className: panel, style: { ...surfaceSlots(color, 0), ...sizeStyle, ...style }, ...props, children: contents }));
179
- }
180
- return (_jsxs(BaseUIDialog.Root, { open: open, defaultOpen: defaultOpen, modal: modal, disablePointerDismissal: !dismissible, onOpenChange: (next, details) => {
181
- // `disablePointerDismissal` covers the click on the scrim; Escape has no
182
- // prop of its own, so it is cancelled here by the reason it arrives
183
- // with.
184
- if (!dismissible && !next && details.reason === 'escape-key') {
185
- details.cancel();
186
- return;
187
- }
188
- onOpenChange?.(next);
189
- }, children: [trigger ? _jsx(BaseUIDialog.Trigger, { render: trigger }) : null, _jsxs(BaseUIDialog.Portal, { children: [_jsx(BaseUIDialog.Backdrop, { className: `plass-portal ${backdropClasses}` }), _jsx(BaseUIDialog.Viewport, { className: cx('plass-portal fixed inset-0 z-50 flex', viewportClasses[side]), children: _jsx(BaseUIDialog.Popup, { className: panel, style: { ...surfaceSlots(color, 3), ...sizeStyle, ...style }, ...props, children: contents }) })] })] }));
190
- }
1
+ "use client";import{jsx as s,jsxs as l,Fragment as e}from"react/jsx-runtime";import{Dialog as r}from"@base-ui/react/dialog";import{CloseIcon as a}from"../../internal/icons.js";import{cx as o,focusRingClasses as d,glassClasses as i,hasContent as t,metaTextClasses as n,sheetBodyClasses as u,sheetHeaderGapClasses as p,sheetLineClasses as m,sheetPaddingXClasses as c,sheetPaddingYClasses as x,sheetSectionGapClasses as f,sheetTitleClasses as g,surfaceSlots as h}from"../../internal/styles.js";const b={xs:"w-56",sm:"w-64",md:"w-80",lg:"w-96",xl:"w-[28rem]"},v={left:{xs:"rounded-r-(--plass-radius-xs)",sm:"rounded-r-(--plass-radius-sm)",md:"rounded-r-(--plass-radius-md)",lg:"rounded-r-(--plass-radius-lg)",xl:"rounded-r-(--plass-radius-xl)"},right:{xs:"rounded-l-(--plass-radius-xs)",sm:"rounded-l-(--plass-radius-sm)",md:"rounded-l-(--plass-radius-md)",lg:"rounded-l-(--plass-radius-lg)",xl:"rounded-l-(--plass-radius-xl)"},top:{xs:"rounded-b-(--plass-radius-xs)",sm:"rounded-b-(--plass-radius-sm)",md:"rounded-b-(--plass-radius-md)",lg:"rounded-b-(--plass-radius-lg)",xl:"rounded-b-(--plass-radius-xl)"},bottom:{xs:"rounded-t-(--plass-radius-xs)",sm:"rounded-t-(--plass-radius-sm)",md:"rounded-t-(--plass-radius-md)",lg:"rounded-t-(--plass-radius-lg)",xl:"rounded-t-(--plass-radius-xl)"}},y={left:"border-r",right:"border-l",top:"border-b",bottom:"border-t"},w={left:"flex-row justify-start",right:"flex-row justify-end",top:"flex-col justify-start",bottom:"flex-col justify-end"},j=/* @__PURE__ */[i,"relative flex flex-col overflow-hidden","text-(--plass-fg) bg-(--plass-glass-press)","[border-color:var(--plass-glass-line)]","[outline:none]"].join(" "),N=/* @__PURE__ */["[transition:opacity_var(--plass-duration)_var(--plass-ease)]","data-[starting-style]:opacity-0 data-[ending-style]:opacity-0"].join(" "),k=/* @__PURE__ */["fixed inset-0 z-50 bg-(--plass-scrim)","[backdrop-filter:blur(2px)] [-webkit-backdrop-filter:blur(2px)]",N].join(" "),C=/* @__PURE__ */["flex size-[1.6em] shrink-0 cursor-pointer items-center justify-center","rounded-full text-(--plass-muted-fg)","[&_svg]:size-[1.1em] [&_svg]:shrink-0","[transition:background-color_var(--plass-duration)_var(--plass-ease),color_var(--plass-duration)_var(--plass-ease)]","hover:bg-(--p-soft) hover:text-(--plass-fg)",d].join(" ");export const PlDrawerClose=r.Close;export function PlDrawer({side:d="left",mode:i="overlay",size:_="md",color:$="primary",density:z="default",open:D,defaultOpen:P,onOpenChange:O,trigger:T,title:B,description:F,actions:L,dividers:R=!1,showClose:V,closeLabel:q="Close",extent:A,rounded:E=!0,modal:G=!0,dismissible:H=!0,className:I,style:J,children:K,...M}){const Q="overlay"===i,S="left"===d||"right"===d,U=V??Q,W=c[z][_],X=x[z][_],Y=R?`${W} ${X}`:W,Z=t(B)||t(F),ss=t(L),ls=void 0===A?null:{[S?"width":"height"]:"number"==typeof A?`${A}px`:A},es=o(j,u[_],y[d],E?v[d][_]:"",Q?"[box-shadow:var(--plass-shadow-4),var(--plass-gloss-glass)]":"[box-shadow:var(--plass-gloss-glass)]",Q?N:"",S?`h-full max-w-full ${void 0===A?b[_]:""}`:"w-full "+(void 0===A?"max-h-[85%]":""),R?"":`${X} ${f[_]}`,I),rs=Q?r.Title:"h2",as=Q?r.Description:"p",os=l(e,{children:[Z||U?l("div",{className:o("flex shrink-0 items-start gap-3",Y),children:[l("div",{className:o("flex min-w-0 flex-1 flex-col",p[_]),children:[t(B)?s(rs,{className:o("m-0 font-semibold",g[_]),children:B}):null,t(F)?s(as,{className:o("m-0 text-(--plass-muted-fg)",n[_]),children:F}):null]}),U?Q?s(r.Close,{"aria-label":q,className:C,children:s(a,{})}):s("button",{type:"button","aria-label":q,className:C,onClick:()=>O?.(!1),children:s(a,{})}):null]}):null,t(K)?s("div",{className:o("min-h-0 flex-1 overflow-y-auto overscroll-contain",Y,R&&(Z||U)?m:"",R?"":"-my-1 py-1"),children:K}):null,ss?s("div",{className:o("flex shrink-0 flex-wrap items-center justify-end gap-2",Y,R?m:""),children:L}):null]});return Q?l(r.Root,{open:D,defaultOpen:P,modal:G,disablePointerDismissal:!H,onOpenChange:(s,l)=>{H||s||"escape-key"!==l.reason?O?.(s):l.cancel()},children:[T?s(r.Trigger,{render:T}):null,l(r.Portal,{children:[s(r.Backdrop,{className:`plass-portal ${k}`}),s(r.Viewport,{className:o("plass-portal fixed inset-0 z-50 flex",w[d]),children:s(r.Popup,{className:es,style:{...h($,3),...ls,...J},...M,children:os})})]})]}):D??P??!0?s("div",{className:es,style:{...h($,0),...ls,...J},...M,children:os}):null}
@@ -1 +1 @@
1
- export { PlDrawer, PlDrawerClose } from './PlDrawer.js';
1
+ export{PlDrawer,PlDrawerClose}from"./PlDrawer.js";