@inshorts/glint-ui 0.5.4 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/alert.cjs +96 -0
- package/dist/alert.cjs.map +1 -0
- package/dist/alert.d.cts +29 -0
- package/dist/alert.d.ts +29 -0
- package/dist/alert.js +10 -0
- package/dist/alert.js.map +1 -0
- package/dist/autocomplete.cjs +578 -0
- package/dist/autocomplete.cjs.map +1 -0
- package/dist/autocomplete.d.cts +56 -0
- package/dist/autocomplete.d.ts +56 -0
- package/dist/autocomplete.js +11 -0
- package/dist/autocomplete.js.map +1 -0
- package/dist/badge.cjs +89 -0
- package/dist/badge.cjs.map +1 -0
- package/dist/badge.d.cts +25 -0
- package/dist/badge.d.ts +25 -0
- package/dist/badge.js +10 -0
- package/dist/badge.js.map +1 -0
- package/dist/breadcrumb.cjs +88 -0
- package/dist/breadcrumb.cjs.map +1 -0
- package/dist/breadcrumb.d.cts +14 -0
- package/dist/breadcrumb.d.ts +14 -0
- package/dist/breadcrumb.js +8 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/button.cjs +143 -0
- package/dist/button.cjs.map +1 -0
- package/dist/button.d.cts +34 -0
- package/dist/button.d.ts +34 -0
- package/dist/button.js +9 -0
- package/dist/button.js.map +1 -0
- package/dist/card.cjs +111 -0
- package/dist/card.cjs.map +1 -0
- package/dist/card.d.cts +15 -0
- package/dist/card.d.ts +15 -0
- package/dist/card.js +18 -0
- package/dist/card.js.map +1 -0
- package/dist/checkbox.cjs +66 -0
- package/dist/checkbox.cjs.map +1 -0
- package/{src/checkbox.tsx → dist/checkbox.d.cts} +5 -22
- package/dist/checkbox.d.ts +25 -0
- package/dist/checkbox.js +10 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-5MEOZHJA.js +513 -0
- package/dist/chunk-5MEOZHJA.js.map +1 -0
- package/dist/chunk-67ACNS42.js +29 -0
- package/dist/chunk-67ACNS42.js.map +1 -0
- package/dist/chunk-A6GRLKOO.js +85 -0
- package/dist/chunk-A6GRLKOO.js.map +1 -0
- package/dist/chunk-DS3QYIKL.js +90 -0
- package/dist/chunk-DS3QYIKL.js.map +1 -0
- package/dist/chunk-EWSBFU54.js +53 -0
- package/dist/chunk-EWSBFU54.js.map +1 -0
- package/dist/chunk-G4ZQUSAJ.js +38 -0
- package/dist/chunk-G4ZQUSAJ.js.map +1 -0
- package/dist/chunk-GMCUXEFI.js +67 -0
- package/dist/chunk-GMCUXEFI.js.map +1 -0
- package/dist/chunk-HBBOR43A.js +85 -0
- package/dist/chunk-HBBOR43A.js.map +1 -0
- package/dist/chunk-HCA5ODCD.js +11 -0
- package/dist/chunk-HCA5ODCD.js.map +1 -0
- package/dist/chunk-HYRJYUPI.js +26 -0
- package/dist/chunk-HYRJYUPI.js.map +1 -0
- package/dist/chunk-IRCTGJQB.js +26 -0
- package/dist/chunk-IRCTGJQB.js.map +1 -0
- package/dist/chunk-ISPICB4W.js +70 -0
- package/dist/chunk-ISPICB4W.js.map +1 -0
- package/dist/chunk-JDE5XYPT.js +30 -0
- package/dist/chunk-JDE5XYPT.js.map +1 -0
- package/dist/chunk-JSJEEKR3.js +59 -0
- package/dist/chunk-JSJEEKR3.js.map +1 -0
- package/dist/chunk-KR3BCFP7.js +85 -0
- package/dist/chunk-KR3BCFP7.js.map +1 -0
- package/dist/chunk-MLRSOTFI.js +81 -0
- package/dist/chunk-MLRSOTFI.js.map +1 -0
- package/dist/chunk-MQT5RAQV.js +202 -0
- package/dist/chunk-MQT5RAQV.js.map +1 -0
- package/dist/chunk-MUPW2TFJ.js +102 -0
- package/dist/chunk-MUPW2TFJ.js.map +1 -0
- package/dist/chunk-OUYT6SPU.js +76 -0
- package/dist/chunk-OUYT6SPU.js.map +1 -0
- package/dist/chunk-PM2VE7DJ.js +100 -0
- package/dist/chunk-PM2VE7DJ.js.map +1 -0
- package/dist/chunk-PPYR3O3L.js +44 -0
- package/dist/chunk-PPYR3O3L.js.map +1 -0
- package/dist/chunk-PUTC52SI.js +98 -0
- package/dist/chunk-PUTC52SI.js.map +1 -0
- package/dist/chunk-PWAKTEXF.js +18 -0
- package/dist/chunk-PWAKTEXF.js.map +1 -0
- package/dist/chunk-QTFWORA7.js +26 -0
- package/dist/chunk-QTFWORA7.js.map +1 -0
- package/dist/chunk-RUPL2H6V.js +49 -0
- package/dist/chunk-RUPL2H6V.js.map +1 -0
- package/dist/chunk-S7PVZAPL.js +28 -0
- package/dist/chunk-S7PVZAPL.js.map +1 -0
- package/dist/chunk-SQDV2AKJ.js +49 -0
- package/dist/chunk-SQDV2AKJ.js.map +1 -0
- package/dist/chunk-T2KXVH3O.js +297 -0
- package/dist/chunk-T2KXVH3O.js.map +1 -0
- package/dist/chunk-T4WCCHJQ.js +29 -0
- package/dist/chunk-T4WCCHJQ.js.map +1 -0
- package/dist/chunk-UC3ZIQPE.js +93 -0
- package/dist/chunk-UC3ZIQPE.js.map +1 -0
- package/dist/chunk-UE7JY7VR.js +28 -0
- package/dist/chunk-UE7JY7VR.js.map +1 -0
- package/dist/chunk-Y5WCT6XN.js +93 -0
- package/dist/chunk-Y5WCT6XN.js.map +1 -0
- package/dist/chunk-YDICVETX.js +151 -0
- package/dist/chunk-YDICVETX.js.map +1 -0
- package/dist/chunk-ZFSQVMLJ.js +126 -0
- package/dist/chunk-ZFSQVMLJ.js.map +1 -0
- package/dist/chunk-ZHATD73Y.js +46 -0
- package/dist/chunk-ZHATD73Y.js.map +1 -0
- package/dist/chunk-ZLAA4DGG.js +111 -0
- package/dist/chunk-ZLAA4DGG.js.map +1 -0
- package/dist/chunk-ZP252OJZ.js +56 -0
- package/dist/chunk-ZP252OJZ.js.map +1 -0
- package/dist/clipboard.cjs +125 -0
- package/dist/clipboard.cjs.map +1 -0
- package/dist/clipboard.d.cts +52 -0
- package/dist/clipboard.d.ts +52 -0
- package/dist/clipboard.js +23 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/collapsible.cjs +94 -0
- package/dist/collapsible.cjs.map +1 -0
- package/dist/collapsible.d.cts +21 -0
- package/dist/collapsible.d.ts +21 -0
- package/dist/collapsible.js +9 -0
- package/dist/collapsible.js.map +1 -0
- package/dist/confirm-dialog.cjs +369 -0
- package/dist/confirm-dialog.cjs.map +1 -0
- package/dist/confirm-dialog.d.cts +16 -0
- package/dist/confirm-dialog.d.ts +16 -0
- package/dist/confirm-dialog.js +13 -0
- package/dist/confirm-dialog.js.map +1 -0
- package/dist/copy-button.cjs +102 -0
- package/dist/copy-button.cjs.map +1 -0
- package/dist/copy-button.d.cts +18 -0
- package/dist/copy-button.d.ts +18 -0
- package/dist/copy-button.js +10 -0
- package/dist/copy-button.js.map +1 -0
- package/dist/data-table.cjs +140 -0
- package/dist/data-table.cjs.map +1 -0
- package/dist/data-table.d.cts +81 -0
- package/dist/data-table.d.ts +81 -0
- package/dist/data-table.js +8 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-range-picker/dateRange.cjs +138 -0
- package/dist/date-range-picker/dateRange.cjs.map +1 -0
- package/dist/date-range-picker/dateRange.d.cts +57 -0
- package/dist/date-range-picker/dateRange.d.ts +57 -0
- package/dist/date-range-picker/dateRange.js +31 -0
- package/dist/date-range-picker/dateRange.js.map +1 -0
- package/dist/date-range-picker/index.cjs +375 -0
- package/dist/date-range-picker/index.cjs.map +1 -0
- package/dist/date-range-picker/index.d.cts +18 -0
- package/dist/date-range-picker/index.d.ts +18 -0
- package/dist/date-range-picker/index.js +10 -0
- package/dist/date-range-picker/index.js.map +1 -0
- package/dist/dialogLayer.cjs +121 -0
- package/dist/dialogLayer.cjs.map +1 -0
- package/dist/dialogLayer.d.cts +11 -0
- package/dist/dialogLayer.d.ts +11 -0
- package/dist/dialogLayer.js +8 -0
- package/dist/dialogLayer.js.map +1 -0
- package/dist/feature-access-gate.cjs +160 -0
- package/dist/feature-access-gate.cjs.map +1 -0
- package/dist/feature-access-gate.d.cts +14 -0
- package/dist/feature-access-gate.d.ts +14 -0
- package/dist/feature-access-gate.js +11 -0
- package/dist/feature-access-gate.js.map +1 -0
- package/dist/field.cjs +58 -0
- package/dist/field.cjs.map +1 -0
- package/dist/field.d.cts +23 -0
- package/dist/field.d.ts +23 -0
- package/dist/field.js +8 -0
- package/dist/field.js.map +1 -0
- package/dist/image-uploader.cjs +293 -0
- package/dist/image-uploader.cjs.map +1 -0
- package/dist/image-uploader.d.cts +34 -0
- package/dist/image-uploader.d.ts +34 -0
- package/dist/image-uploader.js +12 -0
- package/dist/image-uploader.js.map +1 -0
- package/dist/index.cjs +3008 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +232 -0
- package/dist/index.js.map +1 -0
- package/dist/input.cjs +58 -0
- package/dist/input.cjs.map +1 -0
- package/dist/input.d.cts +7 -0
- package/dist/input.d.ts +7 -0
- package/dist/input.js +10 -0
- package/dist/input.js.map +1 -0
- package/dist/label.cjs +67 -0
- package/dist/label.cjs.map +1 -0
- package/dist/label.d.cts +7 -0
- package/dist/label.d.ts +7 -0
- package/dist/label.js +9 -0
- package/dist/label.js.map +1 -0
- package/dist/modal.cjs +212 -0
- package/dist/modal.cjs.map +1 -0
- package/dist/modal.d.cts +39 -0
- package/dist/modal.d.ts +39 -0
- package/dist/modal.js +12 -0
- package/dist/modal.js.map +1 -0
- package/dist/page-header.cjs +78 -0
- package/dist/page-header.cjs.map +1 -0
- package/dist/page-header.d.cts +35 -0
- package/dist/page-header.d.ts +35 -0
- package/dist/page-header.js +8 -0
- package/dist/page-header.js.map +1 -0
- package/dist/pagination.cjs +237 -0
- package/dist/pagination.cjs.map +1 -0
- package/dist/pagination.d.cts +15 -0
- package/dist/pagination.d.ts +15 -0
- package/dist/pagination.js +11 -0
- package/dist/pagination.js.map +1 -0
- package/dist/panel-brand-mark.cjs +59 -0
- package/dist/panel-brand-mark.cjs.map +1 -0
- package/dist/panel-brand-mark.d.cts +13 -0
- package/dist/panel-brand-mark.d.ts +13 -0
- package/dist/panel-brand-mark.js +8 -0
- package/dist/panel-brand-mark.js.map +1 -0
- package/dist/panel-sign-in.cjs +256 -0
- package/dist/panel-sign-in.cjs.map +1 -0
- package/dist/panel-sign-in.d.cts +31 -0
- package/dist/panel-sign-in.d.ts +31 -0
- package/dist/panel-sign-in.js +14 -0
- package/dist/panel-sign-in.js.map +1 -0
- package/dist/segmented-control.cjs +122 -0
- package/dist/segmented-control.cjs.map +1 -0
- package/dist/segmented-control.d.cts +58 -0
- package/dist/segmented-control.d.ts +58 -0
- package/dist/segmented-control.js +9 -0
- package/dist/segmented-control.js.map +1 -0
- package/dist/select.cjs +648 -0
- package/dist/select.cjs.map +1 -0
- package/dist/select.d.cts +30 -0
- package/dist/select.d.ts +30 -0
- package/dist/select.js +12 -0
- package/dist/select.js.map +1 -0
- package/dist/separator.cjs +70 -0
- package/dist/separator.cjs.map +1 -0
- package/dist/separator.d.cts +13 -0
- package/dist/separator.d.ts +13 -0
- package/dist/separator.js +9 -0
- package/dist/separator.js.map +1 -0
- package/dist/side-drawer.cjs +321 -0
- package/dist/side-drawer.cjs.map +1 -0
- package/dist/side-drawer.d.cts +21 -0
- package/dist/side-drawer.d.ts +21 -0
- package/dist/side-drawer.js +13 -0
- package/dist/side-drawer.js.map +1 -0
- package/dist/spinner.cjs +57 -0
- package/dist/spinner.cjs.map +1 -0
- package/{src/spinner.tsx → dist/spinner.d.cts} +11 -22
- package/dist/spinner.d.ts +27 -0
- package/dist/spinner.js +8 -0
- package/dist/spinner.js.map +1 -0
- package/dist/spreadsheet-grid.cjs +238 -0
- package/dist/spreadsheet-grid.cjs.map +1 -0
- package/dist/spreadsheet-grid.d.cts +48 -0
- package/dist/spreadsheet-grid.d.ts +48 -0
- package/dist/spreadsheet-grid.js +8 -0
- package/dist/spreadsheet-grid.js.map +1 -0
- package/dist/state-panel.cjs +86 -0
- package/dist/state-panel.cjs.map +1 -0
- package/dist/state-panel.d.cts +23 -0
- package/dist/state-panel.d.ts +23 -0
- package/dist/state-panel.js +9 -0
- package/dist/state-panel.js.map +1 -0
- package/dist/switch.cjs +87 -0
- package/dist/switch.cjs.map +1 -0
- package/dist/switch.d.cts +13 -0
- package/dist/switch.d.ts +13 -0
- package/dist/switch.js +9 -0
- package/dist/switch.js.map +1 -0
- package/dist/table.cjs +139 -0
- package/dist/table.cjs.map +1 -0
- package/dist/table.d.cts +16 -0
- package/dist/table.d.ts +16 -0
- package/dist/table.js +22 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.cjs +168 -0
- package/dist/tabs.cjs.map +1 -0
- package/dist/tabs.d.cts +59 -0
- package/dist/tabs.d.ts +59 -0
- package/dist/tabs.js +11 -0
- package/dist/tabs.js.map +1 -0
- package/dist/textarea.cjs +66 -0
- package/dist/textarea.cjs.map +1 -0
- package/dist/textarea.d.cts +18 -0
- package/dist/textarea.d.ts +18 -0
- package/dist/textarea.js +10 -0
- package/dist/textarea.js.map +1 -0
- package/dist/utils.cjs +35 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +5 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +7 -0
- package/dist/utils.js.map +1 -0
- package/package.json +391 -14
- package/src/alert.tsx +0 -74
- package/src/autocomplete.tsx +0 -666
- package/src/badge.tsx +0 -60
- package/src/breadcrumb.tsx +0 -71
- package/src/button.tsx +0 -113
- package/src/card.tsx +0 -79
- package/src/clipboard.ts +0 -144
- package/src/collapsible.tsx +0 -63
- package/src/confirm-dialog.tsx +0 -84
- package/src/copy-button.tsx +0 -58
- package/src/data-table.tsx +0 -190
- package/src/date-range-picker/dateRange.ts +0 -142
- package/src/date-range-picker/index.tsx +0 -366
- package/src/dialogLayer.ts +0 -142
- package/src/feature-access-gate.tsx +0 -38
- package/src/field.tsx +0 -56
- package/src/image-uploader.tsx +0 -181
- package/src/index.ts +0 -37
- package/src/input.tsx +0 -16
- package/src/label.tsx +0 -23
- package/src/modal.tsx +0 -117
- package/src/page-header.tsx +0 -75
- package/src/pagination.tsx +0 -116
- package/src/panel-brand-mark.tsx +0 -32
- package/src/panel-sign-in.tsx +0 -134
- package/src/segmented-control.tsx +0 -155
- package/src/select.tsx +0 -105
- package/src/separator.tsx +0 -32
- package/src/side-drawer.tsx +0 -87
- package/src/spreadsheet-grid.tsx +0 -264
- package/src/state-panel.tsx +0 -46
- package/src/switch.tsx +0 -47
- package/src/table.tsx +0 -110
- package/src/tabs.tsx +0 -201
- package/src/textarea.tsx +0 -32
- package/src/utils.ts +0 -6
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import {
|
|
2
|
+
addDays,
|
|
3
|
+
addMonths,
|
|
4
|
+
formatDisplay,
|
|
5
|
+
fromIsoDate,
|
|
6
|
+
isSameDay,
|
|
7
|
+
monthGrid,
|
|
8
|
+
monthLabel,
|
|
9
|
+
startOfMonth,
|
|
10
|
+
toIsoDate
|
|
11
|
+
} from "./chunk-MUPW2TFJ.js";
|
|
12
|
+
import {
|
|
13
|
+
cn
|
|
14
|
+
} from "./chunk-HCA5ODCD.js";
|
|
15
|
+
|
|
16
|
+
// src/date-range-picker/index.tsx
|
|
17
|
+
import { CalendarDays, ChevronLeft, ChevronRight, X } from "lucide-react";
|
|
18
|
+
import * as React from "react";
|
|
19
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
20
|
+
var PRESETS = [
|
|
21
|
+
{
|
|
22
|
+
label: "Today",
|
|
23
|
+
range: () => {
|
|
24
|
+
const today = toIsoDate(/* @__PURE__ */ new Date());
|
|
25
|
+
return { from: today, to: today };
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
label: "Yesterday",
|
|
30
|
+
range: () => {
|
|
31
|
+
const day = toIsoDate(addDays(/* @__PURE__ */ new Date(), -1));
|
|
32
|
+
return { from: day, to: day };
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
label: "Last 7 days",
|
|
37
|
+
range: () => ({
|
|
38
|
+
from: toIsoDate(addDays(/* @__PURE__ */ new Date(), -6)),
|
|
39
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
40
|
+
})
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
label: "Last 30 days",
|
|
44
|
+
range: () => ({
|
|
45
|
+
from: toIsoDate(addDays(/* @__PURE__ */ new Date(), -29)),
|
|
46
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
47
|
+
})
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
label: "This month",
|
|
51
|
+
range: () => ({
|
|
52
|
+
from: toIsoDate(startOfMonth(/* @__PURE__ */ new Date())),
|
|
53
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
54
|
+
})
|
|
55
|
+
}
|
|
56
|
+
];
|
|
57
|
+
var WEEKDAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
58
|
+
function DateRangePicker({
|
|
59
|
+
value,
|
|
60
|
+
onChange,
|
|
61
|
+
disabled,
|
|
62
|
+
placeholder = "Any date",
|
|
63
|
+
className,
|
|
64
|
+
ariaLabel = "Date range"
|
|
65
|
+
}) {
|
|
66
|
+
const [open, setOpen] = React.useState(false);
|
|
67
|
+
const [hovered, setHovered] = React.useState(null);
|
|
68
|
+
const [pendingFrom, setPendingFrom] = React.useState(null);
|
|
69
|
+
const rootRef = React.useRef(null);
|
|
70
|
+
const from = fromIsoDate(value.from);
|
|
71
|
+
const to = fromIsoDate(value.to);
|
|
72
|
+
const [viewMonth, setViewMonth] = React.useState(
|
|
73
|
+
() => startOfMonth(from ?? /* @__PURE__ */ new Date())
|
|
74
|
+
);
|
|
75
|
+
React.useEffect(() => {
|
|
76
|
+
if (!open) return void 0;
|
|
77
|
+
const onPointerDown = (event) => {
|
|
78
|
+
if (!rootRef.current?.contains(event.target)) setOpen(false);
|
|
79
|
+
};
|
|
80
|
+
const onKeyDown = (event) => {
|
|
81
|
+
if (event.key === "Escape") setOpen(false);
|
|
82
|
+
};
|
|
83
|
+
document.addEventListener("mousedown", onPointerDown);
|
|
84
|
+
document.addEventListener("keydown", onKeyDown);
|
|
85
|
+
return () => {
|
|
86
|
+
document.removeEventListener("mousedown", onPointerDown);
|
|
87
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
88
|
+
};
|
|
89
|
+
}, [open]);
|
|
90
|
+
function openPicker() {
|
|
91
|
+
setViewMonth(startOfMonth(fromIsoDate(value.from) ?? /* @__PURE__ */ new Date()));
|
|
92
|
+
setPendingFrom(null);
|
|
93
|
+
setHovered(null);
|
|
94
|
+
setOpen(true);
|
|
95
|
+
}
|
|
96
|
+
const anchor = pendingFrom ?? (to ? null : from);
|
|
97
|
+
const previewEnd = pendingFrom ? hovered : null;
|
|
98
|
+
function rangeBounds() {
|
|
99
|
+
if (pendingFrom) {
|
|
100
|
+
if (!previewEnd) return [pendingFrom, pendingFrom];
|
|
101
|
+
return previewEnd.getTime() < pendingFrom.getTime() ? [previewEnd, pendingFrom] : [pendingFrom, previewEnd];
|
|
102
|
+
}
|
|
103
|
+
return [from, to];
|
|
104
|
+
}
|
|
105
|
+
const [rangeStart, rangeEnd] = rangeBounds();
|
|
106
|
+
function selectDay(day) {
|
|
107
|
+
if (!anchor) {
|
|
108
|
+
setPendingFrom(day);
|
|
109
|
+
onChange({ from: toIsoDate(day), to: "" });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const [start, end] = day.getTime() < anchor.getTime() ? [day, anchor] : [anchor, day];
|
|
113
|
+
onChange({ from: toIsoDate(start), to: toIsoDate(end) });
|
|
114
|
+
setPendingFrom(null);
|
|
115
|
+
setHovered(null);
|
|
116
|
+
setOpen(false);
|
|
117
|
+
}
|
|
118
|
+
function onGridKeyDown(event) {
|
|
119
|
+
const offsets = {
|
|
120
|
+
ArrowLeft: -1,
|
|
121
|
+
ArrowRight: 1,
|
|
122
|
+
ArrowUp: -7,
|
|
123
|
+
ArrowDown: 7
|
|
124
|
+
};
|
|
125
|
+
const offset = offsets[event.key];
|
|
126
|
+
if (offset === void 0) return;
|
|
127
|
+
const focused = document.activeElement;
|
|
128
|
+
const iso = focused?.dataset?.day;
|
|
129
|
+
const current = fromIsoDate(iso);
|
|
130
|
+
if (!current) return;
|
|
131
|
+
event.preventDefault();
|
|
132
|
+
const next = addDays(current, offset);
|
|
133
|
+
const nextIso = toIsoDate(next);
|
|
134
|
+
if (!rootRef.current?.querySelector(`[data-day="${nextIso}"]`)) {
|
|
135
|
+
setViewMonth(startOfMonth(offset < 0 ? next : addMonths(next, -1)));
|
|
136
|
+
}
|
|
137
|
+
window.requestAnimationFrame(() => {
|
|
138
|
+
rootRef.current?.querySelector(`[data-day="${nextIso}"]`)?.focus();
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
const label = value.from || value.to ? `${formatDisplay(value.from) || "Any"} \u2192 ${formatDisplay(value.to) || "Any"}` : placeholder;
|
|
142
|
+
const today = /* @__PURE__ */ new Date();
|
|
143
|
+
function renderMonth(month) {
|
|
144
|
+
return /* @__PURE__ */ jsxs("div", { className: "w-[15.75rem] shrink-0", children: [
|
|
145
|
+
/* @__PURE__ */ jsx("div", { className: "text-foreground mb-2 text-center text-sm font-medium whitespace-nowrap", children: monthLabel(month) }),
|
|
146
|
+
/* @__PURE__ */ jsx("div", { className: "text-muted-foreground grid grid-cols-7 text-center text-[11px]", children: WEEKDAYS.map((day) => /* @__PURE__ */ jsx("div", { className: "grid size-9 place-items-center", children: day }, day)) }),
|
|
147
|
+
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-7", children: monthGrid(month).map((day) => {
|
|
148
|
+
const iso = toIsoDate(day);
|
|
149
|
+
const outside = day.getMonth() !== month.getMonth();
|
|
150
|
+
const isStart = isSameDay(day, rangeStart);
|
|
151
|
+
const isEnd = isSameDay(day, rangeEnd);
|
|
152
|
+
const inRange = rangeStart != null && rangeEnd != null && day.getTime() > rangeStart.getTime() && day.getTime() < rangeEnd.getTime();
|
|
153
|
+
const isToday = isSameDay(day, today);
|
|
154
|
+
return /* @__PURE__ */ jsx(
|
|
155
|
+
"button",
|
|
156
|
+
{
|
|
157
|
+
type: "button",
|
|
158
|
+
"data-day": iso,
|
|
159
|
+
onClick: () => selectDay(day),
|
|
160
|
+
onMouseEnter: () => setHovered(day),
|
|
161
|
+
"aria-label": day.toDateString(),
|
|
162
|
+
"aria-pressed": isStart || isEnd,
|
|
163
|
+
className: cn(
|
|
164
|
+
"focus-visible:ring-ring relative grid size-9 place-items-center rounded-md text-sm transition-colors focus-visible:ring-2 focus-visible:outline-none",
|
|
165
|
+
outside ? "text-muted-foreground/50" : "text-foreground",
|
|
166
|
+
inRange && "bg-primary/10 rounded-none",
|
|
167
|
+
(isStart || isEnd) && "bg-primary text-primary-foreground font-medium",
|
|
168
|
+
// Square off the inner edge so a range reads as one bar
|
|
169
|
+
// rather than two pills with a gap.
|
|
170
|
+
isStart && rangeEnd && !isEnd && "rounded-r-none",
|
|
171
|
+
isEnd && rangeStart && !isStart && "rounded-l-none",
|
|
172
|
+
!isStart && !isEnd && "hover:bg-muted",
|
|
173
|
+
isToday && !isStart && !isEnd && "ring-border font-semibold ring-1"
|
|
174
|
+
),
|
|
175
|
+
children: day.getDate()
|
|
176
|
+
},
|
|
177
|
+
iso
|
|
178
|
+
);
|
|
179
|
+
}) })
|
|
180
|
+
] }, monthLabel(month));
|
|
181
|
+
}
|
|
182
|
+
return /* @__PURE__ */ jsxs("div", { ref: rootRef, className: cn("relative", className), children: [
|
|
183
|
+
/* @__PURE__ */ jsxs(
|
|
184
|
+
"div",
|
|
185
|
+
{
|
|
186
|
+
className: cn(
|
|
187
|
+
"border-border bg-background flex items-center rounded-md border",
|
|
188
|
+
"focus-within:ring-ring/50 focus-within:border-ring focus-within:ring-2",
|
|
189
|
+
disabled && "opacity-50"
|
|
190
|
+
),
|
|
191
|
+
children: [
|
|
192
|
+
/* @__PURE__ */ jsxs(
|
|
193
|
+
"button",
|
|
194
|
+
{
|
|
195
|
+
type: "button",
|
|
196
|
+
disabled,
|
|
197
|
+
"aria-haspopup": "dialog",
|
|
198
|
+
"aria-expanded": open,
|
|
199
|
+
"aria-label": ariaLabel,
|
|
200
|
+
onClick: () => open ? setOpen(false) : openPicker(),
|
|
201
|
+
className: "flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5 text-left text-sm",
|
|
202
|
+
children: [
|
|
203
|
+
/* @__PURE__ */ jsx(
|
|
204
|
+
CalendarDays,
|
|
205
|
+
{
|
|
206
|
+
className: "text-muted-foreground size-4 shrink-0",
|
|
207
|
+
"aria-hidden": true
|
|
208
|
+
}
|
|
209
|
+
),
|
|
210
|
+
/* @__PURE__ */ jsx(
|
|
211
|
+
"span",
|
|
212
|
+
{
|
|
213
|
+
className: cn(
|
|
214
|
+
"truncate",
|
|
215
|
+
!value.from && !value.to && "text-muted-foreground"
|
|
216
|
+
),
|
|
217
|
+
children: label
|
|
218
|
+
}
|
|
219
|
+
)
|
|
220
|
+
]
|
|
221
|
+
}
|
|
222
|
+
),
|
|
223
|
+
(value.from || value.to) && !disabled ? /* @__PURE__ */ jsx(
|
|
224
|
+
"button",
|
|
225
|
+
{
|
|
226
|
+
type: "button",
|
|
227
|
+
"aria-label": "Clear date range",
|
|
228
|
+
onClick: () => {
|
|
229
|
+
onChange({ from: "", to: "" });
|
|
230
|
+
setPendingFrom(null);
|
|
231
|
+
},
|
|
232
|
+
className: "text-muted-foreground hover:text-foreground shrink-0 px-2",
|
|
233
|
+
children: /* @__PURE__ */ jsx(X, { className: "size-3.5", "aria-hidden": true })
|
|
234
|
+
}
|
|
235
|
+
) : null
|
|
236
|
+
]
|
|
237
|
+
}
|
|
238
|
+
),
|
|
239
|
+
open ? /* @__PURE__ */ jsxs(
|
|
240
|
+
"div",
|
|
241
|
+
{
|
|
242
|
+
role: "dialog",
|
|
243
|
+
"aria-label": ariaLabel,
|
|
244
|
+
className: "border-border bg-background absolute top-full right-0 z-50 mt-1 flex w-max rounded-lg border p-3 shadow-lg",
|
|
245
|
+
children: [
|
|
246
|
+
/* @__PURE__ */ jsx("div", { className: "border-border mr-3 flex w-32 shrink-0 flex-col gap-0.5 border-r pr-3", children: PRESETS.map((preset) => /* @__PURE__ */ jsx(
|
|
247
|
+
"button",
|
|
248
|
+
{
|
|
249
|
+
type: "button",
|
|
250
|
+
className: "hover:bg-muted text-foreground rounded-md px-2 py-1.5 text-left text-xs",
|
|
251
|
+
onClick: () => {
|
|
252
|
+
onChange(preset.range());
|
|
253
|
+
setPendingFrom(null);
|
|
254
|
+
setOpen(false);
|
|
255
|
+
},
|
|
256
|
+
children: preset.label
|
|
257
|
+
},
|
|
258
|
+
preset.label
|
|
259
|
+
)) }),
|
|
260
|
+
/* @__PURE__ */ jsxs("div", { onKeyDown: onGridKeyDown, children: [
|
|
261
|
+
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex items-center justify-between", children: [
|
|
262
|
+
/* @__PURE__ */ jsx(
|
|
263
|
+
"button",
|
|
264
|
+
{
|
|
265
|
+
type: "button",
|
|
266
|
+
"aria-label": "Previous month",
|
|
267
|
+
className: "hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5",
|
|
268
|
+
onClick: () => setViewMonth(addMonths(viewMonth, -1)),
|
|
269
|
+
children: /* @__PURE__ */ jsx(ChevronLeft, { className: "size-4", "aria-hidden": true })
|
|
270
|
+
}
|
|
271
|
+
),
|
|
272
|
+
/* @__PURE__ */ jsx(
|
|
273
|
+
"button",
|
|
274
|
+
{
|
|
275
|
+
type: "button",
|
|
276
|
+
"aria-label": "Next month",
|
|
277
|
+
className: "hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5",
|
|
278
|
+
onClick: () => setViewMonth(addMonths(viewMonth, 1)),
|
|
279
|
+
children: /* @__PURE__ */ jsx(ChevronRight, { className: "size-4", "aria-hidden": true })
|
|
280
|
+
}
|
|
281
|
+
)
|
|
282
|
+
] }),
|
|
283
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-5", onMouseLeave: () => setHovered(null), children: [
|
|
284
|
+
renderMonth(viewMonth),
|
|
285
|
+
renderMonth(addMonths(viewMonth, 1))
|
|
286
|
+
] })
|
|
287
|
+
] })
|
|
288
|
+
]
|
|
289
|
+
}
|
|
290
|
+
) : null
|
|
291
|
+
] });
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
export {
|
|
295
|
+
DateRangePicker
|
|
296
|
+
};
|
|
297
|
+
//# sourceMappingURL=chunk-T2KXVH3O.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/date-range-picker/index.tsx"],"sourcesContent":["\"use client\";\n\nimport { CalendarDays, ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../utils\";\nimport {\n addDays,\n addMonths,\n formatDisplay,\n fromIsoDate,\n isSameDay,\n monthGrid,\n monthLabel,\n startOfMonth,\n toIsoDate,\n} from \"./dateRange\";\n\nexport type DateRangeValue = { from: string; to: string };\n\n/**\n * A two-month range calendar.\n *\n * Two separate date fields cost two columns and read as two unrelated\n * questions when they are one: which window. They also let the pair be set\n * backwards, which returns nothing and looks like a broken filter.\n *\n * Two months rather than one because almost every range anyone picks here\n * crosses a month boundary — \"last week of July into the first of August\" is a\n * single gesture with two months visible and a paging exercise with one.\n *\n * Presets are the useful half. The common ranges are the same handful every\n * time, and picking \"Last 7 days\" out of a list beats counting backwards on a\n * grid.\n */\nconst PRESETS: { label: string; range: () => DateRangeValue }[] = [\n {\n label: \"Today\",\n range: () => {\n const today = toIsoDate(new Date());\n return { from: today, to: today };\n },\n },\n {\n label: \"Yesterday\",\n range: () => {\n const day = toIsoDate(addDays(new Date(), -1));\n return { from: day, to: day };\n },\n },\n {\n label: \"Last 7 days\",\n range: () => ({\n from: toIsoDate(addDays(new Date(), -6)),\n to: toIsoDate(new Date()),\n }),\n },\n {\n label: \"Last 30 days\",\n range: () => ({\n from: toIsoDate(addDays(new Date(), -29)),\n to: toIsoDate(new Date()),\n }),\n },\n {\n label: \"This month\",\n range: () => ({\n from: toIsoDate(startOfMonth(new Date())),\n to: toIsoDate(new Date()),\n }),\n },\n];\n\nconst WEEKDAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\n\nexport interface DateRangePickerProps {\n value: DateRangeValue;\n onChange: (next: DateRangeValue) => void;\n disabled?: boolean;\n placeholder?: string;\n className?: string;\n /** Names the trigger for screen readers when there is no visible label. */\n ariaLabel?: string;\n}\n\nexport function DateRangePicker({\n value,\n onChange,\n disabled,\n placeholder = \"Any date\",\n className,\n ariaLabel = \"Date range\",\n}: DateRangePickerProps) {\n const [open, setOpen] = React.useState(false);\n const [hovered, setHovered] = React.useState<Date | null>(null);\n /** Set while choosing the second end, so the range can preview under the cursor. */\n const [pendingFrom, setPendingFrom] = React.useState<Date | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n const from = fromIsoDate(value.from);\n const to = fromIsoDate(value.to);\n\n const [viewMonth, setViewMonth] = React.useState<Date>(() =>\n startOfMonth(from ?? new Date()),\n );\n\n React.useEffect(() => {\n if (!open) return undefined;\n const onPointerDown = (event: MouseEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) setOpen(false);\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"mousedown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open]);\n\n /**\n * Reopening lands on the current selection rather than wherever the view was\n * left. Done here rather than in an effect: it is a response to an event, and\n * setting state from an effect is what `react-hooks/set-state-in-effect`\n * rejects — correctly, since it costs an extra render every open.\n */\n function openPicker() {\n setViewMonth(startOfMonth(fromIsoDate(value.from) ?? new Date()));\n setPendingFrom(null);\n setHovered(null);\n setOpen(true);\n }\n\n const anchor = pendingFrom ?? (to ? null : from);\n const previewEnd = pendingFrom ? hovered : null;\n\n function rangeBounds(): [Date | null, Date | null] {\n if (pendingFrom) {\n if (!previewEnd) return [pendingFrom, pendingFrom];\n return previewEnd.getTime() < pendingFrom.getTime()\n ? [previewEnd, pendingFrom]\n : [pendingFrom, previewEnd];\n }\n return [from, to];\n }\n\n const [rangeStart, rangeEnd] = rangeBounds();\n\n function selectDay(day: Date) {\n if (!anchor) {\n // Starting a new range. Keeping only `from` means the next click closes\n // it, whichever side of the anchor it lands on.\n setPendingFrom(day);\n onChange({ from: toIsoDate(day), to: \"\" });\n return;\n }\n const [start, end] =\n day.getTime() < anchor.getTime() ? [day, anchor] : [anchor, day];\n onChange({ from: toIsoDate(start), to: toIsoDate(end) });\n setPendingFrom(null);\n setHovered(null);\n setOpen(false);\n }\n\n /** Arrow keys move by day/week across both months, as a calendar should. */\n function onGridKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n const offsets: Record<string, number> = {\n ArrowLeft: -1,\n ArrowRight: 1,\n ArrowUp: -7,\n ArrowDown: 7,\n };\n const offset = offsets[event.key];\n if (offset === undefined) return;\n const focused = document.activeElement as HTMLElement | null;\n const iso = focused?.dataset?.day;\n const current = fromIsoDate(iso);\n if (!current) return;\n event.preventDefault();\n const next = addDays(current, offset);\n const nextIso = toIsoDate(next);\n // Page the view when the move lands outside what is rendered.\n if (!rootRef.current?.querySelector(`[data-day=\"${nextIso}\"]`)) {\n setViewMonth(startOfMonth(offset < 0 ? next : addMonths(next, -1)));\n }\n window.requestAnimationFrame(() => {\n rootRef.current\n ?.querySelector<HTMLElement>(`[data-day=\"${nextIso}\"]`)\n ?.focus();\n });\n }\n\n const label =\n value.from || value.to\n ? `${formatDisplay(value.from) || \"Any\"} → ${formatDisplay(value.to) || \"Any\"}`\n : placeholder;\n\n const today = new Date();\n\n function renderMonth(month: Date) {\n return (\n <div key={monthLabel(month)} className=\"w-[15.75rem] shrink-0\">\n <div className=\"text-foreground mb-2 text-center text-sm font-medium whitespace-nowrap\">\n {monthLabel(month)}\n </div>\n <div className=\"text-muted-foreground grid grid-cols-7 text-center text-[11px]\">\n {WEEKDAYS.map((day) => (\n <div key={day} className=\"grid size-9 place-items-center\">\n {day}\n </div>\n ))}\n </div>\n <div className=\"grid grid-cols-7\">\n {monthGrid(month).map((day) => {\n const iso = toIsoDate(day);\n const outside = day.getMonth() !== month.getMonth();\n const isStart = isSameDay(day, rangeStart);\n const isEnd = isSameDay(day, rangeEnd);\n const inRange =\n rangeStart != null &&\n rangeEnd != null &&\n day.getTime() > rangeStart.getTime() &&\n day.getTime() < rangeEnd.getTime();\n const isToday = isSameDay(day, today);\n\n return (\n <button\n key={iso}\n type=\"button\"\n data-day={iso}\n // Outside days stay clickable — clicking one is how you reach\n // the neighbouring month without paging.\n onClick={() => selectDay(day)}\n onMouseEnter={() => setHovered(day)}\n aria-label={day.toDateString()}\n aria-pressed={isStart || isEnd}\n className={cn(\n \"focus-visible:ring-ring relative grid size-9 place-items-center rounded-md text-sm transition-colors focus-visible:ring-2 focus-visible:outline-none\",\n outside ? \"text-muted-foreground/50\" : \"text-foreground\",\n inRange && \"bg-primary/10 rounded-none\",\n (isStart || isEnd) &&\n \"bg-primary text-primary-foreground font-medium\",\n // Square off the inner edge so a range reads as one bar\n // rather than two pills with a gap.\n isStart && rangeEnd && !isEnd && \"rounded-r-none\",\n isEnd && rangeStart && !isStart && \"rounded-l-none\",\n !isStart && !isEnd && \"hover:bg-muted\",\n isToday &&\n !isStart &&\n !isEnd &&\n \"ring-border font-semibold ring-1\",\n )}\n >\n {day.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n );\n }\n\n return (\n <div ref={rootRef} className={cn(\"relative\", className)}>\n <div\n className={cn(\n \"border-border bg-background flex items-center rounded-md border\",\n \"focus-within:ring-ring/50 focus-within:border-ring focus-within:ring-2\",\n disabled && \"opacity-50\",\n )}\n >\n <button\n type=\"button\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-label={ariaLabel}\n onClick={() => (open ? setOpen(false) : openPicker())}\n className=\"flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5 text-left text-sm\"\n >\n <CalendarDays\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden\n />\n <span\n className={cn(\n \"truncate\",\n !value.from && !value.to && \"text-muted-foreground\",\n )}\n >\n {label}\n </span>\n </button>\n {(value.from || value.to) && !disabled ? (\n <button\n type=\"button\"\n aria-label=\"Clear date range\"\n onClick={() => {\n onChange({ from: \"\", to: \"\" });\n setPendingFrom(null);\n }}\n className=\"text-muted-foreground hover:text-foreground shrink-0 px-2\"\n >\n <X className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n </div>\n\n {open ? (\n <div\n role=\"dialog\"\n aria-label={ariaLabel}\n // `w-max` so the calendar sets its own width instead of inheriting\n // the filter column, which squeezed the months until the numbers ran\n // together. Anchored right because this sits in the last column and\n // would otherwise open off the edge of the viewport.\n className=\"border-border bg-background absolute top-full right-0 z-50 mt-1 flex w-max rounded-lg border p-3 shadow-lg\"\n >\n <div className=\"border-border mr-3 flex w-32 shrink-0 flex-col gap-0.5 border-r pr-3\">\n {PRESETS.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className=\"hover:bg-muted text-foreground rounded-md px-2 py-1.5 text-left text-xs\"\n onClick={() => {\n onChange(preset.range());\n setPendingFrom(null);\n setOpen(false);\n }}\n >\n {preset.label}\n </button>\n ))}\n </div>\n\n <div onKeyDown={onGridKeyDown}>\n <div className=\"mb-2 flex items-center justify-between\">\n <button\n type=\"button\"\n aria-label=\"Previous month\"\n className=\"hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5\"\n onClick={() => setViewMonth(addMonths(viewMonth, -1))}\n >\n <ChevronLeft className=\"size-4\" aria-hidden />\n </button>\n <button\n type=\"button\"\n aria-label=\"Next month\"\n className=\"hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5\"\n onClick={() => setViewMonth(addMonths(viewMonth, 1))}\n >\n <ChevronRight className=\"size-4\" aria-hidden />\n </button>\n </div>\n <div className=\"flex gap-5\" onMouseLeave={() => setHovered(null)}>\n {renderMonth(viewMonth)}\n {renderMonth(addMonths(viewMonth, 1))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAEA,SAAS,cAAc,aAAa,cAAc,SAAS;AAC3D,YAAY,WAAW;AAwMjB,SACE,KADF;AAxKN,IAAM,UAA4D;AAAA,EAChE;AAAA,IACE,OAAO;AAAA,IACP,OAAO,MAAM;AACX,YAAM,QAAQ,UAAU,oBAAI,KAAK,CAAC;AAClC,aAAO,EAAE,MAAM,OAAO,IAAI,MAAM;AAAA,IAClC;AAAA,EACF;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,MAAM;AACX,YAAM,MAAM,UAAU,QAAQ,oBAAI,KAAK,GAAG,EAAE,CAAC;AAC7C,aAAO,EAAE,MAAM,KAAK,IAAI,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,OAAO;AAAA,MACZ,MAAM,UAAU,QAAQ,oBAAI,KAAK,GAAG,EAAE,CAAC;AAAA,MACvC,IAAI,UAAU,oBAAI,KAAK,CAAC;AAAA,IAC1B;AAAA,EACF;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,OAAO;AAAA,MACZ,MAAM,UAAU,QAAQ,oBAAI,KAAK,GAAG,GAAG,CAAC;AAAA,MACxC,IAAI,UAAU,oBAAI,KAAK,CAAC;AAAA,IAC1B;AAAA,EACF;AAAA,EACA;AAAA,IACE,OAAO;AAAA,IACP,OAAO,OAAO;AAAA,MACZ,MAAM,UAAU,aAAa,oBAAI,KAAK,CAAC,CAAC;AAAA,MACxC,IAAI,UAAU,oBAAI,KAAK,CAAC;AAAA,IAC1B;AAAA,EACF;AACF;AAEA,IAAM,WAAW,CAAC,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,IAAI;AAYnD,SAAS,gBAAgB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,YAAY;AACd,GAAyB;AACvB,QAAM,CAAC,MAAM,OAAO,IAAU,eAAS,KAAK;AAC5C,QAAM,CAAC,SAAS,UAAU,IAAU,eAAsB,IAAI;AAE9D,QAAM,CAAC,aAAa,cAAc,IAAU,eAAsB,IAAI;AACtE,QAAM,UAAgB,aAAuB,IAAI;AAEjD,QAAM,OAAO,YAAY,MAAM,IAAI;AACnC,QAAM,KAAK,YAAY,MAAM,EAAE;AAE/B,QAAM,CAAC,WAAW,YAAY,IAAU;AAAA,IAAe,MACrD,aAAa,QAAQ,oBAAI,KAAK,CAAC;AAAA,EACjC;AAEA,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,KAAM,QAAO;AAClB,UAAM,gBAAgB,CAAC,UAAsB;AAC3C,UAAI,CAAC,QAAQ,SAAS,SAAS,MAAM,MAAc,EAAG,SAAQ,KAAK;AAAA,IACrE;AACA,UAAM,YAAY,CAAC,UAAyB;AAC1C,UAAI,MAAM,QAAQ,SAAU,SAAQ,KAAK;AAAA,IAC3C;AACA,aAAS,iBAAiB,aAAa,aAAa;AACpD,aAAS,iBAAiB,WAAW,SAAS;AAC9C,WAAO,MAAM;AACX,eAAS,oBAAoB,aAAa,aAAa;AACvD,eAAS,oBAAoB,WAAW,SAAS;AAAA,IACnD;AAAA,EACF,GAAG,CAAC,IAAI,CAAC;AAQT,WAAS,aAAa;AACpB,iBAAa,aAAa,YAAY,MAAM,IAAI,KAAK,oBAAI,KAAK,CAAC,CAAC;AAChE,mBAAe,IAAI;AACnB,eAAW,IAAI;AACf,YAAQ,IAAI;AAAA,EACd;AAEA,QAAM,SAAS,gBAAgB,KAAK,OAAO;AAC3C,QAAM,aAAa,cAAc,UAAU;AAE3C,WAAS,cAA0C;AACjD,QAAI,aAAa;AACf,UAAI,CAAC,WAAY,QAAO,CAAC,aAAa,WAAW;AACjD,aAAO,WAAW,QAAQ,IAAI,YAAY,QAAQ,IAC9C,CAAC,YAAY,WAAW,IACxB,CAAC,aAAa,UAAU;AAAA,IAC9B;AACA,WAAO,CAAC,MAAM,EAAE;AAAA,EAClB;AAEA,QAAM,CAAC,YAAY,QAAQ,IAAI,YAAY;AAE3C,WAAS,UAAU,KAAW;AAC5B,QAAI,CAAC,QAAQ;AAGX,qBAAe,GAAG;AAClB,eAAS,EAAE,MAAM,UAAU,GAAG,GAAG,IAAI,GAAG,CAAC;AACzC;AAAA,IACF;AACA,UAAM,CAAC,OAAO,GAAG,IACf,IAAI,QAAQ,IAAI,OAAO,QAAQ,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,QAAQ,GAAG;AACjE,aAAS,EAAE,MAAM,UAAU,KAAK,GAAG,IAAI,UAAU,GAAG,EAAE,CAAC;AACvD,mBAAe,IAAI;AACnB,eAAW,IAAI;AACf,YAAQ,KAAK;AAAA,EACf;AAGA,WAAS,cAAc,OAA4C;AACjE,UAAM,UAAkC;AAAA,MACtC,WAAW;AAAA,MACX,YAAY;AAAA,MACZ,SAAS;AAAA,MACT,WAAW;AAAA,IACb;AACA,UAAM,SAAS,QAAQ,MAAM,GAAG;AAChC,QAAI,WAAW,OAAW;AAC1B,UAAM,UAAU,SAAS;AACzB,UAAM,MAAM,SAAS,SAAS;AAC9B,UAAM,UAAU,YAAY,GAAG;AAC/B,QAAI,CAAC,QAAS;AACd,UAAM,eAAe;AACrB,UAAM,OAAO,QAAQ,SAAS,MAAM;AACpC,UAAM,UAAU,UAAU,IAAI;AAE9B,QAAI,CAAC,QAAQ,SAAS,cAAc,cAAc,OAAO,IAAI,GAAG;AAC9D,mBAAa,aAAa,SAAS,IAAI,OAAO,UAAU,MAAM,EAAE,CAAC,CAAC;AAAA,IACpE;AACA,WAAO,sBAAsB,MAAM;AACjC,cAAQ,SACJ,cAA2B,cAAc,OAAO,IAAI,GACpD,MAAM;AAAA,IACZ,CAAC;AAAA,EACH;AAEA,QAAM,QACJ,MAAM,QAAQ,MAAM,KAChB,GAAG,cAAc,MAAM,IAAI,KAAK,KAAK,WAAM,cAAc,MAAM,EAAE,KAAK,KAAK,KAC3E;AAEN,QAAM,QAAQ,oBAAI,KAAK;AAEvB,WAAS,YAAY,OAAa;AAChC,WACE,qBAAC,SAA4B,WAAU,yBACrC;AAAA,0BAAC,SAAI,WAAU,0EACZ,qBAAW,KAAK,GACnB;AAAA,MACA,oBAAC,SAAI,WAAU,kEACZ,mBAAS,IAAI,CAAC,QACb,oBAAC,SAAc,WAAU,kCACtB,iBADO,GAEV,CACD,GACH;AAAA,MACA,oBAAC,SAAI,WAAU,oBACZ,oBAAU,KAAK,EAAE,IAAI,CAAC,QAAQ;AAC7B,cAAM,MAAM,UAAU,GAAG;AACzB,cAAM,UAAU,IAAI,SAAS,MAAM,MAAM,SAAS;AAClD,cAAM,UAAU,UAAU,KAAK,UAAU;AACzC,cAAM,QAAQ,UAAU,KAAK,QAAQ;AACrC,cAAM,UACJ,cAAc,QACd,YAAY,QACZ,IAAI,QAAQ,IAAI,WAAW,QAAQ,KACnC,IAAI,QAAQ,IAAI,SAAS,QAAQ;AACnC,cAAM,UAAU,UAAU,KAAK,KAAK;AAEpC,eACE;AAAA,UAAC;AAAA;AAAA,YAEC,MAAK;AAAA,YACL,YAAU;AAAA,YAGV,SAAS,MAAM,UAAU,GAAG;AAAA,YAC5B,cAAc,MAAM,WAAW,GAAG;AAAA,YAClC,cAAY,IAAI,aAAa;AAAA,YAC7B,gBAAc,WAAW;AAAA,YACzB,WAAW;AAAA,cACT;AAAA,cACA,UAAU,6BAA6B;AAAA,cACvC,WAAW;AAAA,eACV,WAAW,UACV;AAAA;AAAA;AAAA,cAGF,WAAW,YAAY,CAAC,SAAS;AAAA,cACjC,SAAS,cAAc,CAAC,WAAW;AAAA,cACnC,CAAC,WAAW,CAAC,SAAS;AAAA,cACtB,WACE,CAAC,WACD,CAAC,SACD;AAAA,YACJ;AAAA,YAEC,cAAI,QAAQ;AAAA;AAAA,UA1BR;AAAA,QA2BP;AAAA,MAEJ,CAAC,GACH;AAAA,SAxDQ,WAAW,KAAK,CAyD1B;AAAA,EAEJ;AAEA,SACE,qBAAC,SAAI,KAAK,SAAS,WAAW,GAAG,YAAY,SAAS,GACpD;AAAA;AAAA,MAAC;AAAA;AAAA,QACC,WAAW;AAAA,UACT;AAAA,UACA;AAAA,UACA,YAAY;AAAA,QACd;AAAA,QAEA;AAAA;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL;AAAA,cACA,iBAAc;AAAA,cACd,iBAAe;AAAA,cACf,cAAY;AAAA,cACZ,SAAS,MAAO,OAAO,QAAQ,KAAK,IAAI,WAAW;AAAA,cACnD,WAAU;AAAA,cAEV;AAAA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAU;AAAA,oBACV,eAAW;AAAA;AAAA,gBACb;AAAA,gBACA;AAAA,kBAAC;AAAA;AAAA,oBACC,WAAW;AAAA,sBACT;AAAA,sBACA,CAAC,MAAM,QAAQ,CAAC,MAAM,MAAM;AAAA,oBAC9B;AAAA,oBAEC;AAAA;AAAA,gBACH;AAAA;AAAA;AAAA,UACF;AAAA,WACE,MAAM,QAAQ,MAAM,OAAO,CAAC,WAC5B;AAAA,YAAC;AAAA;AAAA,cACC,MAAK;AAAA,cACL,cAAW;AAAA,cACX,SAAS,MAAM;AACb,yBAAS,EAAE,MAAM,IAAI,IAAI,GAAG,CAAC;AAC7B,+BAAe,IAAI;AAAA,cACrB;AAAA,cACA,WAAU;AAAA,cAEV,8BAAC,KAAE,WAAU,YAAW,eAAW,MAAC;AAAA;AAAA,UACtC,IACE;AAAA;AAAA;AAAA,IACN;AAAA,IAEC,OACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,cAAY;AAAA,QAKZ,WAAU;AAAA,QAEV;AAAA,8BAAC,SAAI,WAAU,wEACZ,kBAAQ,IAAI,CAAC,WACZ;AAAA,YAAC;AAAA;AAAA,cAEC,MAAK;AAAA,cACL,WAAU;AAAA,cACV,SAAS,MAAM;AACb,yBAAS,OAAO,MAAM,CAAC;AACvB,+BAAe,IAAI;AACnB,wBAAQ,KAAK;AAAA,cACf;AAAA,cAEC,iBAAO;AAAA;AAAA,YATH,OAAO;AAAA,UAUd,CACD,GACH;AAAA,UAEA,qBAAC,SAAI,WAAW,eACd;AAAA,iCAAC,SAAI,WAAU,0CACb;AAAA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,cAAW;AAAA,kBACX,WAAU;AAAA,kBACV,SAAS,MAAM,aAAa,UAAU,WAAW,EAAE,CAAC;AAAA,kBAEpD,8BAAC,eAAY,WAAU,UAAS,eAAW,MAAC;AAAA;AAAA,cAC9C;AAAA,cACA;AAAA,gBAAC;AAAA;AAAA,kBACC,MAAK;AAAA,kBACL,cAAW;AAAA,kBACX,WAAU;AAAA,kBACV,SAAS,MAAM,aAAa,UAAU,WAAW,CAAC,CAAC;AAAA,kBAEnD,8BAAC,gBAAa,WAAU,UAAS,eAAW,MAAC;AAAA;AAAA,cAC/C;AAAA,eACF;AAAA,YACA,qBAAC,SAAI,WAAU,cAAa,cAAc,MAAM,WAAW,IAAI,GAC5D;AAAA,0BAAY,SAAS;AAAA,cACrB,YAAY,UAAU,WAAW,CAAC,CAAC;AAAA,eACtC;AAAA,aACF;AAAA;AAAA;AAAA,IACF,IACE;AAAA,KACN;AAEJ;","names":[]}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-HCA5ODCD.js";
|
|
4
|
+
|
|
5
|
+
// src/separator.tsx
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var Separator = React.forwardRef(
|
|
9
|
+
({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
10
|
+
"div",
|
|
11
|
+
{
|
|
12
|
+
ref,
|
|
13
|
+
role: decorative ? "none" : "separator",
|
|
14
|
+
"aria-orientation": orientation,
|
|
15
|
+
className: cn(
|
|
16
|
+
"bg-border shrink-0",
|
|
17
|
+
orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
|
|
18
|
+
className
|
|
19
|
+
),
|
|
20
|
+
...props
|
|
21
|
+
}
|
|
22
|
+
)
|
|
23
|
+
);
|
|
24
|
+
Separator.displayName = "Separator";
|
|
25
|
+
|
|
26
|
+
export {
|
|
27
|
+
Separator
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=chunk-T4WCCHJQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/separator.tsx"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\nexport type SeparatorProps = React.HTMLAttributes<HTMLDivElement> & {\n orientation?: \"horizontal\" | \"vertical\";\n decorative?: boolean;\n};\n\n/** Thin rule between sections. */\nexport const Separator = React.forwardRef<HTMLDivElement, SeparatorProps>(\n (\n { className, orientation = \"horizontal\", decorative = true, ...props },\n ref,\n ) => (\n <div\n ref={ref}\n role={decorative ? \"none\" : \"separator\"}\n aria-orientation={orientation}\n className={cn(\n \"bg-border shrink-0\",\n orientation === \"horizontal\" ? \"h-px w-full\" : \"h-full w-px\",\n className,\n )}\n {...props}\n />\n ),\n);\n\nSeparator.displayName = \"Separator\";\n"],"mappings":";;;;;AAEA,YAAY,WAAW;AAenB;AALG,IAAM,YAAkB;AAAA,EAC7B,CACE,EAAE,WAAW,cAAc,cAAc,aAAa,MAAM,GAAG,MAAM,GACrE,QAEA;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,MAAM,aAAa,SAAS;AAAA,MAC5B,oBAAkB;AAAA,MAClB,WAAW;AAAA,QACT;AAAA,QACA,gBAAgB,eAAe,gBAAgB;AAAA,QAC/C;AAAA,MACF;AAAA,MACC,GAAG;AAAA;AAAA,EACN;AAEJ;AAEA,UAAU,cAAc;","names":[]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-HCA5ODCD.js";
|
|
4
|
+
|
|
5
|
+
// src/table.tsx
|
|
6
|
+
import * as React from "react";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var Table = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ jsx(
|
|
9
|
+
"table",
|
|
10
|
+
{
|
|
11
|
+
ref,
|
|
12
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
13
|
+
...props
|
|
14
|
+
}
|
|
15
|
+
) }));
|
|
16
|
+
Table.displayName = "Table";
|
|
17
|
+
var TableHeader = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
|
|
18
|
+
TableHeader.displayName = "TableHeader";
|
|
19
|
+
var TableBody = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
20
|
+
"tbody",
|
|
21
|
+
{
|
|
22
|
+
ref,
|
|
23
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
24
|
+
...props
|
|
25
|
+
}
|
|
26
|
+
));
|
|
27
|
+
TableBody.displayName = "TableBody";
|
|
28
|
+
var TableFooter = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
29
|
+
"tfoot",
|
|
30
|
+
{
|
|
31
|
+
ref,
|
|
32
|
+
className: cn(
|
|
33
|
+
"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
|
|
34
|
+
className
|
|
35
|
+
),
|
|
36
|
+
...props
|
|
37
|
+
}
|
|
38
|
+
));
|
|
39
|
+
TableFooter.displayName = "TableFooter";
|
|
40
|
+
var TableRow = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
41
|
+
"tr",
|
|
42
|
+
{
|
|
43
|
+
ref,
|
|
44
|
+
className: cn(
|
|
45
|
+
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
|
46
|
+
className
|
|
47
|
+
),
|
|
48
|
+
...props
|
|
49
|
+
}
|
|
50
|
+
));
|
|
51
|
+
TableRow.displayName = "TableRow";
|
|
52
|
+
var TableHead = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
53
|
+
"th",
|
|
54
|
+
{
|
|
55
|
+
ref,
|
|
56
|
+
className: cn(
|
|
57
|
+
"text-muted-foreground h-12 px-4 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0",
|
|
58
|
+
className
|
|
59
|
+
),
|
|
60
|
+
...props
|
|
61
|
+
}
|
|
62
|
+
));
|
|
63
|
+
TableHead.displayName = "TableHead";
|
|
64
|
+
var TableCell = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
65
|
+
"td",
|
|
66
|
+
{
|
|
67
|
+
ref,
|
|
68
|
+
className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className),
|
|
69
|
+
...props
|
|
70
|
+
}
|
|
71
|
+
));
|
|
72
|
+
TableCell.displayName = "TableCell";
|
|
73
|
+
var TableCaption = React.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
74
|
+
"caption",
|
|
75
|
+
{
|
|
76
|
+
ref,
|
|
77
|
+
className: cn("text-muted-foreground mt-4 text-sm", className),
|
|
78
|
+
...props
|
|
79
|
+
}
|
|
80
|
+
));
|
|
81
|
+
TableCaption.displayName = "TableCaption";
|
|
82
|
+
|
|
83
|
+
export {
|
|
84
|
+
Table,
|
|
85
|
+
TableHeader,
|
|
86
|
+
TableBody,
|
|
87
|
+
TableFooter,
|
|
88
|
+
TableRow,
|
|
89
|
+
TableHead,
|
|
90
|
+
TableCell,
|
|
91
|
+
TableCaption
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=chunk-UC3ZIQPE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/table.tsx"],"sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * Low-level table primitives. Prefer `DataTable` for list panels; use these\n * when the row markup is custom (nested actions, expandable rows, etc.).\n */\nexport const Table = React.forwardRef<\n HTMLTableElement,\n React.HTMLAttributes<HTMLTableElement>\n>(({ className, ...props }, ref) => (\n <div className=\"relative w-full overflow-auto\">\n <table\n ref={ref}\n className={cn(\"w-full caption-bottom text-sm\", className)}\n {...props}\n />\n </div>\n));\nTable.displayName = \"Table\";\n\nexport const TableHeader = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <thead ref={ref} className={cn(\"[&_tr]:border-b\", className)} {...props} />\n));\nTableHeader.displayName = \"TableHeader\";\n\nexport const TableBody = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tbody\n ref={ref}\n className={cn(\"[&_tr:last-child]:border-0\", className)}\n {...props}\n />\n));\nTableBody.displayName = \"TableBody\";\n\nexport const TableFooter = React.forwardRef<\n HTMLTableSectionElement,\n React.HTMLAttributes<HTMLTableSectionElement>\n>(({ className, ...props }, ref) => (\n <tfoot\n ref={ref}\n className={cn(\n \"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0\",\n className,\n )}\n {...props}\n />\n));\nTableFooter.displayName = \"TableFooter\";\n\nexport const TableRow = React.forwardRef<\n HTMLTableRowElement,\n React.HTMLAttributes<HTMLTableRowElement>\n>(({ className, ...props }, ref) => (\n <tr\n ref={ref}\n className={cn(\n \"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors\",\n className,\n )}\n {...props}\n />\n));\nTableRow.displayName = \"TableRow\";\n\nexport const TableHead = React.forwardRef<\n HTMLTableCellElement,\n React.ThHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <th\n ref={ref}\n className={cn(\n \"text-muted-foreground h-12 px-4 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0\",\n className,\n )}\n {...props}\n />\n));\nTableHead.displayName = \"TableHead\";\n\nexport const TableCell = React.forwardRef<\n HTMLTableCellElement,\n React.TdHTMLAttributes<HTMLTableCellElement>\n>(({ className, ...props }, ref) => (\n <td\n ref={ref}\n className={cn(\"p-4 align-middle [&:has([role=checkbox])]:pr-0\", className)}\n {...props}\n />\n));\nTableCell.displayName = \"TableCell\";\n\nexport const TableCaption = React.forwardRef<\n HTMLTableCaptionElement,\n React.HTMLAttributes<HTMLTableCaptionElement>\n>(({ className, ...props }, ref) => (\n <caption\n ref={ref}\n className={cn(\"text-muted-foreground mt-4 text-sm\", className)}\n {...props}\n />\n));\nTableCaption.displayName = \"TableCaption\";\n"],"mappings":";;;;;AAAA,YAAY,WAAW;AAanB;AALG,IAAM,QAAc,iBAGzB,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,oBAAC,SAAI,WAAU,iCACb;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,iCAAiC,SAAS;AAAA,IACvD,GAAG;AAAA;AACN,GACF,CACD;AACD,MAAM,cAAc;AAEb,IAAM,cAAoB,iBAG/B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B,oBAAC,WAAM,KAAU,WAAW,GAAG,mBAAmB,SAAS,GAAI,GAAG,OAAO,CAC1E;AACD,YAAY,cAAc;AAEnB,IAAM,YAAkB,iBAG7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,8BAA8B,SAAS;AAAA,IACpD,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAEjB,IAAM,cAAoB,iBAG/B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,YAAY,cAAc;AAEnB,IAAM,WAAiB,iBAG5B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,SAAS,cAAc;AAEhB,IAAM,YAAkB,iBAG7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW;AAAA,MACT;AAAA,MACA;AAAA,IACF;AAAA,IACC,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAEjB,IAAM,YAAkB,iBAG7B,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,kDAAkD,SAAS;AAAA,IACxE,GAAG;AAAA;AACN,CACD;AACD,UAAU,cAAc;AAEjB,IAAM,eAAqB,iBAGhC,CAAC,EAAE,WAAW,GAAG,MAAM,GAAG,QAC1B;AAAA,EAAC;AAAA;AAAA,IACC;AAAA,IACA,WAAW,GAAG,sCAAsC,SAAS;AAAA,IAC5D,GAAG;AAAA;AACN,CACD;AACD,aAAa,cAAc;","names":[]}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-HCA5ODCD.js";
|
|
4
|
+
|
|
5
|
+
// src/spinner.tsx
|
|
6
|
+
import { Loader2 } from "lucide-react";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var SIZES = {
|
|
9
|
+
sm: "size-3.5",
|
|
10
|
+
md: "size-4",
|
|
11
|
+
lg: "size-5",
|
|
12
|
+
xl: "size-10 border-2"
|
|
13
|
+
};
|
|
14
|
+
function Spinner({ size = "md", className, ...props }) {
|
|
15
|
+
return /* @__PURE__ */ jsx(
|
|
16
|
+
Loader2,
|
|
17
|
+
{
|
|
18
|
+
"aria-hidden": true,
|
|
19
|
+
className: cn("animate-spin", SIZES[size], className),
|
|
20
|
+
...props
|
|
21
|
+
}
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export {
|
|
26
|
+
Spinner
|
|
27
|
+
};
|
|
28
|
+
//# sourceMappingURL=chunk-UE7JY7VR.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/spinner.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { Loader2 } from \"lucide-react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * The one spinner.\n *\n * There were five spellings of `animate-spin` across twelve files — `h-4 w-4`,\n * `h-5 w-5`, `size-4`, bare, and a hand-drawn ring in `ProtectedRoute` — so the\n * same \"working\" signal came out a different size depending on which panel you\n * were on.\n *\n * It is `aria-hidden` on purpose. A spinner is decoration; what a screen reader\n * needs is the surrounding control's `aria-busy` or the panel's status text,\n * and announcing \"loading\" twice is worse than once. `Button` and `StatePanel`\n * both supply that.\n */\nconst SIZES = {\n sm: \"size-3.5\",\n md: \"size-4\",\n lg: \"size-5\",\n xl: \"size-10 border-2\",\n} as const;\n\nexport interface SpinnerProps extends React.SVGProps<SVGSVGElement> {\n size?: keyof typeof SIZES;\n}\n\nexport function Spinner({ size = \"md\", className, ...props }: SpinnerProps) {\n return (\n <Loader2\n aria-hidden\n className={cn(\"animate-spin\", SIZES[size], className)}\n {...props}\n />\n );\n}\n"],"mappings":";;;;;AACA,SAAS,eAAe;AA8BpB;AAbJ,IAAM,QAAQ;AAAA,EACZ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AAAA,EACJ,IAAI;AACN;AAMO,SAAS,QAAQ,EAAE,OAAO,MAAM,WAAW,GAAG,MAAM,GAAiB;AAC1E,SACE;AAAA,IAAC;AAAA;AAAA,MACC,eAAW;AAAA,MACX,WAAW,GAAG,gBAAgB,MAAM,IAAI,GAAG,SAAS;AAAA,MACnD,GAAG;AAAA;AAAA,EACN;AAEJ;","names":[]}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// src/clipboard.ts
|
|
2
|
+
var TSV_DELIMITER = " ";
|
|
3
|
+
var CSV_DELIMITER = ",";
|
|
4
|
+
function normalizeRange(anchor, focus) {
|
|
5
|
+
if (!anchor || !focus) return null;
|
|
6
|
+
return {
|
|
7
|
+
r1: Math.min(anchor.r, focus.r),
|
|
8
|
+
r2: Math.max(anchor.r, focus.r),
|
|
9
|
+
c1: Math.min(anchor.c, focus.c),
|
|
10
|
+
c2: Math.max(anchor.c, focus.c)
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function escapeCell(raw, delimiter) {
|
|
14
|
+
const value = raw == null ? "" : String(raw);
|
|
15
|
+
if (value.includes(delimiter) || value.includes("\n") || value.includes("\r") || value.includes('"')) {
|
|
16
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
17
|
+
}
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
function buildRangeText(range, columns, rows, delimiter, includeHeaders) {
|
|
21
|
+
if (!range) return "";
|
|
22
|
+
const lines = [];
|
|
23
|
+
if (includeHeaders) {
|
|
24
|
+
const header = [];
|
|
25
|
+
for (let c = range.c1; c <= range.c2; c++) {
|
|
26
|
+
header.push(escapeCell(columns[c]?.title, delimiter));
|
|
27
|
+
}
|
|
28
|
+
lines.push(header.join(delimiter));
|
|
29
|
+
}
|
|
30
|
+
for (let r = range.r1; r <= range.r2; r++) {
|
|
31
|
+
const line = [];
|
|
32
|
+
const row = rows[r];
|
|
33
|
+
for (let c = range.c1; c <= range.c2; c++) {
|
|
34
|
+
const column = columns[c];
|
|
35
|
+
line.push(
|
|
36
|
+
escapeCell(
|
|
37
|
+
column && row !== void 0 ? column.value(row) : "",
|
|
38
|
+
delimiter
|
|
39
|
+
)
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
lines.push(line.join(delimiter));
|
|
43
|
+
}
|
|
44
|
+
return lines.join("\n");
|
|
45
|
+
}
|
|
46
|
+
function fullRange(columns, rows) {
|
|
47
|
+
if (!rows.length || !columns.length) return null;
|
|
48
|
+
return { r1: 0, r2: rows.length - 1, c1: 0, c2: columns.length - 1 };
|
|
49
|
+
}
|
|
50
|
+
function describeRange(range) {
|
|
51
|
+
if (!range) return "No selection";
|
|
52
|
+
const rowCount = range.r2 - range.r1 + 1;
|
|
53
|
+
const colCount = range.c2 - range.c1 + 1;
|
|
54
|
+
if (rowCount === 1 && colCount === 1) return "1 cell selected";
|
|
55
|
+
return `${rowCount} \xD7 ${colCount} selected`;
|
|
56
|
+
}
|
|
57
|
+
function countCells(range) {
|
|
58
|
+
return {
|
|
59
|
+
rows: range.r2 - range.r1 + 1,
|
|
60
|
+
columns: range.c2 - range.c1 + 1
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function writeToClipboard(text) {
|
|
64
|
+
if (navigator.clipboard?.writeText) {
|
|
65
|
+
return navigator.clipboard.writeText(text);
|
|
66
|
+
}
|
|
67
|
+
const textarea = document.createElement("textarea");
|
|
68
|
+
textarea.value = text;
|
|
69
|
+
textarea.style.position = "fixed";
|
|
70
|
+
textarea.style.top = "-1000px";
|
|
71
|
+
document.body.appendChild(textarea);
|
|
72
|
+
textarea.select();
|
|
73
|
+
try {
|
|
74
|
+
if (!document.execCommand("copy")) {
|
|
75
|
+
throw new Error("Could not write to the clipboard");
|
|
76
|
+
}
|
|
77
|
+
} finally {
|
|
78
|
+
document.body.removeChild(textarea);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export {
|
|
83
|
+
TSV_DELIMITER,
|
|
84
|
+
CSV_DELIMITER,
|
|
85
|
+
normalizeRange,
|
|
86
|
+
escapeCell,
|
|
87
|
+
buildRangeText,
|
|
88
|
+
fullRange,
|
|
89
|
+
describeRange,
|
|
90
|
+
countCells,
|
|
91
|
+
writeToClipboard
|
|
92
|
+
};
|
|
93
|
+
//# sourceMappingURL=chunk-Y5WCT6XN.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/clipboard.ts"],"sourcesContent":["/**\n * Range maths and clipboard text for the card table's spreadsheet selection.\n *\n * Ported from video-shorts-panel `app/src/common/components/ExcelTable.jsx`.\n * Kept free of React and the DOM (except `writeToClipboard`) so the escaping\n * and range rules are unit-testable.\n */\n\nexport type CellRef = { r: number; c: number };\n\nexport type CellRange = { r1: number; r2: number; c1: number; c2: number };\n\n/** Tab for the clipboard (Excel/Sheets split on it), comma for a .csv file. */\nexport const TSV_DELIMITER = \"\\t\";\nexport const CSV_DELIMITER = \",\";\n\n/**\n * Anchor and focus can be dragged in any direction, so the range is whichever\n * corners they happen to be — normalize to top-left / bottom-right.\n */\nexport function normalizeRange(\n anchor: CellRef | null | undefined,\n focus: CellRef | null | undefined,\n): CellRange | null {\n if (!anchor || !focus) return null;\n return {\n r1: Math.min(anchor.r, focus.r),\n r2: Math.max(anchor.r, focus.r),\n c1: Math.min(anchor.c, focus.c),\n c2: Math.max(anchor.c, focus.c),\n };\n}\n\n/**\n * A cell needs quoting once it carries the delimiters themselves — the same\n * rule Excel uses when it parses the clipboard. Without it, a title containing\n * a tab or a newline silently becomes extra columns or rows on paste.\n */\nexport function escapeCell(raw: unknown, delimiter: string): string {\n const value = raw == null ? \"\" : String(raw);\n if (\n value.includes(delimiter) ||\n value.includes(\"\\n\") ||\n value.includes(\"\\r\") ||\n value.includes('\"')\n ) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nexport type TextColumn<Row> = {\n title: string;\n value: (row: Row) => string;\n};\n\n/** Renders a range as delimited text, optionally with a header line. */\nexport function buildRangeText<Row>(\n range: CellRange | null,\n columns: TextColumn<Row>[],\n rows: Row[],\n delimiter: string,\n includeHeaders: boolean,\n): string {\n if (!range) return \"\";\n const lines: string[] = [];\n\n if (includeHeaders) {\n const header: string[] = [];\n for (let c = range.c1; c <= range.c2; c++) {\n header.push(escapeCell(columns[c]?.title, delimiter));\n }\n lines.push(header.join(delimiter));\n }\n\n for (let r = range.r1; r <= range.r2; r++) {\n const line: string[] = [];\n const row = rows[r];\n for (let c = range.c1; c <= range.c2; c++) {\n const column = columns[c];\n line.push(\n escapeCell(\n column && row !== undefined ? column.value(row) : \"\",\n delimiter,\n ),\n );\n }\n lines.push(line.join(delimiter));\n }\n\n return lines.join(\"\\n\");\n}\n\n/** The whole grid, or null when there is nothing to select. */\nexport function fullRange<Row>(\n columns: TextColumn<Row>[],\n rows: Row[],\n): CellRange | null {\n if (!rows.length || !columns.length) return null;\n return { r1: 0, r2: rows.length - 1, c1: 0, c2: columns.length - 1 };\n}\n\n/** \"3 × 2 selected\" — what the toolbar reports back to the user. */\nexport function describeRange(range: CellRange | null): string {\n if (!range) return \"No selection\";\n const rowCount = range.r2 - range.r1 + 1;\n const colCount = range.c2 - range.c1 + 1;\n if (rowCount === 1 && colCount === 1) return \"1 cell selected\";\n return `${rowCount} × ${colCount} selected`;\n}\n\nexport function countCells(range: CellRange): {\n rows: number;\n columns: number;\n} {\n return {\n rows: range.r2 - range.r1 + 1,\n columns: range.c2 - range.c1 + 1,\n };\n}\n\n/**\n * `navigator.clipboard` is unavailable on http origins and older browsers, so\n * fall back to a hidden textarea + execCommand rather than failing the copy.\n */\nexport async function writeToClipboard(text: string): Promise<void> {\n if (navigator.clipboard?.writeText) {\n return navigator.clipboard.writeText(text);\n }\n\n const textarea = document.createElement(\"textarea\");\n textarea.value = text;\n textarea.style.position = \"fixed\";\n textarea.style.top = \"-1000px\";\n document.body.appendChild(textarea);\n textarea.select();\n try {\n if (!document.execCommand(\"copy\")) {\n throw new Error(\"Could not write to the clipboard\");\n }\n } finally {\n document.body.removeChild(textarea);\n }\n}\n"],"mappings":";AAaO,IAAM,gBAAgB;AACtB,IAAM,gBAAgB;AAMtB,SAAS,eACd,QACA,OACkB;AAClB,MAAI,CAAC,UAAU,CAAC,MAAO,QAAO;AAC9B,SAAO;AAAA,IACL,IAAI,KAAK,IAAI,OAAO,GAAG,MAAM,CAAC;AAAA,IAC9B,IAAI,KAAK,IAAI,OAAO,GAAG,MAAM,CAAC;AAAA,IAC9B,IAAI,KAAK,IAAI,OAAO,GAAG,MAAM,CAAC;AAAA,IAC9B,IAAI,KAAK,IAAI,OAAO,GAAG,MAAM,CAAC;AAAA,EAChC;AACF;AAOO,SAAS,WAAW,KAAc,WAA2B;AAClE,QAAM,QAAQ,OAAO,OAAO,KAAK,OAAO,GAAG;AAC3C,MACE,MAAM,SAAS,SAAS,KACxB,MAAM,SAAS,IAAI,KACnB,MAAM,SAAS,IAAI,KACnB,MAAM,SAAS,GAAG,GAClB;AACA,WAAO,IAAI,MAAM,QAAQ,MAAM,IAAI,CAAC;AAAA,EACtC;AACA,SAAO;AACT;AAQO,SAAS,eACd,OACA,SACA,MACA,WACA,gBACQ;AACR,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAkB,CAAC;AAEzB,MAAI,gBAAgB;AAClB,UAAM,SAAmB,CAAC;AAC1B,aAAS,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK;AACzC,aAAO,KAAK,WAAW,QAAQ,CAAC,GAAG,OAAO,SAAS,CAAC;AAAA,IACtD;AACA,UAAM,KAAK,OAAO,KAAK,SAAS,CAAC;AAAA,EACnC;AAEA,WAAS,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK;AACzC,UAAM,OAAiB,CAAC;AACxB,UAAM,MAAM,KAAK,CAAC;AAClB,aAAS,IAAI,MAAM,IAAI,KAAK,MAAM,IAAI,KAAK;AACzC,YAAM,SAAS,QAAQ,CAAC;AACxB,WAAK;AAAA,QACH;AAAA,UACE,UAAU,QAAQ,SAAY,OAAO,MAAM,GAAG,IAAI;AAAA,UAClD;AAAA,QACF;AAAA,MACF;AAAA,IACF;AACA,UAAM,KAAK,KAAK,KAAK,SAAS,CAAC;AAAA,EACjC;AAEA,SAAO,MAAM,KAAK,IAAI;AACxB;AAGO,SAAS,UACd,SACA,MACkB;AAClB,MAAI,CAAC,KAAK,UAAU,CAAC,QAAQ,OAAQ,QAAO;AAC5C,SAAO,EAAE,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,QAAQ,SAAS,EAAE;AACrE;AAGO,SAAS,cAAc,OAAiC;AAC7D,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,WAAW,MAAM,KAAK,MAAM,KAAK;AACvC,QAAM,WAAW,MAAM,KAAK,MAAM,KAAK;AACvC,MAAI,aAAa,KAAK,aAAa,EAAG,QAAO;AAC7C,SAAO,GAAG,QAAQ,SAAM,QAAQ;AAClC;AAEO,SAAS,WAAW,OAGzB;AACA,SAAO;AAAA,IACL,MAAM,MAAM,KAAK,MAAM,KAAK;AAAA,IAC5B,SAAS,MAAM,KAAK,MAAM,KAAK;AAAA,EACjC;AACF;AAMA,eAAsB,iBAAiB,MAA6B;AAClE,MAAI,UAAU,WAAW,WAAW;AAClC,WAAO,UAAU,UAAU,UAAU,IAAI;AAAA,EAC3C;AAEA,QAAM,WAAW,SAAS,cAAc,UAAU;AAClD,WAAS,QAAQ;AACjB,WAAS,MAAM,WAAW;AAC1B,WAAS,MAAM,MAAM;AACrB,WAAS,KAAK,YAAY,QAAQ;AAClC,WAAS,OAAO;AAChB,MAAI;AACF,QAAI,CAAC,SAAS,YAAY,MAAM,GAAG;AACjC,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAAA,EACF,UAAE;AACA,aAAS,KAAK,YAAY,QAAQ;AAAA,EACpC;AACF;","names":[]}
|