@stll/ui 0.44.1 → 0.46.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -1
- package/dist/components/accordion.d.ts +6 -2
- package/dist/components/accordion.js +4 -4
- package/dist/components/ai-label.d.ts +33 -0
- package/dist/components/ai-label.js +42 -0
- package/dist/components/alert-dialog.js +3 -2
- package/dist/components/animated-count.d.ts +13 -0
- package/dist/components/animated-count.js +63 -0
- package/dist/components/application-rail.js +1 -1
- package/dist/components/brand-icons.d.ts +1 -0
- package/dist/components/brand-icons.js +8 -1
- package/dist/components/button.d.ts +2 -2
- package/dist/components/button.js +12 -2
- package/dist/components/command.js +1 -1
- package/dist/components/court-badge.d.ts +7 -1
- package/dist/components/court-badge.js +13 -3
- package/dist/components/date-picker-popover.d.ts +12 -2
- package/dist/components/date-picker-popover.js +105 -9
- package/dist/components/date-range-filter.d.ts +14 -0
- package/dist/components/date-range-filter.js +74 -0
- package/dist/components/dialog.js +3 -2
- package/dist/components/document-identity-badge.d.ts +12 -0
- package/dist/components/document-identity-badge.js +94 -0
- package/dist/components/document-identity-badge.logic.d.ts +25 -0
- package/dist/components/document-identity-badge.logic.js +25 -0
- package/dist/components/input-group.d.ts +1 -1
- package/dist/components/input-otp.js +1 -1
- package/dist/components/landing.d.ts +1 -1
- package/dist/components/landing.js +2 -2
- package/dist/components/list.d.ts +8 -2
- package/dist/components/list.js +10 -4
- package/dist/components/matter-icon.d.ts +16 -0
- package/dist/components/matter-icon.js +56 -0
- package/dist/components/menu.d.ts +9 -1
- package/dist/components/menu.js +6 -6
- package/dist/components/outline-rail.d.ts +8 -1
- package/dist/components/outline-rail.js +95 -48
- package/dist/components/popover.js +1 -1
- package/dist/components/search-field.js +30 -34
- package/dist/components/select.js +1 -1
- package/dist/components/sheet.js +22 -4
- package/dist/components/sidebar.d.ts +1 -1
- package/dist/components/sidebar.js +8 -8
- package/dist/components/status-mark.d.ts +17 -0
- package/dist/components/status-mark.js +74 -0
- package/dist/components/swap-text.d.ts +16 -0
- package/dist/components/swap-text.js +52 -0
- package/dist/components/switch.d.ts +5 -0
- package/dist/components/switch.js +16 -0
- package/dist/components/table-chart.d.ts +20 -0
- package/dist/components/table-chart.js +274 -0
- package/dist/components/tabs.js +1 -1
- package/dist/components/toast.js +42 -25
- package/dist/components/workspace-shell.js +5 -4
- package/dist/icons.js +1 -2
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/inspector/dock.js +1 -1
- package/dist/inspector/entity-tab.js +1 -2
- package/dist/kanban/virtual-cell.js +1 -1
- package/dist/lib/control-size.d.ts +1 -1
- package/dist/lib/matter-colors.d.ts +38 -0
- package/dist/lib/matter-colors.js +65 -0
- package/dist/lib/panel-inset.d.ts +11 -0
- package/dist/lib/panel-inset.js +33 -0
- package/dist/lib/safe-area.d.ts +11 -0
- package/dist/lib/safe-area.js +12 -0
- package/dist/review/review-word-diff.d.ts +13 -0
- package/dist/review/review-word-diff.js +78 -0
- package/dist/styles/theme.css +79 -0
- package/package.json +64 -8
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { ChevronRightIcon } from "../icons.js";
|
|
2
|
+
import { ChevronRightIcon, PanelLeftIcon } from "../icons.js";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
import { Tooltip, TooltipContent as TooltipPopup, TooltipTrigger } from "./tooltip.js";
|
|
5
|
+
import { ScrollArea } from "./scroll-area.js";
|
|
5
6
|
import { DirectionalIcon } from "./directional-icon.js";
|
|
7
|
+
import "../lib/panel-inset.js";
|
|
6
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
9
|
import { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
8
10
|
import { Temporal } from "temporal-polyfill/full";
|
|
9
11
|
//#region src/components/outline-rail.tsx
|
|
10
12
|
/**
|
|
11
|
-
* Outline
|
|
13
|
+
* Outline navigation: an embedded panel, a host-owned rail, or a disclosure.
|
|
12
14
|
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* jump.
|
|
15
|
+
* Embedded presentations fill their host track. The standalone disclosure
|
|
16
|
+
* owns a toggle above a thin column of ticks; hovering or pressing it reveals
|
|
17
|
+
* the collapsible tree. Click a tick or a row to jump.
|
|
17
18
|
*
|
|
18
19
|
* Generic over the position source: callers supply `resolvePct` (vertical % for
|
|
19
20
|
* a tick) and `onJump`. Active tracking is derived from `resolvePct` by default,
|
|
@@ -29,8 +30,9 @@ const OUTLINE_EMPHASIS = {
|
|
|
29
30
|
primary: "primary",
|
|
30
31
|
secondary: "secondary"
|
|
31
32
|
};
|
|
32
|
-
const
|
|
33
|
-
const
|
|
33
|
+
const OUTLINE_CONTROL_MIN_SIZE = 32;
|
|
34
|
+
const OUTLINE_CONTROL_TARGET_CLASS = "relative pointer-coarse:after:absolute pointer-coarse:after:size-full pointer-coarse:after:min-h-11 pointer-coarse:after:min-w-11";
|
|
35
|
+
const RAIL_WIDTH = 32;
|
|
34
36
|
const TICK_BASE_WIDTH = 6;
|
|
35
37
|
const TICK_LEVEL_STEP = 2;
|
|
36
38
|
const TICK_MAX_LEVEL = 5;
|
|
@@ -87,7 +89,7 @@ const Chevron = ({ open }) => /* @__PURE__ */ jsx(DirectionalIcon, {
|
|
|
87
89
|
flip: !open,
|
|
88
90
|
icon: ChevronRightIcon
|
|
89
91
|
});
|
|
90
|
-
const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId, header, collapsedFromLevel, topOffset = 0, panelWidth = 300, ariaLabel = "Outline" }) => {
|
|
92
|
+
const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId, header, formatMetaLabel, collapsedFromLevel, presentation = "popover", bottomInset, topOffset = 0, panelWidth = 300, ariaLabel = "Outline" }) => {
|
|
91
93
|
const [pctById, setPctById] = useState(/* @__PURE__ */ new Map());
|
|
92
94
|
const [derivedActive, setDerivedActive] = useState(null);
|
|
93
95
|
const [hovered, setHovered] = useState(false);
|
|
@@ -97,7 +99,7 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
97
99
|
const [hoveredId, setHoveredId] = useState(null);
|
|
98
100
|
const panelId = useId();
|
|
99
101
|
const triggerId = useId();
|
|
100
|
-
const panelOpen = hovered || pinned;
|
|
102
|
+
const panelOpen = presentation === "panel" || hovered || pinned;
|
|
101
103
|
const closeTimer = useRef(null);
|
|
102
104
|
const manualLockUntil = useRef(0);
|
|
103
105
|
const panelRef = useRef(null);
|
|
@@ -232,7 +234,13 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
232
234
|
const activeIndex = items.findIndex((item) => item.id === activeId);
|
|
233
235
|
useLayoutEffect(() => {
|
|
234
236
|
if (activeIndex === -1 || !panelOpen) return;
|
|
235
|
-
panelRef.current
|
|
237
|
+
const panel = panelRef.current;
|
|
238
|
+
const row = panel?.querySelector(`[${ACTIVE_ROW_ATTRIBUTE}]`);
|
|
239
|
+
if (!panel || !(row instanceof HTMLElement)) return;
|
|
240
|
+
const panelBox = panel.getBoundingClientRect();
|
|
241
|
+
const rowBox = row.getBoundingClientRect();
|
|
242
|
+
if (rowBox.top < panelBox.top) panel.scrollTop += rowBox.top - panelBox.top;
|
|
243
|
+
else if (rowBox.bottom > panelBox.bottom) panel.scrollTop += rowBox.bottom - panelBox.bottom;
|
|
236
244
|
}, [activeIndex, panelOpen]);
|
|
237
245
|
const openPanel = useCallback(() => {
|
|
238
246
|
if (closeTimer.current !== null) {
|
|
@@ -246,7 +254,7 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
246
254
|
closeTimer.current = setTimeout(() => setHovered(false), 120);
|
|
247
255
|
}, []);
|
|
248
256
|
useEffect(() => {
|
|
249
|
-
if (pinned) panelRef.current?.focus();
|
|
257
|
+
if (pinned) panelRef.current?.closest("nav")?.focus();
|
|
250
258
|
}, [pinned]);
|
|
251
259
|
const closePanel = useCallback(() => {
|
|
252
260
|
if (closeTimer.current !== null) {
|
|
@@ -267,23 +275,21 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
267
275
|
const highlighted = isActive || isHovered;
|
|
268
276
|
const indent = 8 + Math.min(node.item.level, maxLevel) * 12;
|
|
269
277
|
return /* @__PURE__ */ jsxs("li", { children: [/* @__PURE__ */ jsxs("div", {
|
|
270
|
-
className: cn("flex items-center rounded-md pe-2.5",
|
|
278
|
+
className: cn("flex items-center rounded-md pe-2.5", highlighted && "bg-accent"),
|
|
271
279
|
...isActive ? { [ACTIVE_ROW_ATTRIBUTE]: "" } : {},
|
|
272
280
|
onMouseEnter: () => setHoveredId(node.item.id),
|
|
273
281
|
onMouseLeave: () => setHoveredId(null),
|
|
274
|
-
style: hasChildren ? {
|
|
275
|
-
position: "sticky",
|
|
276
|
-
top: node.item.level * ROW_H,
|
|
277
|
-
zIndex: 40 - node.item.level,
|
|
278
|
-
background: highlighted ? "linear-gradient(var(--color-accent), var(--color-accent)), var(--color-popover)" : "var(--color-popover)"
|
|
279
|
-
} : void 0,
|
|
280
282
|
children: [
|
|
281
283
|
hasChildren ? /* @__PURE__ */ jsx("button", {
|
|
282
284
|
"aria-expanded": !isCollapsed,
|
|
283
285
|
"aria-label": isCollapsed ? "Expand" : "Collapse",
|
|
284
|
-
className: "text-muted-foreground hover:text-foreground flex
|
|
286
|
+
className: cn("text-muted-foreground hover:text-foreground flex shrink-0 items-center justify-center", OUTLINE_CONTROL_TARGET_CLASS),
|
|
287
|
+
style: {
|
|
288
|
+
minWidth: 32,
|
|
289
|
+
minHeight: 32,
|
|
290
|
+
marginInlineStart: indent - 4
|
|
291
|
+
},
|
|
285
292
|
onClick: (event) => toggleCollapse(node.item.id, event.currentTarget.parentElement),
|
|
286
|
-
style: { marginInlineStart: indent - 4 },
|
|
287
293
|
type: "button",
|
|
288
294
|
children: /* @__PURE__ */ jsx(Chevron, { open: !isCollapsed })
|
|
289
295
|
}) : /* @__PURE__ */ jsx("span", {
|
|
@@ -314,10 +320,22 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
314
320
|
children: node.item.title
|
|
315
321
|
})] })
|
|
316
322
|
}), /* @__PURE__ */ jsx(TooltipPopup, { children: outlineEntryText(node.item) })] }),
|
|
317
|
-
node.item.meta !== void 0 && /* @__PURE__ */ jsx(
|
|
323
|
+
node.item.meta !== void 0 && (formatMetaLabel ? /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
324
|
+
render: /* @__PURE__ */ jsx("button", {
|
|
325
|
+
"aria-label": formatMetaLabel(node.item.meta),
|
|
326
|
+
className: cn("text-foreground-placeholder text-2xs shrink-0 tabular-nums", OUTLINE_CONTROL_TARGET_CLASS),
|
|
327
|
+
style: {
|
|
328
|
+
minWidth: 32,
|
|
329
|
+
minHeight: 32
|
|
330
|
+
},
|
|
331
|
+
onClick: () => jumpTo(node.item.id),
|
|
332
|
+
type: "button"
|
|
333
|
+
}),
|
|
334
|
+
children: node.item.meta
|
|
335
|
+
}), /* @__PURE__ */ jsx(TooltipPopup, { children: formatMetaLabel(node.item.meta) })] }) : /* @__PURE__ */ jsx("span", {
|
|
318
336
|
className: "text-foreground-placeholder text-2xs shrink-0 ps-2 tabular-nums",
|
|
319
337
|
children: node.item.meta
|
|
320
|
-
})
|
|
338
|
+
}))
|
|
321
339
|
]
|
|
322
340
|
}), hasChildren && !isCollapsed && /* @__PURE__ */ jsx("ul", {
|
|
323
341
|
className: "m-0 list-none p-0",
|
|
@@ -337,18 +355,26 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
337
355
|
const ghostItem = ghostPct === void 0 ? void 0 : items.find((item) => item.id === hoveredId);
|
|
338
356
|
return /* @__PURE__ */ jsxs("div", {
|
|
339
357
|
"aria-label": ariaLabel,
|
|
340
|
-
className:
|
|
358
|
+
className: OUTLINE_PRESENTATION_CLASS[presentation],
|
|
341
359
|
role: "group",
|
|
342
360
|
style: {
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
361
|
+
marginBlockEnd: bottomInset ?? "max(env(safe-area-inset-bottom, 0px), var(--document-panel-bottom-inset, 0px))",
|
|
362
|
+
...presentation === "popover" ? {
|
|
363
|
+
top: topOffset,
|
|
364
|
+
bottom: 0,
|
|
365
|
+
width: RAIL_WIDTH
|
|
366
|
+
} : {}
|
|
346
367
|
},
|
|
347
368
|
children: [
|
|
348
|
-
/* @__PURE__ */ jsx("button", {
|
|
369
|
+
presentation === "popover" && /* @__PURE__ */ jsx("button", {
|
|
349
370
|
"aria-controls": panelId,
|
|
350
371
|
"aria-expanded": panelOpen,
|
|
351
|
-
className: "focus-visible:ring-ring bg-popover text-popover-foreground
|
|
372
|
+
className: cn("focus-visible:ring-ring bg-popover text-popover-foreground flex shrink-0 items-center justify-center self-start rounded-md focus-visible:ring-2 focus-visible:outline-none", "pointer-coarse:my-1.5", OUTLINE_CONTROL_TARGET_CLASS),
|
|
373
|
+
"aria-label": ariaLabel,
|
|
374
|
+
style: {
|
|
375
|
+
minWidth: 32,
|
|
376
|
+
minHeight: 32
|
|
377
|
+
},
|
|
352
378
|
id: triggerId,
|
|
353
379
|
onClick: () => {
|
|
354
380
|
if (pinned) {
|
|
@@ -359,10 +385,15 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
359
385
|
openPanel();
|
|
360
386
|
},
|
|
361
387
|
type: "button",
|
|
362
|
-
children:
|
|
388
|
+
children: /* @__PURE__ */ jsx(PanelLeftIcon, {
|
|
389
|
+
"aria-hidden": true,
|
|
390
|
+
className: "size-4 rtl:-scale-x-100"
|
|
391
|
+
})
|
|
363
392
|
}),
|
|
364
|
-
/* @__PURE__ */ jsxs("div", {
|
|
365
|
-
className: "relative h-
|
|
393
|
+
presentation !== "panel" && /* @__PURE__ */ jsxs("div", {
|
|
394
|
+
className: "relative min-h-0 flex-1",
|
|
395
|
+
"data-outline-ticks": true,
|
|
396
|
+
style: presentation === "popover" ? { height: `calc(100% - 32px)` } : void 0,
|
|
366
397
|
onMouseEnter: openPanel,
|
|
367
398
|
onMouseLeave: scheduleClose,
|
|
368
399
|
onWheel: (event) => {
|
|
@@ -379,7 +410,7 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
379
410
|
onMouseEnter: () => setHoveredId(item.id),
|
|
380
411
|
onMouseLeave: () => setHoveredId(null),
|
|
381
412
|
style: {
|
|
382
|
-
top:
|
|
413
|
+
top: `clamp(2px, ${pct}%, calc(100% - 2px))`,
|
|
383
414
|
transform: "translateY(-50%)",
|
|
384
415
|
width: isHovered ? tickWidth(item.level) + 8 : tickWidth(item.level),
|
|
385
416
|
height: tickHeight(isHovered, isActive),
|
|
@@ -391,7 +422,7 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
391
422
|
"aria-hidden": true,
|
|
392
423
|
className: "absolute end-0 rounded-full opacity-100",
|
|
393
424
|
style: {
|
|
394
|
-
top:
|
|
425
|
+
top: `clamp(2px, ${ghostPct}%, calc(100% - 2px))`,
|
|
395
426
|
transform: "translateY(-50%)",
|
|
396
427
|
width: tickWidth(ghostItem.level) + 8,
|
|
397
428
|
height: 4,
|
|
@@ -399,13 +430,15 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
399
430
|
}
|
|
400
431
|
})]
|
|
401
432
|
}),
|
|
402
|
-
/* @__PURE__ */ jsxs("nav", {
|
|
433
|
+
presentation !== "rail" && /* @__PURE__ */ jsxs("nav", {
|
|
434
|
+
"aria-label": ariaLabel,
|
|
403
435
|
"aria-hidden": !panelOpen,
|
|
404
436
|
id: panelId,
|
|
405
437
|
inert: panelOpen ? void 0 : true,
|
|
406
438
|
tabIndex: -1,
|
|
407
|
-
className: cn("
|
|
439
|
+
className: cn("bg-popover text-popover-foreground flex min-h-0 flex-col", presentation === "popover" && "border-border absolute rounded-xl border shadow-lg transition-[opacity,transform] duration-150", outlinePanelVisibilityClass(presentation, panelOpen)),
|
|
408
440
|
onBlurCapture: (event) => {
|
|
441
|
+
if (event.relatedTarget instanceof HTMLElement && event.relatedTarget.id === triggerId) return;
|
|
409
442
|
if (pinned && !event.currentTarget.contains(event.relatedTarget)) {
|
|
410
443
|
closePanel();
|
|
411
444
|
return;
|
|
@@ -422,28 +455,42 @@ const OutlineRail = ({ items, scrollContainerRef, resolvePct, onJump, activeId,
|
|
|
422
455
|
onMouseEnter: openPanel,
|
|
423
456
|
onMouseLeave: scheduleClose,
|
|
424
457
|
onWheel: (event) => {
|
|
425
|
-
const panel =
|
|
458
|
+
const panel = panelRef.current;
|
|
459
|
+
if (!panel) return;
|
|
426
460
|
const room = panel.scrollHeight - panel.clientHeight;
|
|
427
461
|
if (room > WHEEL_EDGE_TOLERANCE && (event.deltaY < 0 ? panel.scrollTop > WHEEL_EDGE_TOLERANCE : panel.scrollTop < room - WHEEL_EDGE_TOLERANCE)) return;
|
|
428
462
|
scrollContainerRef.current?.scrollBy(0, event.deltaY);
|
|
429
463
|
},
|
|
430
|
-
|
|
431
|
-
style: {
|
|
464
|
+
style: presentation === "popover" ? {
|
|
432
465
|
top: 0,
|
|
433
|
-
insetInlineEnd:
|
|
434
|
-
width: panelWidth,
|
|
435
|
-
|
|
436
|
-
},
|
|
466
|
+
insetInlineEnd: 38,
|
|
467
|
+
width: `min(${panelWidth}px, calc(100vw - 54px))`,
|
|
468
|
+
height: "calc(100% - 24px)"
|
|
469
|
+
} : void 0,
|
|
437
470
|
children: [header !== void 0 && /* @__PURE__ */ jsx("div", {
|
|
438
|
-
className: "bg-popover
|
|
471
|
+
className: "bg-popover z-50 shrink-0 border-b p-2",
|
|
439
472
|
children: header
|
|
440
|
-
}), /* @__PURE__ */ jsx(
|
|
441
|
-
|
|
442
|
-
|
|
473
|
+
}), /* @__PURE__ */ jsx(ScrollArea, {
|
|
474
|
+
axis: "vertical",
|
|
475
|
+
className: "min-h-0 flex-1",
|
|
476
|
+
viewportRef: panelRef,
|
|
477
|
+
children: /* @__PURE__ */ jsx("ul", {
|
|
478
|
+
className: "m-0 list-none p-0 pb-2",
|
|
479
|
+
children: tree.map(renderNode)
|
|
480
|
+
})
|
|
443
481
|
})]
|
|
444
482
|
})
|
|
445
483
|
]
|
|
446
484
|
});
|
|
447
485
|
};
|
|
486
|
+
const OUTLINE_PRESENTATION_CLASS = {
|
|
487
|
+
popover: "absolute end-0 z-20 flex flex-col pointer-coarse:min-w-11",
|
|
488
|
+
panel: "relative flex min-h-0 w-full flex-1 flex-col",
|
|
489
|
+
rail: "relative flex min-h-0 w-full flex-1 flex-col"
|
|
490
|
+
};
|
|
491
|
+
function outlinePanelVisibilityClass(presentation, open) {
|
|
492
|
+
if (presentation === "panel") return "flex-1";
|
|
493
|
+
return open ? "translate-x-0 opacity-100" : "pointer-events-none translate-x-2 opacity-0";
|
|
494
|
+
}
|
|
448
495
|
//#endregion
|
|
449
|
-
export { OUTLINE_EMPHASIS, OutlineRail, outlineEntryText };
|
|
496
|
+
export { OUTLINE_CONTROL_MIN_SIZE, OUTLINE_EMPHASIS, OutlineRail, outlineEntryText };
|
|
@@ -42,7 +42,7 @@ const PopoverPopup = ({ children, className, side = "bottom", align = "center",
|
|
|
42
42
|
"data-slot": "popover-popup",
|
|
43
43
|
...props,
|
|
44
44
|
children: /* @__PURE__ */ jsx(Popover$1.Viewport, {
|
|
45
|
-
className: cn("relative size-full max-h-(--available-height) overflow-clip px-(--viewport-inline-padding) outline-none **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-current:transition-opacity **:data-current:data-ending-style:opacity-0 data-instant:transition-none **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:opacity-100 **:data-previous:transition-opacity **:data-previous:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-starting-style:opacity-0", tooltipStyle ? "py-1 [--viewport-inline-padding:--spacing(2)]" : [POPOVER_PADDING[padding], "not-data-transitioning:overflow-y-auto"]),
|
|
45
|
+
className: cn("relative size-full max-h-(--available-height) overflow-clip px-(--viewport-inline-padding) outline-none **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-current:opacity-100 **:data-current:transition-opacity **:data-current:data-ending-style:opacity-0 data-instant:transition-none **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:opacity-100 **:data-previous:transition-opacity **:data-previous:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-starting-style:opacity-0", tooltipStyle ? "py-1 [--viewport-inline-padding:--spacing(2)]" : [POPOVER_PADDING[padding], "overscroll-contain not-data-transitioning:overflow-y-auto"]),
|
|
46
46
|
"data-slot": "popover-viewport",
|
|
47
47
|
children
|
|
48
48
|
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
2
|
+
import { XIcon } from "../icons.js";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
4
|
import { Button } from "./button.js";
|
|
5
5
|
import { InputGroup, InputGroupAddon, InputGroupInput } from "./input-group.js";
|
|
@@ -13,41 +13,37 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
*/
|
|
14
14
|
const SearchField = ({ value, onValueChange, clearLabel, groupClassName, className, onKeyDown, ...props }) => /* @__PURE__ */ jsxs(InputGroup, {
|
|
15
15
|
className: cn("min-h-11 sm:min-h-0", groupClassName),
|
|
16
|
-
children: [
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
16
|
+
children: [/* @__PURE__ */ jsx(InputGroupInput, {
|
|
17
|
+
autoComplete: "off",
|
|
18
|
+
spellCheck: false,
|
|
19
|
+
...props,
|
|
20
|
+
className: cn("max-sm:h-11 max-sm:leading-11", className),
|
|
21
|
+
onChange: (event) => {
|
|
22
|
+
onValueChange(event.target.value);
|
|
23
|
+
},
|
|
24
|
+
onKeyDown: (event) => {
|
|
25
|
+
if (event.key === "Escape" && value.length > 0) {
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
event.stopPropagation();
|
|
28
|
+
onValueChange("");
|
|
29
|
+
}
|
|
30
|
+
onKeyDown?.(event);
|
|
31
|
+
},
|
|
32
|
+
type: "search",
|
|
33
|
+
value
|
|
34
|
+
}), value.length > 0 && /* @__PURE__ */ jsx(InputGroupAddon, {
|
|
35
|
+
align: "inline-end",
|
|
36
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
37
|
+
"aria-label": clearLabel,
|
|
38
|
+
onClick: () => {
|
|
39
|
+
onValueChange("");
|
|
25
40
|
},
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
onValueChange("");
|
|
31
|
-
}
|
|
32
|
-
onKeyDown?.(event);
|
|
33
|
-
},
|
|
34
|
-
type: "search",
|
|
35
|
-
value
|
|
36
|
-
}),
|
|
37
|
-
value.length > 0 && /* @__PURE__ */ jsx(InputGroupAddon, {
|
|
38
|
-
align: "inline-end",
|
|
39
|
-
children: /* @__PURE__ */ jsx(Button, {
|
|
40
|
-
"aria-label": clearLabel,
|
|
41
|
-
onClick: () => {
|
|
42
|
-
onValueChange("");
|
|
43
|
-
},
|
|
44
|
-
size: "icon-xs",
|
|
45
|
-
type: "button",
|
|
46
|
-
variant: "ghost",
|
|
47
|
-
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
48
|
-
})
|
|
41
|
+
size: "icon-xs",
|
|
42
|
+
type: "button",
|
|
43
|
+
variant: "ghost",
|
|
44
|
+
children: /* @__PURE__ */ jsx(XIcon, {})
|
|
49
45
|
})
|
|
50
|
-
]
|
|
46
|
+
})]
|
|
51
47
|
});
|
|
52
48
|
//#endregion
|
|
53
49
|
export { SearchField };
|
|
@@ -83,7 +83,7 @@ const SelectPopup = ({ className, children, side = "bottom", sideOffset = 4, ali
|
|
|
83
83
|
/* @__PURE__ */ jsx("div", {
|
|
84
84
|
className: "bg-popover text-popover-foreground relative h-full min-w-(--anchor-width) rounded-lg border shadow-lg/5 not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] dark:before:shadow-[0_-1px_--theme(--color-white/6%)]",
|
|
85
85
|
children: /* @__PURE__ */ jsx(Select$1.List, {
|
|
86
|
-
className: cn("max-h-(--available-height) overflow-y-auto p-1", className),
|
|
86
|
+
className: cn("max-h-(--available-height) overflow-y-auto overscroll-contain p-1", className),
|
|
87
87
|
"data-slot": "select-list",
|
|
88
88
|
children
|
|
89
89
|
})
|
package/dist/components/sheet.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { XIcon } from "../icons.js";
|
|
3
3
|
import { cn } from "../lib/utils.js";
|
|
4
|
+
import { OVERLAY_LAYER_CLASS_NAMES } from "../lib/overlay-layer.js";
|
|
5
|
+
import "../lib/safe-area.js";
|
|
4
6
|
import { renderTooltipTrigger } from "./tooltip-trigger-helper.js";
|
|
5
7
|
import { Button } from "./button.js";
|
|
6
8
|
import { ScrollArea } from "./scroll-area.js";
|
|
@@ -28,12 +30,12 @@ function SheetClose({ tooltip, ...props }) {
|
|
|
28
30
|
});
|
|
29
31
|
}
|
|
30
32
|
const SheetBackdrop = ({ className, ...props }) => /* @__PURE__ */ jsx(Dialog.Backdrop, {
|
|
31
|
-
className: cn("fixed inset-0
|
|
33
|
+
className: cn("fixed inset-0 bg-black/32 backdrop-blur-sm transition-opacity duration-200 data-ending-style:opacity-0 data-starting-style:opacity-0", OVERLAY_LAYER_CLASS_NAMES.default, className),
|
|
32
34
|
"data-slot": "sheet-backdrop",
|
|
33
35
|
...props
|
|
34
36
|
});
|
|
35
37
|
const SheetViewport = ({ className: _className, side, variant = "default", ...props }) => /* @__PURE__ */ jsx(Dialog.Viewport, {
|
|
36
|
-
className: cn("fixed inset-0
|
|
38
|
+
className: cn("fixed inset-0", OVERLAY_LAYER_CLASS_NAMES.default, side === "block-end" && "grid grid-rows-[1fr_auto] pt-12", side === "block-start" && "grid grid-rows-[auto_1fr] pb-12", side === "inline-start" && "flex justify-start", side === "inline-end" && "flex justify-end", variant === "inset" && "sm:p-4"),
|
|
37
39
|
"data-slot": "sheet-viewport",
|
|
38
40
|
...props
|
|
39
41
|
});
|
|
@@ -41,12 +43,28 @@ const SheetPopup = ({ className, children, showCloseButton = true, side = "inlin
|
|
|
41
43
|
side,
|
|
42
44
|
variant,
|
|
43
45
|
children: /* @__PURE__ */ jsxs(Dialog.Popup, {
|
|
44
|
-
className: cn("bg-popover text-popover-foreground relative flex max-h-full min-h-0 w-full min-w-0 flex-col shadow-lg/5 transition-[opacity,translate] duration-200 ease-
|
|
46
|
+
className: cn("bg-popover text-popover-foreground relative flex max-h-full min-h-0 w-full min-w-0 flex-col shadow-lg/5 transition-[opacity,translate] duration-200 ease-out will-change-transform not-dark:bg-clip-padding before:pointer-events-none before:absolute before:inset-0 before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:opacity-0 data-ending-style:duration-150 data-starting-style:opacity-0 max-sm:before:hidden dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", side === "block-end" && [
|
|
47
|
+
"row-start-2 border-t data-ending-style:translate-y-8 data-starting-style:translate-y-8",
|
|
48
|
+
"pb-(--safe-area-bottom)",
|
|
49
|
+
"ps-(--safe-area-inline-start) pe-(--safe-area-inline-end)"
|
|
50
|
+
], side === "block-start" && [
|
|
51
|
+
"border-b data-ending-style:-translate-y-8 data-starting-style:-translate-y-8",
|
|
52
|
+
"pt-(--safe-area-top)",
|
|
53
|
+
"ps-(--safe-area-inline-start) pe-(--safe-area-inline-end)"
|
|
54
|
+
], side === "inline-start" && [
|
|
55
|
+
"w-[calc(100%-(--spacing(12)))] max-w-md border-e ps-(--safe-area-inline-start) data-ending-style:-translate-x-8 data-starting-style:-translate-x-8 rtl:data-ending-style:translate-x-8 rtl:data-starting-style:translate-x-8 [&.w-full.max-w-none]:pe-(--safe-area-inline-end)",
|
|
56
|
+
"pt-(--safe-area-top)",
|
|
57
|
+
"pb-(--safe-area-bottom)"
|
|
58
|
+
], side === "inline-end" && [
|
|
59
|
+
"w-[calc(100%-(--spacing(12)))] max-w-md border-s pe-(--safe-area-inline-end) data-ending-style:translate-x-8 data-starting-style:translate-x-8 rtl:data-ending-style:-translate-x-8 rtl:data-starting-style:-translate-x-8 [&.w-full.max-w-none]:ps-(--safe-area-inline-start)",
|
|
60
|
+
"pt-(--safe-area-top)",
|
|
61
|
+
"pb-(--safe-area-bottom)"
|
|
62
|
+
], variant === "inset" && "before:hidden sm:rounded-2xl sm:border sm:before:rounded-[calc(var(--radius-2xl)-1px)] sm:**:data-[slot=sheet-footer]:rounded-b-[calc(var(--radius-2xl)-1px)]", className),
|
|
45
63
|
"data-slot": "sheet-popup",
|
|
46
64
|
...props,
|
|
47
65
|
children: [children, showCloseButton && /* @__PURE__ */ jsx(Dialog.Close, {
|
|
48
66
|
"aria-label": "Close",
|
|
49
|
-
className: "absolute end-2 top-2",
|
|
67
|
+
className: cn("absolute end-[calc(--spacing(2)+var(--safe-area-inline-end))] top-2", side !== "block-end" && "top-[calc(--spacing(2)+var(--safe-area-top))]"),
|
|
50
68
|
render: /* @__PURE__ */ jsx(Button, {
|
|
51
69
|
size: "icon",
|
|
52
70
|
variant: "ghost"
|
|
@@ -86,7 +86,7 @@ declare const SidebarMenu: ({ className, ...props }: React.ComponentProps<"ul">)
|
|
|
86
86
|
declare const SidebarMenuItem: ({ className, ...props }: React.ComponentProps<"li">) => import("react").JSX.Element;
|
|
87
87
|
declare const sidebarMenuButtonVariants: (props?: ({
|
|
88
88
|
variant?: "default" | "outline" | null | undefined;
|
|
89
|
-
size?: "
|
|
89
|
+
size?: "default" | "lg" | "sm" | "rail" | null | undefined;
|
|
90
90
|
} & import("class-variance-authority/types").ClassProp) | undefined) => string;
|
|
91
91
|
/**
|
|
92
92
|
* The footer's avatar trigger, signed in (user menu) or not (sign-in): a
|
|
@@ -118,7 +118,7 @@ const Sidebar = ({ side = "left", variant = "sidebar", collapsible = "offcanvas"
|
|
|
118
118
|
open: openMobile,
|
|
119
119
|
...props,
|
|
120
120
|
children: /* @__PURE__ */ jsxs(SheetPopup, {
|
|
121
|
-
className: "bg-sidebar text-sidebar-foreground w-(--sidebar-width)
|
|
121
|
+
className: "bg-sidebar text-sidebar-foreground w-(--sidebar-width) [&>button]:hidden",
|
|
122
122
|
"data-mobile": "true",
|
|
123
123
|
"data-sidebar": "sidebar",
|
|
124
124
|
"data-slot": "sidebar",
|
|
@@ -135,17 +135,17 @@ const Sidebar = ({ side = "left", variant = "sidebar", collapsible = "offcanvas"
|
|
|
135
135
|
});
|
|
136
136
|
}
|
|
137
137
|
return /* @__PURE__ */ jsxs("div", {
|
|
138
|
-
className: "group peer text-sidebar-foreground hidden md:block",
|
|
138
|
+
className: cn("group peer text-sidebar-foreground hidden [--sidebar-inline-size:calc(var(--sidebar-width)+var(--sidebar-safe-area-inline))] md:block", side === "left" ? "[--sidebar-safe-area-inline:var(--safe-area-inline-start)]" : "[--sidebar-safe-area-inline:var(--safe-area-inline-end)]", variant === "floating" || variant === "inset" ? "data-[collapsible=icon]:[--sidebar-inline-size:calc(var(--sidebar-width-icon)+--spacing(4)+var(--sidebar-safe-area-inline))]" : "data-[collapsible=icon]:[--sidebar-inline-size:calc(var(--sidebar-width-icon)+var(--sidebar-safe-area-inline))]"),
|
|
139
139
|
"data-collapsible": state === "collapsed" ? collapsible : "",
|
|
140
140
|
"data-side": side,
|
|
141
141
|
"data-slot": "sidebar",
|
|
142
142
|
"data-state": state,
|
|
143
143
|
"data-variant": variant,
|
|
144
144
|
children: [/* @__PURE__ */ jsx("div", {
|
|
145
|
-
className: cn("relative w-(--sidebar-
|
|
145
|
+
className: cn("relative w-(--sidebar-inline-size) bg-transparent transition-[width] duration-200 ease-in-out", "group-data-[collapsible=offcanvas]:w-0", "group-data-[side=right]:rotate-180"),
|
|
146
146
|
"data-slot": "sidebar-gap"
|
|
147
147
|
}), /* @__PURE__ */ jsx("div", {
|
|
148
|
-
className: cn("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-
|
|
148
|
+
className: cn("fixed inset-y-0 z-10 hidden h-svh w-(--sidebar-inline-size) transition-[inset-inline-start,inset-inline-end,width] duration-200 ease-in-out md:flex", "pt-(--safe-area-top) pb-(--safe-area-bottom)", side === "left" ? "start-0 ps-(--safe-area-inline-start) group-data-[collapsible=offcanvas]:start-[calc(var(--sidebar-inline-size)*-1)]" : "end-0 pe-(--safe-area-inline-end) group-data-[collapsible=offcanvas]:end-[calc(var(--sidebar-inline-size)*-1)]", variant === "floating" || variant === "inset" ? ["p-2 pt-[calc(var(--safe-area-top)+--spacing(2))] pb-[calc(var(--safe-area-bottom)+--spacing(2))] group-data-[collapsible=icon]:w-[calc(var(--sidebar-inline-size)+2px)]", side === "left" ? "ps-[calc(var(--safe-area-inline-start)+--spacing(2))]" : "pe-[calc(var(--safe-area-inline-end)+--spacing(2))]"] : "group-data-[side=left]:border-e group-data-[side=right]:border-s", className),
|
|
149
149
|
"data-slot": "sidebar-container",
|
|
150
150
|
...props,
|
|
151
151
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -182,7 +182,7 @@ const SidebarRail = ({ className, label = DEFAULT_TOGGLE_LABEL, "aria-label": ar
|
|
|
182
182
|
return /* @__PURE__ */ jsx("button", {
|
|
183
183
|
"aria-label": ariaLabel ?? label,
|
|
184
184
|
type: "button",
|
|
185
|
-
className: cn("hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 transition-transform ease-
|
|
185
|
+
className: cn("hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 transition-transform ease-in-out group-data-[side=left]:-end-4 group-data-[side=right]:start-0 after:absolute after:inset-y-0 after:start-1/2 after:w-[2px] sm:flex", "ltr:-translate-x-1/2 rtl:translate-x-1/2", "in-data-[side=left]:cursor-w-resize in-data-[side=right]:cursor-e-resize", "[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize", "hover:group-data-[collapsible=offcanvas]:bg-sidebar", "group-data-[collapsible=offcanvas]:ltr:translate-x-0 group-data-[collapsible=offcanvas]:rtl:translate-x-0", "group-data-[collapsible=offcanvas]:group-data-[side=left]:after:end-full group-data-[collapsible=offcanvas]:group-data-[side=right]:after:start-full", "[[data-side=left][data-collapsible=offcanvas]_&]:-end-2", "[[data-side=right][data-collapsible=offcanvas]_&]:-start-2", className),
|
|
186
186
|
"data-sidebar": "rail",
|
|
187
187
|
"data-slot": "sidebar-rail",
|
|
188
188
|
onClick: toggleSidebar,
|
|
@@ -220,7 +220,7 @@ const SidebarSeparator = ({ className, ...props }) => /* @__PURE__ */ jsx(Separa
|
|
|
220
220
|
...props
|
|
221
221
|
});
|
|
222
222
|
const SidebarContent = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
223
|
-
className: cn("flex min-h-0 flex-1 flex-col gap-2 overflow-x-hidden overflow-y-auto group-data-[collapsible=icon]:[scrollbar-width:none] group-data-[collapsible=icon]:[&::-webkit-scrollbar]:hidden", className),
|
|
223
|
+
className: cn("flex min-h-0 flex-1 flex-col gap-2 overflow-x-hidden overflow-y-auto overscroll-contain group-data-[collapsible=icon]:[scrollbar-width:none] group-data-[collapsible=icon]:[&::-webkit-scrollbar]:hidden", className),
|
|
224
224
|
"data-sidebar": "content",
|
|
225
225
|
"data-slot": "sidebar-content",
|
|
226
226
|
...props
|
|
@@ -233,7 +233,7 @@ const SidebarGroup = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
|
233
233
|
});
|
|
234
234
|
const SidebarGroupLabel = ({ className, asChild = false, ...props }) => {
|
|
235
235
|
return /* @__PURE__ */ jsx(asChild ? Slot : "div", {
|
|
236
|
-
className: cn("text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-
|
|
236
|
+
className: cn("text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-hidden transition-[margin,opacity] duration-200 ease-in-out focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0", "group-data-[collapsible=icon]:hidden", className),
|
|
237
237
|
"data-sidebar": "group-label",
|
|
238
238
|
"data-slot": "sidebar-group-label",
|
|
239
239
|
...props
|
|
@@ -265,7 +265,7 @@ const SidebarMenuItem = ({ className, ...props }) => /* @__PURE__ */ jsx("li", {
|
|
|
265
265
|
"data-slot": "sidebar-menu-item",
|
|
266
266
|
...props
|
|
267
267
|
});
|
|
268
|
-
const sidebarMenuButtonVariants = cva("peer/menu-button ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-sidebar-accent-foreground data-[active=true]:hover:bg-sidebar-accent data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-start text-sm outline-hidden transition-[width,height,padding] group-has-data-[sidebar=menu-action]/menu-item:pe-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>span:last-child]:transition-opacity [&>span:last-child]:duration-200 group-data-[collapsible=icon]:[&>span:last-child]:opacity-0 [&>svg]:size-4 [&>svg]:shrink-0", {
|
|
268
|
+
const sidebarMenuButtonVariants = cva("peer/menu-button ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground data-[active=true]:bg-accent data-[active=true]:text-sidebar-accent-foreground data-[active=true]:hover:bg-sidebar-accent data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-start text-sm outline-hidden transition-[width,height,padding] select-none group-has-data-[sidebar=menu-action]/menu-item:pe-8 group-data-[collapsible=icon]:size-8! group-data-[collapsible=icon]:p-2! focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:font-medium [&>span:last-child]:truncate [&>span:last-child]:transition-opacity [&>span:last-child]:duration-200 group-data-[collapsible=icon]:[&>span:last-child]:opacity-0 [&>svg]:size-4 [&>svg]:shrink-0", {
|
|
269
269
|
variants: {
|
|
270
270
|
variant: {
|
|
271
271
|
default: "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground",
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/components/status-mark.d.ts
|
|
2
|
+
type StatusMarkStatus = "pending" | "running" | "done" | "failed";
|
|
3
|
+
type StatusMarkProps = {
|
|
4
|
+
status: StatusMarkStatus;
|
|
5
|
+
/** Accessible name; omit when adjacent text already states the status. */
|
|
6
|
+
label?: string | undefined;
|
|
7
|
+
className?: string;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* One glyph for a unit of work across its life: dashes while it waits, a
|
|
11
|
+
* turning arc while it runs, then a closed ring with a check or a cross
|
|
12
|
+
* drawn in. Monochrome by design: it takes the text colour, and only a
|
|
13
|
+
* failure eases to destructive.
|
|
14
|
+
*/
|
|
15
|
+
declare const StatusMark: ({ className, label, status }: StatusMarkProps) => import("react").JSX.Element;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { StatusMark, type StatusMarkStatus };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { cn } from "../lib/utils.js";
|
|
3
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
4
|
+
//#region src/components/status-mark.tsx
|
|
5
|
+
const RING_RADIUS = 6.25;
|
|
6
|
+
const CHECK_PATH = "M5.4 8.3 7.2 10.1 10.6 6.3";
|
|
7
|
+
const CROSS_PATH = "M6.1 6.1 9.9 9.9M9.9 6.1 6.1 9.9";
|
|
8
|
+
const on = {
|
|
9
|
+
active: "group-data-[status=running]/status:opacity-100 group-data-[status=done]/status:opacity-50 group-data-[status=failed]/status:opacity-60",
|
|
10
|
+
settled: "group-data-[status=done]/status:[stroke-dasharray:100_0] group-data-[status=failed]/status:[stroke-dasharray:100_0]"
|
|
11
|
+
};
|
|
12
|
+
const RING_CLASS = cn("opacity-55 [stroke-dasharray:3.75_8.75]", "transition-[stroke-dasharray,opacity] duration-300 ease-in-out motion-reduce:transition-[opacity]", "group-data-[status=running]/status:[stroke-dasharray:30_70]", on.active, on.settled, "motion-reduce:group-data-[status=running]/status:animate-status-breathe");
|
|
13
|
+
const SPIN_CLASS = "origin-center [transform-box:view-box] animate-status-spin [animation-play-state:paused] motion-safe:group-data-[status=running]/status:[animation-play-state:running]";
|
|
14
|
+
const markClass = (status) => cn("opacity-0 [stroke-dasharray:1_2] [stroke-dashoffset:1.05]", "[transition:stroke-dashoffset_150ms_cubic-bezier(0.22,1,0.36,1),opacity_0ms_linear_150ms]", status === "done" ? "group-data-[status=done]/status:opacity-100 group-data-[status=done]/status:[stroke-dashoffset:0] group-data-[status=done]/status:[transition:stroke-dashoffset_300ms_cubic-bezier(0.22,1,0.36,1)_140ms,opacity_0ms_linear_140ms]" : "group-data-[status=failed]/status:opacity-100 group-data-[status=failed]/status:[stroke-dashoffset:0] group-data-[status=failed]/status:[transition:stroke-dashoffset_300ms_cubic-bezier(0.22,1,0.36,1)_140ms,opacity_0ms_linear_140ms]", "motion-reduce:[stroke-dashoffset:0] motion-reduce:[transition:opacity_200ms_ease]");
|
|
15
|
+
/**
|
|
16
|
+
* One glyph for a unit of work across its life: dashes while it waits, a
|
|
17
|
+
* turning arc while it runs, then a closed ring with a check or a cross
|
|
18
|
+
* drawn in. Monochrome by design: it takes the text colour, and only a
|
|
19
|
+
* failure eases to destructive.
|
|
20
|
+
*/
|
|
21
|
+
const StatusMark = ({ className, label, status }) => /* @__PURE__ */ jsxs("svg", {
|
|
22
|
+
className: cn("group/status size-4 shrink-0 transition-[color] duration-200", status === "failed" && "text-destructive", className),
|
|
23
|
+
"data-slot": "status-mark",
|
|
24
|
+
"data-status": status,
|
|
25
|
+
fill: "none",
|
|
26
|
+
stroke: "currentColor",
|
|
27
|
+
strokeLinecap: "round",
|
|
28
|
+
strokeLinejoin: "round",
|
|
29
|
+
strokeWidth: 1.5,
|
|
30
|
+
viewBox: "0 0 16 16",
|
|
31
|
+
...label === void 0 ? { "aria-hidden": true } : {
|
|
32
|
+
"aria-label": label,
|
|
33
|
+
role: "img"
|
|
34
|
+
},
|
|
35
|
+
children: [
|
|
36
|
+
/* @__PURE__ */ jsx("circle", {
|
|
37
|
+
className: "opacity-0 transition-opacity duration-200 group-data-[status=done]/status:opacity-[0.06] group-data-[status=failed]/status:opacity-[0.08]",
|
|
38
|
+
cx: "8",
|
|
39
|
+
cy: "8",
|
|
40
|
+
fill: "currentColor",
|
|
41
|
+
r: RING_RADIUS,
|
|
42
|
+
stroke: "none"
|
|
43
|
+
}),
|
|
44
|
+
/* @__PURE__ */ jsx("circle", {
|
|
45
|
+
className: "opacity-0 transition-opacity duration-200 group-data-[status=running]/status:opacity-20",
|
|
46
|
+
cx: "8",
|
|
47
|
+
cy: "8",
|
|
48
|
+
r: RING_RADIUS
|
|
49
|
+
}),
|
|
50
|
+
/* @__PURE__ */ jsx("g", {
|
|
51
|
+
className: SPIN_CLASS,
|
|
52
|
+
children: /* @__PURE__ */ jsx("circle", {
|
|
53
|
+
className: RING_CLASS,
|
|
54
|
+
cx: "8",
|
|
55
|
+
cy: "8",
|
|
56
|
+
pathLength: 100,
|
|
57
|
+
r: RING_RADIUS,
|
|
58
|
+
transform: "rotate(-90 8 8)"
|
|
59
|
+
})
|
|
60
|
+
}),
|
|
61
|
+
/* @__PURE__ */ jsx("path", {
|
|
62
|
+
className: markClass("done"),
|
|
63
|
+
d: CHECK_PATH,
|
|
64
|
+
pathLength: 1
|
|
65
|
+
}),
|
|
66
|
+
/* @__PURE__ */ jsx("path", {
|
|
67
|
+
className: markClass("failed"),
|
|
68
|
+
d: CROSS_PATH,
|
|
69
|
+
pathLength: 1
|
|
70
|
+
})
|
|
71
|
+
]
|
|
72
|
+
});
|
|
73
|
+
//#endregion
|
|
74
|
+
export { StatusMark };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//#region src/components/swap-text.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A short label that changes in place (a live status line): the old text
|
|
4
|
+
* lifts out with a slight blur while the new one rises into the same cell,
|
|
5
|
+
* so the change reads as one motion instead of a blink. Both layers share a
|
|
6
|
+
* grid cell, so nothing reflows mid-swap. The first render is still, and
|
|
7
|
+
* under reduced motion the label simply changes.
|
|
8
|
+
*/
|
|
9
|
+
declare const SwapText: ({ className, text }: {
|
|
10
|
+
/** Applied to the text inside each layer, so a text effect with its own
|
|
11
|
+
* animation (a shimmer) runs alongside the swap instead of replacing it. */
|
|
12
|
+
className?: string;
|
|
13
|
+
text: string;
|
|
14
|
+
}) => import("react").JSX.Element;
|
|
15
|
+
//#endregion
|
|
16
|
+
export { SwapText };
|