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,126 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { Field } from '@base-ui/react/field';
4
- import { Input } from '@base-ui/react/input';
5
- import { Spinner } from '../../internal/icons.js';
6
- import { controlHeightClasses, controlTextLeadingClasses, disabledClasses, fieldReadOnlyClasses, fieldRestClasses, focusWithinRingClasses, gapClasses, hasContent, iconClasses, metaTextClasses, paddingXClasses, radiusClasses, stackGapClasses, surfaceSlots, transitionClasses } from '../../internal/styles.js';
7
- /**
8
- * Type scale and radius, shared by both modes. The line height is explicit here
9
- * rather than `leading-none` as on PlButton, because in multiline mode it is what
10
- * decides the height of a row — and it has to agree with the single-line
11
- * heights below or a one-row textarea would not line up with an input.
12
- */
13
- const sizeClasses = {
14
- xs: `${gapClasses.xs} ${radiusClasses.xs} ${controlTextLeadingClasses.xs}`,
15
- sm: `${gapClasses.sm} ${radiusClasses.sm} ${controlTextLeadingClasses.sm}`,
16
- md: `${gapClasses.md} ${radiusClasses.md} ${controlTextLeadingClasses.md}`,
17
- lg: `${gapClasses.lg} ${radiusClasses.lg} ${controlTextLeadingClasses.lg}`,
18
- xl: `${gapClasses.xl} ${radiusClasses.xl} ${controlTextLeadingClasses.xl}`
19
- };
20
- /**
21
- * Multiline cannot use a fixed height — `rows` decides it. Instead the vertical
22
- * padding is `(height - border - line-height) / 2`, which makes a one-row
23
- * textarea exactly as tall as the single-line field of the same size. The
24
- * `min-h-*` catches the variants that carry no border.
25
- *
26
- * These are keyed by `size` and never by `density`: density is horizontal
27
- * padding only, and letting it touch this would make the same `rows` produce
28
- * two different heights.
29
- */
30
- const multilineClasses = {
31
- xs: 'min-h-6 py-[3px]',
32
- sm: 'min-h-8 py-[6px]',
33
- md: 'min-h-10 py-[9px]',
34
- lg: 'min-h-12 py-[11px]',
35
- xl: 'min-h-14 py-[13px]'
36
- };
37
- const resizeClasses = {
38
- none: 'resize-none',
39
- vertical: 'resize-y',
40
- horizontal: 'resize-x',
41
- both: 'resize'
42
- };
43
- const shellBaseClasses = /* @__PURE__ */ [
44
- // `group` so the adornments can answer the control's focus; `cursor-text`
45
- // because the whole shell behaves as the field, padding included.
46
- 'group relative flex w-full cursor-text',
47
- '[-webkit-tap-highlight-color:transparent]',
48
- transitionClasses,
49
- // The ring belongs to the shell, not to the control inside it, so it traces
50
- // the glass edge rather than a rectangle floating inside it.
51
- focusWithinRingClasses,
52
- iconClasses
53
- ].join(' ');
54
- /**
55
- * The shell, the read-only treatment and the disabled treatment are the ones
56
- * `internal/styles` defines for every field-shaped control — a Select's trigger
57
- * is drawn on exactly the same box, and the two have to be indistinguishable.
58
- */
59
- const restClasses = fieldRestClasses;
60
- const readOnlyClasses = fieldReadOnlyClasses;
61
- export const PlTextField = /* @__PURE__ */ React.forwardRef(function PlTextField({ variant = 'glass', size = 'md', color = 'primary', density = 'default', elevation = 0, multiline = false, rows = 3, resize = 'vertical', label, description, error, invalid, startIcon, endIcon, loading = false, fullWidth = false, readOnly = false, disabled = false, type = 'text', className, style, ...props }, ref) {
62
- const hasError = hasContent(error);
63
- const isInvalid = invalid ?? hasError;
64
- // Invalid re-points the whole slot family at `danger`, so the edge, the ring,
65
- // the caret and the message all turn over together and no state needs its own
66
- // set of tokens.
67
- const family = isInvalid ? 'danger' : color;
68
- const controlRef = React.useRef(null);
69
- const setControlRef = React.useCallback((node) => {
70
- controlRef.current = node;
71
- if (typeof ref === 'function') {
72
- ref(node);
73
- }
74
- else if (ref) {
75
- ref.current = node;
76
- }
77
- }, [ref]);
78
- const shellClasses = [
79
- shellBaseClasses,
80
- sizeClasses[size],
81
- multiline
82
- ? `${multilineClasses[size]} items-start`
83
- : `${controlHeightClasses[size]} items-center`,
84
- paddingXClasses[density][size],
85
- // An if/else rather than stacked `data-*` variants: two Tailwind variants
86
- // of equal specificity resolve by their order in the generated stylesheet.
87
- disabled ? disabledClasses[variant] : readOnly ? readOnlyClasses[variant] : restClasses[variant]
88
- ]
89
- .filter(Boolean)
90
- .join(' ');
91
- const controlClasses = [
92
- 'min-w-0 flex-1 bg-transparent [font:inherit] text-inherit',
93
- // Not `outline-none`: that utility zeroes `--tw-outline-style`, and the
94
- // shell's focus ring is drawn with the same variable family. The shorthand
95
- // takes the outline off this element and leaves the ring alone.
96
- '[outline:none]',
97
- 'placeholder:text-(--plass-muted-fg)',
98
- 'caret-(--p-accent) selection:bg-(--p-soft-press)',
99
- 'disabled:cursor-not-allowed',
100
- multiline ? `block ${resizeClasses[resize]}` : 'self-stretch'
101
- ].join(' ');
102
- // `1lh` keeps an adornment centred on the first line rather than on the whole
103
- // box, which is the only way it stays put when the control grows to 5 rows.
104
- const adornmentClasses = 'inline-flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg) transition-[color] duration-(--plass-duration) group-focus-within:text-(--p-accent)';
105
- return (_jsxs(Field.Root, { disabled: disabled, invalid: isInvalid, className: [
106
- 'flex-col align-top',
107
- stackGapClasses[size],
108
- fullWidth ? 'flex w-full' : 'inline-flex',
109
- className ?? ''
110
- ]
111
- .filter(Boolean)
112
- .join(' '), style: { ...surfaceSlots(family, elevation), ...style }, children: [label ? (_jsx(Field.Label, { className: [
113
- metaTextClasses[size],
114
- 'font-semibold',
115
- disabled ? 'text-(--plass-muted-fg)' : 'text-(--plass-fg)'
116
- ].join(' '), children: label })) : null, _jsxs("span", { className: shellClasses, onPointerDown: (event) => {
117
- // Clicking the shell's own padding should put the caret in the field,
118
- // the way clicking anywhere inside a native input does. Only when the
119
- // shell itself was hit — a click on the control or on an adornment is
120
- // left alone so text selection still works.
121
- if (event.target === event.currentTarget && !disabled) {
122
- event.preventDefault();
123
- controlRef.current?.focus();
124
- }
125
- }, children: [startIcon ? _jsx("span", { className: adornmentClasses, children: startIcon }) : null, _jsx(Input, { ref: setControlRef, className: controlClasses, disabled: disabled, readOnly: readOnly, "aria-busy": loading || undefined, "data-loading": loading || undefined, ...(multiline ? { render: _jsx("textarea", { rows: rows }) } : { type }), ...props }), loading ? (_jsx("span", { className: adornmentClasses, children: _jsx(Spinner, {}) })) : endIcon ? (_jsx("span", { className: adornmentClasses, children: endIcon })) : null] }), description ? (_jsx(Field.Description, { className: [metaTextClasses[size], 'text-(--plass-muted-fg)'].join(' '), children: description })) : null, hasError ? (_jsx(Field.Error, { match: true, className: [metaTextClasses[size], 'text-(--p-accent)'].join(' '), children: error })) : null] }));
126
- });
1
+ "use client";import{jsx as e,jsxs as t}from"react/jsx-runtime";import*as l from"react";import{Field as n}from"@base-ui/react/field";import{Input as s}from"@base-ui/react/input";import{Spinner as r}from"../../internal/icons.js";import{controlHeightClasses as i,controlTextLeadingClasses as a,disabledClasses as o,fieldReadOnlyClasses as c,fieldRestClasses as d,focusWithinRingClasses as m,gapClasses as p,hasContent as u,iconClasses as x,metaTextClasses as f,paddingXClasses as h,radiusClasses as g,stackGapClasses as $,surfaceSlots as y,transitionClasses as b}from"../../internal/styles.js";const j={xs:`${p.xs} ${g.xs} ${a.xs}`,sm:`${p.sm} ${g.sm} ${a.sm}`,md:`${p.md} ${g.md} ${a.md}`,lg:`${p.lg} ${g.lg} ${a.lg}`,xl:`${p.xl} ${g.xl} ${a.xl}`},v={xs:"min-h-6 py-[3px]",sm:"min-h-8 py-[6px]",md:"min-h-10 py-[9px]",lg:"min-h-12 py-[11px]",xl:"min-h-14 py-[13px]"},w={none:"resize-none",vertical:"resize-y",horizontal:"resize-x",both:"resize"},N=/* @__PURE__ */["group relative flex w-full cursor-text","[-webkit-tap-highlight-color:transparent]",b,m,x].join(" "),z=d,k=c;export const PlTextField=/* @__PURE__ */l.forwardRef(function PlTextField({variant:a="glass",size:c="md",color:d="primary",density:m="default",elevation:p=0,multiline:x=!1,rows:g=3,resize:b="vertical",label:D,description:P,error:R,invalid:T,startIcon:B,endIcon:F,loading:I=!1,fullWidth:O=!1,readOnly:C=!1,disabled:E=!1,type:L="text",className:W,style:q,...A},G){const H=u(R),J=T??H,K=J?"danger":d,M=l.useRef(null),Q=l.useCallback(e=>{M.current=e,"function"==typeof G?G(e):G&&(G.current=e)},[G]),S=[N,j[c],x?`${v[c]} items-start`:`${i[c]} items-center`,h[m][c],E?o[a]:C?k[a]:z[a]].filter(Boolean).join(" "),U=["min-w-0 flex-1 bg-transparent [font:inherit] text-inherit","[outline:none]","placeholder:text-(--plass-muted-fg)","caret-(--p-accent) selection:bg-(--p-soft-press)","disabled:cursor-not-allowed",x?`block ${w[b]}`:"self-stretch"].join(" "),V="inline-flex h-[1lh] shrink-0 items-center text-(--plass-muted-fg) transition-[color] duration-(--plass-duration) group-focus-within:text-(--p-accent)";return t(n.Root,{disabled:E,invalid:J,className:["flex-col align-top",$[c],O?"flex w-full":"inline-flex",W??""].filter(Boolean).join(" "),style:{...y(K,p),...q},children:[D?e(n.Label,{className:[f[c],"font-semibold",E?"text-(--plass-muted-fg)":"text-(--plass-fg)"].join(" "),children:D}):null,t("span",{className:S,onPointerDown:e=>{e.target!==e.currentTarget||E||(e.preventDefault(),M.current?.focus())},children:[B?e("span",{className:V,children:B}):null,e(s,{ref:Q,className:U,disabled:E,readOnly:C,"aria-busy":I||void 0,"data-loading":I||void 0,...x?{render:e("textarea",{rows:g})}:{type:L},...A}),I?e("span",{className:V,children:e(r,{})}):F?e("span",{className:V,children:F}):null]}),P?e(n.Description,{className:[f[c],"text-(--plass-muted-fg)"].join(" "),children:P}):null,H?e(n.Error,{match:!0,className:[f[c],"text-(--p-accent)"].join(" "),children:R}):null]})});
@@ -1 +1 @@
1
- export { PlTextField } from './PlTextField.js';
1
+ export{PlTextField}from"./PlTextField.js";
@@ -1,136 +1 @@
1
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { useRender } from '@base-ui/react/use-render';
4
- import { ExternalLinkIcon, LinkIcon } from '../../internal/icons.js';
5
- import { controlTextLeadingClasses, focusRingClasses, srOnlyClasses } from '../../internal/styles.js';
6
- /**
7
- * Whether the line is drawn, and — with the colour below — the only two things
8
- * about a link that a prop changes. Everything else about the line is in
9
- * `styles.css`, under `.plass-link`.
10
- *
11
- * Every utility here is written through `[&.plass-link]`, which doubles the
12
- * component's own class into the selector and takes it to two classes. That is
13
- * not decoration: `<a>` is, with `<td>`, one of the two tags a host stylesheet
14
- * still styles by name — `.prose a`, `.vp-doc a`, every CSS framework — and all
15
- * of those are a class plus a type, which outranks a plain utility. A link that
16
- * lost its colour and its line inside a `.prose` block would have lost the only
17
- * two things it is.
18
- *
19
- * Hover deliberately leaves the *text* colour alone. A link inside running
20
- * prose that changes colour under the pointer drags the reader's eye off the
21
- * line they were reading — the same rule the library applies to a control's
22
- * label, on the one component that lives inside a sentence.
23
- */
24
- const underlineClasses = {
25
- always: '[&.plass-link]:underline',
26
- hover: '[&.plass-link]:no-underline [&.plass-link]:hover:underline',
27
- // Nothing to hover, on purpose. A link with no line and no colour is a link
28
- // whose surroundings are saying what it is.
29
- none: '[&.plass-link]:no-underline'
30
- };
31
- /**
32
- * Only two properties move, so this is written out rather than taken from
33
- * `transitionClasses` — the house list has no `text-decoration-color` in it,
34
- * and adding one there would put a property on every control in the library
35
- * that no control draws.
36
- */
37
- const transition = /* @__PURE__ */ [
38
- '[transition-property:color,text-decoration-color]',
39
- '[transition-duration:var(--plass-duration)]',
40
- '[transition-timing-function:var(--plass-ease)]'
41
- ].join(' ');
42
- const baseClasses = /* @__PURE__ */ [
43
- // Both a style hook and the specificity. `styles.css` doubles this class to
44
- // write the parts of the line that never vary — its thickness, its offset,
45
- // its colour — above whatever the host page says about an `<a>`, and every
46
- // utility that *does* vary is written through it for the same reason.
47
- 'plass-link',
48
- 'cursor-pointer',
49
- // The glyph rides on the label at just under its cap height, rather than at
50
- // the `1.2em` an icon inside a control takes: this one sits in a sentence,
51
- // and an icon as tall as the line spaces the words around it apart.
52
- '[&_svg]:pointer-events-none [&_svg]:inline [&_svg]:size-[0.95em] [&_svg]:shrink-0',
53
- transition,
54
- focusRingClasses,
55
- 'focus-visible:rounded-[0.25rem]'
56
- ].join(' ');
57
- /**
58
- * A link, in a sentence or on its own.
59
- *
60
- * Everything about it is deliberately smaller than a PlButton. It has no
61
- * surface, no height of its own and no colour unless asked — what it has is a
62
- * line under it, which is the one mark a reader already knows means "this goes
63
- * somewhere".
64
- *
65
- * The three things it does that a bare `<a>` does not: it draws that line on a
66
- * schedule (`always`, or only under the pointer), it marks a link that opens a
67
- * new tab both visibly and for a screen reader, and it takes `render`, so the
68
- * `Link` a router brings can wear all of it.
69
- */
70
- export const PlTextLink = /* @__PURE__ */ React.forwardRef(function PlTextLink({ href, underline = 'always', color, size, newTab = false, icon, newTabLabel = '(opens in a new tab)', render, className, style, children, ...props }, ref) {
71
- // `icon` left out follows `newTab`, which is the whole reason it is not a
72
- // plain boolean with a `false` default: a link that takes over the window
73
- // should say so, and a caller should have to ask for the silent version.
74
- const mark = icon ?? newTab;
75
- const glyph = mark === true ? newTab ? _jsx(ExternalLinkIcon, {}) : _jsx(LinkIcon, {}) : mark;
76
- const classNames = [
77
- baseClasses,
78
- size ? controlTextLeadingClasses[size] : '',
79
- underlineClasses[underline],
80
- color ? '[&.plass-link]:text-(--p-accent)' : '[&.plass-link]:text-inherit',
81
- className ?? ''
82
- ]
83
- .filter(Boolean)
84
- .join(' ');
85
- /*
86
- * The two line colours and the focus ring, as slots.
87
- *
88
- * `--p-ring` is set even when no family was asked for, because the ring is
89
- * written as the `outline` shorthand and an undefined `var()` inside it
90
- * makes the browser drop the whole declaration — an uncoloured link would
91
- * lose its focus ring entirely rather than fall back to something plainer.
92
- *
93
- * The line rests at 45% of whatever the text is and goes to the full colour
94
- * on hover, so it works the same on an inherited colour as on an accent one.
95
- */
96
- const slots = {
97
- '--p-underline': 'color-mix(in oklab, currentColor 45%, transparent)',
98
- '--p-underline-hover': 'currentColor',
99
- '--p-ring': `var(--plass-${color ?? 'primary'}-ring)`,
100
- ...(color ? { '--p-accent': `var(--plass-${color}-accent)` } : null)
101
- };
102
- /*
103
- * `rel` is the one thing here a caller's own value is merged with rather
104
- * than replaced by, and the reason is that the two purposes of the
105
- * attribute have nothing to do with each other.
106
- *
107
- * `noopener` is what stops the new page reaching back through
108
- * `window.opener`; `noreferrer` sits beside it for the browsers that still
109
- * need the pair. The common reason to write a `rel` by hand is `nofollow`
110
- * or `sponsored`, which is an SEO decision — and spelled as a plain
111
- * override it would silently take the protection off a link that still
112
- * opens in a new tab. Whatever was asked for is kept, with the two tokens
113
- * added if they are not already there.
114
- */
115
- const { rel: askedFor, ...rest } = props;
116
- const rel = newTab
117
- ? [
118
- ...new Set([...(askedFor ?? '').split(/\s+/).filter(Boolean), 'noopener', 'noreferrer'])
119
- ].join(' ')
120
- : askedFor;
121
- return useRender({
122
- render: render ?? _jsx("a", {}),
123
- ref,
124
- props: {
125
- href,
126
- target: newTab ? '_blank' : undefined,
127
- className: classNames,
128
- style: { ...slots, ...style },
129
- children: (_jsxs(_Fragment, { children: [children, glyph ? _jsx("span", { className: "ms-[0.25em]", children: glyph }) : null, newTab ? (_jsxs(_Fragment, { children: [' ', _jsx("span", { className: srOnlyClasses, children: newTabLabel })] })) : null] })),
130
- ...rest,
131
- // After the spread on purpose: this is the merge above, not an override
132
- // for a caller to win.
133
- rel
134
- }
135
- });
136
- });
1
+ "use client";import{jsx as n,Fragment as e,jsxs as r}from"react/jsx-runtime";import*as s from"react";import{useRender as i}from"@base-ui/react/use-render";import{ExternalLinkIcon as l,LinkIcon as o}from"../../internal/icons.js";import{controlTextLeadingClasses as a,focusRingClasses as t,srOnlyClasses as c}from"../../internal/styles.js";const p={always:"[&.plass-link]:underline",hover:"[&.plass-link]:no-underline [&.plass-link]:hover:underline",none:"[&.plass-link]:no-underline"},u=/* @__PURE__ */["plass-link","cursor-pointer","[&_svg]:pointer-events-none [&_svg]:inline [&_svg]:size-[0.95em] [&_svg]:shrink-0",/* @__PURE__ */["[transition-property:color,text-decoration-color]","[transition-duration:var(--plass-duration)]","[transition-timing-function:var(--plass-ease)]"].join(" "),t,"focus-visible:rounded-[0.25rem]"].join(" ");export const PlTextLink=/* @__PURE__ */s.forwardRef(function PlTextLink({href:s,underline:t="always",color:d,size:m,newTab:f=!1,icon:v,newTabLabel:h="(opens in a new tab)",render:k,className:x,style:g,children:j,...b},w){const y=v??f,_=!0===y?n(f?l:o,{}):y,N=[u,m?a[m]:"",p[t],d?"[&.plass-link]:text-(--p-accent)":"[&.plass-link]:text-inherit",x??""].filter(Boolean).join(" "),T={"--p-underline":"color-mix(in oklab, currentColor 45%, transparent)","--p-underline-hover":"currentColor","--p-ring":`var(--plass-${d??"primary"}-ring)`,...d?{"--p-accent":`var(--plass-${d}-accent)`}:null},{rel:L,...z}=b,B=f?[...new Set([...(L??"").split(/\s+/).filter(Boolean),"noopener","noreferrer"])].join(" "):L;return i({render:k??n("a",{}),ref:w,props:{href:s,target:f?"_blank":void 0,className:N,style:{...T,...g},children:r(e,{children:[j,_?n("span",{className:"ms-[0.25em]",children:_}):null,f?r(e,{children:[" ",n("span",{className:c,children:h})]}):null]}),...z,rel:B}})});
@@ -1 +1 @@
1
- export { PlTextLink } from './PlTextLink.js';
1
+ export{PlTextLink}from"./PlTextLink.js";
@@ -1,97 +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 { TimeGrid, usePickerLabels } from '../../internal/calendar.js';
5
- import { ClockIcon } from '../../internal/icons.js';
6
- import { PickerFooter, PickerShell } from '../../internal/picker.js';
7
- import { displaySamples, formatDate, isHour12, isValidDate, secondsOfDay, timeUnitSpan, toISOTime, withPlaceholder, withTime } from '../../internal/date.js';
8
- import { cx } from '../../internal/styles.js';
9
- /**
10
- * A time of day, chosen from columns.
11
- *
12
- * Columns because they are the shape that answers what a time picker is actually
13
- * asked: "half past nine" is two glances, and "any time at all, on the hour" is
14
- * a column you never touch. A clock face is prettier and needs a `transform` to
15
- * read, which this library does not have.
16
- *
17
- * The bounds are checked at the granularity of the column being drawn, which is
18
- * the detail that separates a working time picker from a frustrating one. With a
19
- * `minTime` of 09:30 the hour `9` stays available — the hour *contains* allowed
20
- * minutes — and it is the minute column that greys out `00` through `25`. The
21
- * naive check compares the whole candidate instant, hides the 9 entirely, and
22
- * makes half past nine unreachable.
23
- *
24
- * The value is a `Date` rather than a string or a number of minutes, because
25
- * everything else in this library that carries a moment is one, and because a
26
- * time on its own has nowhere to record that it crossed a DST boundary.
27
- * `referenceDate` is the day a bare time is written onto.
28
- */
29
- export const PlTimePicker = /* @__PURE__ */ React.forwardRef(function PlTimePicker({ value: valueProp, defaultValue, onValueChange, open: openProp, defaultOpen, onOpenChange, referenceDate, minTime, maxTime, shouldDisableTime, hour12: hour12Prop, showSeconds = false, hourStep = 1, minuteStep = 1, secondStep = 1, locale, format, placeholder, clearable = false, showNowButton = true, closeOnSelect = false, labels: labelOverrides, name, size = 'md', color = 'primary', density = 'default', readOnly = false, disabled = false, startIcon, ...shell }, ref) {
30
- const labels = usePickerLabels(labelOverrides);
31
- const hour12 = hour12Prop ?? isHour12(locale);
32
- const [uncontrolledValue, setUncontrolledValue] = React.useState(defaultValue ?? null);
33
- const value = valueProp !== undefined ? valueProp : uncontrolledValue;
34
- const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen ?? false);
35
- const open = openProp ?? uncontrolledOpen;
36
- // Held still for as long as the picker is mounted, so a popup left open
37
- // across midnight does not quietly move the value it is writing onto a new
38
- // day.
39
- const [fallbackDay] = React.useState(() => referenceDate ?? new Date());
40
- const setOpen = (next) => {
41
- if (next && (readOnly || disabled)) {
42
- return;
43
- }
44
- if (openProp === undefined) {
45
- setUncontrolledOpen(next);
46
- }
47
- onOpenChange?.(next);
48
- };
49
- const commit = (next) => {
50
- if (valueProp === undefined) {
51
- setUncontrolledValue(next);
52
- }
53
- onValueChange?.(next);
54
- };
55
- const isBlocked = React.useCallback((candidate, unit) => {
56
- const [from, to] = timeUnitSpan(unit, candidate);
57
- if (isValidDate(minTime) && to < secondsOfDay(minTime)) {
58
- return true;
59
- }
60
- if (isValidDate(maxTime) && from > secondsOfDay(maxTime)) {
61
- return true;
62
- }
63
- return shouldDisableTime?.(candidate, unit) ?? false;
64
- }, [minTime, maxTime, shouldDisableTime]);
65
- /* Memoised because `samples` below is keyed on it, and the fallback is a
66
- fresh object every render — which is the case that runs by default, since
67
- `format` is optional. Left bare, the sizer re-formatted all twenty-four
68
- sample instants on every render the picker saw. */
69
- const displayFormat = React.useMemo(() => format ?? {
70
- hour: 'numeric',
71
- minute: '2-digit',
72
- ...(showSeconds ? { second: '2-digit' } : {})
73
- }, [format, showSeconds]);
74
- const now = new Date();
75
- const nowValue = withTime(referenceDate ?? fallbackDay, {
76
- hours: now.getHours(),
77
- minutes: now.getMinutes(),
78
- seconds: showSeconds ? now.getSeconds() : 0
79
- });
80
- const hasFooter = showNowButton || clearable || !closeOnSelect;
81
- // Holds the trigger open at the width of the longest time it could show.
82
- const samples = React.useMemo(() => withPlaceholder(displaySamples(locale, displayFormat), placeholder), [locale, displayFormat, placeholder]);
83
- return (_jsx(PickerShell, { ...shell, size: size, color: color, density: density, readOnly: readOnly, disabled: disabled, triggerRef: ref, startIcon: startIcon ?? _jsx(ClockIcon, {}), display: isValidDate(value) ? formatDate(value, locale, displayFormat) : (placeholder ?? ''), samples: samples, empty: !isValidDate(value), clearable: clearable, onClear: () => commit(null), open: open, onOpenChange: setOpen, labels: labels, hiddenValues: name
84
- ? [{ name, value: isValidDate(value) ? toISOTime(value, showSeconds) : '' }]
85
- : undefined, children: _jsxs("div", { className: cx('flex flex-col', hasFooter && 'gap-1.5'), children: [_jsx(TimeGrid, { size: size, density: density, locale: locale, value: isValidDate(value) ? value : null, referenceDate: referenceDate ?? fallbackDay, onChange: (next) => {
86
- commit(next);
87
- if (closeOnSelect) {
88
- setOpen(false);
89
- }
90
- }, hour12: hour12, showSeconds: showSeconds, hourStep: hourStep, minuteStep: minuteStep, secondStep: secondStep, shouldDisableTime: isBlocked, labels: labels, autoFocus: true }), hasFooter ? (_jsxs(PickerFooter, { size: size, children: [clearable ? (_jsx(PlButton, { variant: "ghost", size: size, color: color, density: "compact", onClick: () => {
91
- commit(null);
92
- setOpen(false);
93
- }, children: labels.clear })) : null, showNowButton ? (_jsx(PlButton, { variant: "ghost", size: size, color: color, density: "compact", disabled: isBlocked(nowValue, 'second'), onClick: () => {
94
- commit(nowValue);
95
- setOpen(false);
96
- }, children: labels.now })) : null, !closeOnSelect ? (_jsx(PlButton, { variant: "solid", size: size, color: color, density: "compact", onClick: () => setOpen(false), children: labels.done })) : null] })) : null] }) }));
97
- });
1
+ "use client";import{jsx as e,jsxs as n}from"react/jsx-runtime";import*as o from"react";import{PlButton as l}from"../button/PlButton.js";import{TimeGrid as t,usePickerLabels as s}from"../../internal/calendar.js";import{ClockIcon as a}from"../../internal/icons.js";import{PickerFooter as i,PickerShell as r}from"../../internal/picker.js";import{displaySamples as c,formatDate as d,isHour12 as u,isValidDate as m,secondsOfDay as p,timeUnitSpan as h,toISOTime as f,withPlaceholder as g,withTime as S}from"../../internal/date.js";import{cx as b}from"../../internal/styles.js";export const PlTimePicker=/* @__PURE__ */o.forwardRef(function PlTimePicker({value:y,defaultValue:v,onValueChange:j,open:C,defaultOpen:w,onOpenChange:k,referenceDate:x,minTime:z,maxTime:D,shouldDisableTime:O,hour12:T,showSeconds:P=!1,hourStep:M=1,minuteStep:V=1,secondStep:B=1,locale:I,format:N,placeholder:R,clearable:F=!1,showNowButton:H=!0,closeOnSelect:q=!1,labels:A,name:E,size:G="md",color:J="primary",density:K="default",readOnly:L=!1,disabled:Q=!1,startIcon:U,...W},X){const Y=s(A),Z=T??u(I),[$,_]=o.useState(v??null),ee=void 0!==y?y:$,[ne,oe]=o.useState(w??!1),le=C??ne,[te]=o.useState(()=>x??new Date),setOpen=e=>{e&&(L||Q)||(void 0===C&&oe(e),k?.(e))},commit=e=>{void 0===y&&_(e),j?.(e)},se=o.useCallback((e,n)=>{const[o,l]=h(n,e);return!!(m(z)&&l<p(z))||!!(m(D)&&o>p(D))||(O?.(e,n)??!1)},[z,D,O]),ae=o.useMemo(()=>N??{hour:"numeric",minute:"2-digit",...P?{second:"2-digit"}:{}},[N,P]),ie=new Date,re=S(x??te,{hours:ie.getHours(),minutes:ie.getMinutes(),seconds:P?ie.getSeconds():0}),ce=H||F||!q,de=o.useMemo(()=>g(c(I,ae),R),[I,ae,R]);return e(r,{...W,size:G,color:J,density:K,readOnly:L,disabled:Q,triggerRef:X,startIcon:U??e(a,{}),display:m(ee)?d(ee,I,ae):R??"",samples:de,empty:!m(ee),clearable:F,onClear:()=>commit(null),open:le,onOpenChange:setOpen,labels:Y,hiddenValues:E?[{name:E,value:m(ee)?f(ee,P):""}]:void 0,children:n("div",{className:b("flex flex-col",ce&&"gap-1.5"),children:[e(t,{size:G,density:K,locale:I,value:m(ee)?ee:null,referenceDate:x??te,onChange:e=>{commit(e),q&&setOpen(!1)},hour12:Z,showSeconds:P,hourStep:M,minuteStep:V,secondStep:B,shouldDisableTime:se,labels:Y,autoFocus:!0}),ce?n(i,{size:G,children:[F?e(l,{variant:"ghost",size:G,color:J,density:"compact",onClick:()=>{commit(null),setOpen(!1)},children:Y.clear}):null,H?e(l,{variant:"ghost",size:G,color:J,density:"compact",disabled:se(re,"second"),onClick:()=>{commit(re),setOpen(!1)},children:Y.now}):null,q?null:e(l,{variant:"solid",size:G,color:J,density:"compact",onClick:()=>setOpen(!1),children:Y.done})]}):null]})})});
@@ -1 +1 @@
1
- export { PlTimePicker } from './PlTimePicker.js';
1
+ export{PlTimePicker}from"./PlTimePicker.js";
@@ -1,207 +1 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import * as React from 'react';
3
- import { useRender } from '@base-ui/react/use-render';
4
- import { cx, hasContent, iconClasses, metaTextClasses, sheetBodyClasses, sheetTitleClasses, surfaceSlots, transitionClasses } from '../../internal/styles.js';
5
- const TimelineContext = /* @__PURE__ */ React.createContext(null);
6
- const TimelineItemContext = /* @__PURE__ */ React.createContext({
7
- index: 0,
8
- last: false
9
- });
10
- /* ---------------------------------------------------------------------------
11
- * Scales
12
- * ------------------------------------------------------------------------- */
13
- /**
14
- * The bullet.
15
- *
16
- * Its own ladder rather than a step off `controlHeightClasses`, for the reason
17
- * `tickSizeClasses` has one: a bullet is not a control you can put a label
18
- * inside. It is a mark beside one, sized against the title next to it — which is
19
- * why the steps are close to the tick ladder and not to the control ladder.
20
- *
21
- * It is written as a custom property rather than as a class because the
22
- * connector has to know it: the line is centred on the bullet, and centring is
23
- * arithmetic on this number.
24
- */
25
- const bulletSizeValues = {
26
- xs: '0.875rem',
27
- sm: '1rem',
28
- md: '1.25rem',
29
- lg: '1.5rem',
30
- xl: '1.875rem'
31
- };
32
- /** Between the bullet column and the content beside it. */
33
- const bulletGapClasses = {
34
- xs: 'gap-2',
35
- sm: 'gap-2.5',
36
- md: 'gap-3',
37
- lg: 'gap-3.5',
38
- xl: 'gap-4'
39
- };
40
- /**
41
- * How far apart two items sit, and the one thing `density` is allowed to touch
42
- * here — a compact timeline is the same type at the same bullet size with less
43
- * air between the steps.
44
- *
45
- * The floor is set by the item with nothing in it. A step that is only a title
46
- * and a time is one line tall, so the gap is the *whole* of what separates it
47
- * from the next one — where a step with a paragraph under it has the paragraph's
48
- * own leading working for it as well. Tuned against that case, which is why even
49
- * `compact` keeps more air than a list of one-liners would otherwise suggest.
50
- */
51
- const itemGapClasses = {
52
- default: { xs: 'pb-5', sm: 'pb-6', md: 'pb-7', lg: 'pb-8', xl: 'pb-10' },
53
- compact: { xs: 'pb-3', sm: 'pb-3.5', md: 'pb-4', lg: 'pb-5', xl: 'pb-6' }
54
- };
55
- /** The same ladder across, for the horizontal form. */
56
- const itemGapXClasses = {
57
- default: { xs: 'pe-5', sm: 'pe-6', md: 'pe-7', lg: 'pe-8', xl: 'pe-10' },
58
- compact: { xs: 'pe-3', sm: 'pe-3.5', md: 'pe-4', lg: 'pe-5', xl: 'pe-6' }
59
- };
60
- const borderStyleClasses = {
61
- solid: 'border-solid',
62
- dashed: 'border-dashed',
63
- dotted: 'border-dotted',
64
- none: ''
65
- };
66
- /**
67
- * The bullet at each of the three states.
68
- *
69
- * Every one of them is a different axis, never a different opacity: `complete`
70
- * is the family's gradient, `current` is that gradient with a halo of the soft
71
- * tint around it, and `upcoming` is a hairline ring on the page's own surface. A
72
- * reader who cannot tell the colours apart still has a filled shape, a haloed
73
- * shape and an empty one.
74
- *
75
- * There is no gloss line on the two filled ones, for the reason a filled
76
- * `PlButton` has none — the gradient is the form. The `upcoming` ring is drawn
77
- * in the neutral hairline rather than the sheet's white one, the same call a
78
- * checkbox's edge makes: a bullet is small enough that its edge *is* the object,
79
- * and white light on a translucent pane disappears on a light card.
80
- */
81
- const bulletStatusClasses = {
82
- complete: '[background-image:var(--p-fill)] text-(--p-on-solid)',
83
- current: '[background-image:var(--p-fill)] text-(--p-on-solid) [box-shadow:0_0_0_0.25rem_var(--p-soft)]',
84
- upcoming: 'border-2 bg-(--plass-surface) text-(--plass-muted-fg) [border-color:var(--plass-border)]'
85
- };
86
- /**
87
- * The line *after* an item, which is what makes it the item's own property: a
88
- * connector is coloured by whether the step it leaves has been reached, not by
89
- * where it arrives.
90
- */
91
- const connectorColorClasses = {
92
- complete: '[border-color:var(--p-line-hover)]',
93
- current: '[border-color:var(--plass-border)]',
94
- upcoming: '[border-color:var(--plass-border)]'
95
- };
96
- const titleStatusClasses = {
97
- complete: 'text-(--plass-fg)',
98
- current: 'text-(--p-accent)',
99
- upcoming: 'text-(--plass-muted-fg)'
100
- };
101
- /**
102
- * One step.
103
- *
104
- * Its index is not a prop and cannot be: an item that had to be told where it
105
- * was in the list would be an item every caller could put in the wrong place,
106
- * and `active={2}` would stop meaning anything. The `PlTimeline` numbers its
107
- * children as it walks them, and hands each one its index through a context.
108
- */
109
- export const PlTimelineItem = /* @__PURE__ */ React.forwardRef(function PlTimelineItem({ title, meta, bullet, status, color, connector = 'solid', className, children, ...props }, ref) {
110
- const timeline = React.useContext(TimelineContext);
111
- const { index, last } = React.useContext(TimelineItemContext);
112
- // A bare item outside a timeline still renders — it is just one step with
113
- // nothing before or after it. The defaults are the timeline's own.
114
- const size = timeline?.size ?? 'md';
115
- const density = timeline?.density ?? 'default';
116
- const orientation = timeline?.orientation ?? 'vertical';
117
- const family = color ?? timeline?.color ?? 'primary';
118
- const active = timeline?.active ?? null;
119
- const resolved = status ??
120
- (active === null
121
- ? 'upcoming'
122
- : index < active
123
- ? 'complete'
124
- : index === active
125
- ? 'current'
126
- : 'upcoming');
127
- const horizontal = orientation === 'horizontal';
128
- // The last item's line would run off the end of the sequence into nothing.
129
- const drawsConnector = connector !== 'none' && !last;
130
- const bulletBox = (_jsx("span", { "aria-hidden": "true", className: cx('relative z-10 flex shrink-0 items-center justify-center rounded-full',
131
- // The label inside the bullet is sized off the bullet rather than off
132
- // the page's own text, so a number in an `xs` bullet is not the same
133
- // 8px it would be in an `xl` one.
134
- 'size-(--p-bullet) text-[calc(var(--p-bullet)*0.5)] leading-none font-semibold tabular-nums', bulletStatusClasses[resolved], transitionClasses, iconClasses), children: bullet }));
135
- /*
136
- * The line, drawn as one border edge on an absolutely positioned box rather
137
- * than as a filled `<div>`, so `dashed` and `dotted` are the browser's own
138
- * dashes and land on the device pixel grid the way every other edge in the
139
- * library does.
140
- *
141
- * It starts at the far edge of the bullet and runs to the edge of the item,
142
- * which is where the next bullet begins — so the arithmetic is the bullet
143
- * size, and that is the whole reason it is a custom property.
144
- */
145
- const connectorLine = drawsConnector ? (_jsx("span", { "aria-hidden": "true", className: cx('pointer-events-none absolute',
146
- // Half the bullet, less half the line, so the 2px rule is centred on
147
- // the bullet rather than starting at its centre.
148
- horizontal
149
- ? 'top-[calc(var(--p-bullet)/2_-_1px)] end-0 start-(--p-bullet) border-t-2'
150
- : 'top-(--p-bullet) bottom-0 start-[calc(var(--p-bullet)/2_-_1px)] border-s-2', borderStyleClasses[connector], connectorColorClasses[resolved], transitionClasses) })) : null;
151
- const body = (_jsxs("div", { className: cx('flex min-w-0 flex-col gap-0.5', horizontal ? 'mt-2' : ''), children: [hasContent(title) || hasContent(meta) ? (_jsxs("div", { className: "flex flex-wrap items-baseline gap-x-2", children: [hasContent(title) ? (_jsx("span", { className: cx('font-semibold', sheetTitleClasses[size], titleStatusClasses[resolved], transitionClasses), children: title })) : null, hasContent(meta) ? (_jsx("span", { className: cx('text-(--plass-muted-fg)', metaTextClasses[size]), children: meta })) : null] })) : null, hasContent(children) ? (_jsx("div", { className: cx('text-(--plass-muted-fg)', sheetBodyClasses[size]), children: children })) : null] }));
152
- return (_jsxs("li", { ref: ref, "aria-current": resolved === 'current' ? 'step' : undefined, "data-status": resolved, className: cx('relative', horizontal
153
- ? cx('flex min-w-0 flex-1 flex-col', last ? '' : itemGapXClasses[density][size])
154
- : cx('flex', bulletGapClasses[size], last ? '' : itemGapClasses[density][size]), className), style: {
155
- '--p-bullet': bulletSizeValues[size],
156
- ...surfaceSlots(family, 0),
157
- // A container's slots leave the sheet undyed, which is right for the
158
- // ground a bullet sits on — but a bullet *is* the thing being
159
- // coloured, so the two fills it needs are put back.
160
- '--p-fill': `var(--plass-${family}-fill)`,
161
- '--p-on-solid': `var(--plass-${family}-on-solid)`
162
- }, ...props, children: [connectorLine, bulletBox, body] }));
163
- });
164
- /**
165
- * A sequence of steps, in the order they happen in.
166
- *
167
- * There is no Base UI primitive under this and there should not be: a timeline
168
- * has no selection, no roving focus and no keyboard contract — it is a list, and
169
- * reaching for a composite primitive to draw one would hand every consumer's
170
- * record of events the semantics of a widget.
171
- *
172
- * It is an `<ol>` for the reason it exists at all: the order *is* the content. A
173
- * screen reader announcing "list of 5 items" over an unordered list would be
174
- * describing something else.
175
- *
176
- * The children are numbered here rather than by a prop on each item, so `active`
177
- * has something to count against and inserting a step in the middle does not
178
- * mean renumbering the ones after it.
179
- */
180
- export const PlTimeline = /* @__PURE__ */ React.forwardRef(function PlTimeline({ active, size = 'md', color = 'primary', density = 'default', orientation = 'vertical', render, className, style, children, ...props }, ref) {
181
- // `toArray` is what drops the `null`s and `false`s a conditional step leaves
182
- // behind, so `active={2}` counts the steps that are actually on the page.
183
- const items = React.Children.toArray(children);
184
- const count = items.length;
185
- const context = React.useMemo(() => ({
186
- size,
187
- density,
188
- orientation,
189
- color,
190
- active: active ?? null
191
- }), [size, density, orientation, color, active]);
192
- const element = useRender({
193
- render: render ?? _jsx("ol", {}),
194
- ref,
195
- props: {
196
- // Tailwind's reset takes the markers off every `<ol>`, and Safari takes
197
- // the list semantics off with them. Saying `role="list"` out loud is the
198
- // one-line fix, and it costs nothing when the reset is not there.
199
- role: 'list',
200
- className: cx('flex', orientation === 'horizontal' ? 'flex-row' : 'flex-col', className),
201
- style: { ...surfaceSlots(color, 0), ...style },
202
- children: items.map((item, index) => (_jsx(TimelineItemContext.Provider, { value: { index, last: index === count - 1 }, children: item }, index))),
203
- ...props
204
- }
205
- });
206
- return _jsx(TimelineContext.Provider, { value: context, children: element });
207
- });
1
+ "use client";import{jsx as e,jsxs as l}from"react/jsx-runtime";import*as r from"react";import{useRender as t}from"@base-ui/react/use-render";import{cx as a,hasContent as s,iconClasses as o,metaTextClasses as n,sheetBodyClasses as i,sheetTitleClasses as d,surfaceSlots as p,transitionClasses as c}from"../../internal/styles.js";const m=/* @__PURE__ */r.createContext(null),u=/* @__PURE__ */r.createContext({index:0,last:!1}),x={xs:"0.875rem",sm:"1rem",md:"1.25rem",lg:"1.5rem",xl:"1.875rem"},f={xs:"gap-2",sm:"gap-2.5",md:"gap-3",lg:"gap-3.5",xl:"gap-4"},b={default:{xs:"pb-5",sm:"pb-6",md:"pb-7",lg:"pb-8",xl:"pb-10"},compact:{xs:"pb-3",sm:"pb-3.5",md:"pb-4",lg:"pb-5",xl:"pb-6"}},g={default:{xs:"pe-5",sm:"pe-6",md:"pe-7",lg:"pe-8",xl:"pe-10"},compact:{xs:"pe-3",sm:"pe-3.5",md:"pe-4",lg:"pe-5",xl:"pe-6"}},v={solid:"border-solid",dashed:"border-dashed",dotted:"border-dotted",none:""},h={complete:"[background-image:var(--p-fill)] text-(--p-on-solid)",current:"[background-image:var(--p-fill)] text-(--p-on-solid) [box-shadow:0_0_0_0.25rem_var(--p-soft)]",upcoming:"border-2 bg-(--plass-surface) text-(--plass-muted-fg) [border-color:var(--plass-border)]"},y={complete:"[border-color:var(--p-line-hover)]",current:"[border-color:var(--plass-border)]",upcoming:"[border-color:var(--plass-border)]"},N={complete:"text-(--plass-fg)",current:"text-(--p-accent)",upcoming:"text-(--plass-muted-fg)"};export const PlTimelineItem=/* @__PURE__ */r.forwardRef(function PlTimelineItem({title:t,meta:_,bullet:w,status:z,color:P,connector:j="solid",className:C,children:T,...k},I){const R=r.useContext(m),{index:$,last:A}=r.useContext(u),M=R?.size??"md",q=R?.density??"default",B=R?.orientation??"vertical",D=P??R?.color??"primary",E=R?.active??null,F=z??(null===E?"upcoming":$<E?"complete":$===E?"current":"upcoming"),G="horizontal"===B,H="none"!==j&&!A,J=e("span",{"aria-hidden":"true",className:a("relative z-10 flex shrink-0 items-center justify-center rounded-full","size-(--p-bullet) text-[calc(var(--p-bullet)*0.5)] leading-none font-semibold tabular-nums",h[F],c,o),children:w}),K=H?e("span",{"aria-hidden":"true",className:a("pointer-events-none absolute",G?"top-[calc(var(--p-bullet)/2_-_1px)] end-0 start-(--p-bullet) border-t-2":"top-(--p-bullet) bottom-0 start-[calc(var(--p-bullet)/2_-_1px)] border-s-2",v[j],y[F],c)}):null,L=l("div",{className:a("flex min-w-0 flex-col gap-0.5",G?"mt-2":""),children:[s(t)||s(_)?l("div",{className:"flex flex-wrap items-baseline gap-x-2",children:[s(t)?e("span",{className:a("font-semibold",d[M],N[F],c),children:t}):null,s(_)?e("span",{className:a("text-(--plass-muted-fg)",n[M]),children:_}):null]}):null,s(T)?e("div",{className:a("text-(--plass-muted-fg)",i[M]),children:T}):null]});return l("li",{ref:I,"aria-current":"current"===F?"step":void 0,"data-status":F,className:a("relative",G?a("flex min-w-0 flex-1 flex-col",A?"":g[q][M]):a("flex",f[M],A?"":b[q][M]),C),style:{"--p-bullet":x[M],...p(D,0),"--p-fill":`var(--plass-${D}-fill)`,"--p-on-solid":`var(--plass-${D}-on-solid)`},...k,children:[K,J,L]})});export const PlTimeline=/* @__PURE__ */r.forwardRef(function PlTimeline({active:l,size:s="md",color:o="primary",density:n="default",orientation:i="vertical",render:d,className:c,style:x,children:f,...b},g){const v=r.Children.toArray(f),h=v.length,y=r.useMemo(()=>({size:s,density:n,orientation:i,color:o,active:l??null}),[s,n,i,o,l]),N=t({render:d??e("ol",{}),ref:g,props:{role:"list",className:a("flex","horizontal"===i?"flex-row":"flex-col",c),style:{...p(o,0),...x},children:v.map((l,r)=>e(u.Provider,{value:{index:r,last:r===h-1},children:l},r)),...b}});return e(m.Provider,{value:y,children:N})});
@@ -1 +1 @@
1
- export { PlTimeline, PlTimelineItem } from './PlTimeline.js';
1
+ export{PlTimeline,PlTimelineItem}from"./PlTimeline.js";