@inshorts/glint-ui 0.5.4 → 0.6.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 +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-43ZUFY63.js +85 -0
- package/dist/chunk-43ZUFY63.js.map +1 -0
- package/dist/chunk-67ACNS42.js +29 -0
- package/dist/chunk-67ACNS42.js.map +1 -0
- package/dist/chunk-6URKHMCF.js +76 -0
- package/dist/chunk-6URKHMCF.js.map +1 -0
- package/dist/chunk-ASU6CUTZ.js +85 -0
- package/dist/chunk-ASU6CUTZ.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-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-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-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-PVK4WQJZ.js +513 -0
- package/dist/chunk-PVK4WQJZ.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-WVNRFO5F.js +70 -0
- package/dist/chunk-WVNRFO5F.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-YSU4VWRD.js +90 -0
- package/dist/chunk-YSU4VWRD.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 +3012 -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 +126 -0
- package/dist/segmented-control.cjs.map +1 -0
- package/dist/segmented-control.d.cts +60 -0
- package/dist/segmented-control.d.ts +60 -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 +390 -13
- 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
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3012 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
Alert: () => Alert,
|
|
35
|
+
Autocomplete: () => Autocomplete,
|
|
36
|
+
Badge: () => Badge,
|
|
37
|
+
Breadcrumb: () => Breadcrumb,
|
|
38
|
+
Button: () => Button,
|
|
39
|
+
CSV_DELIMITER: () => CSV_DELIMITER,
|
|
40
|
+
Card: () => Card,
|
|
41
|
+
CardContent: () => CardContent,
|
|
42
|
+
CardDescription: () => CardDescription,
|
|
43
|
+
CardFooter: () => CardFooter,
|
|
44
|
+
CardHeader: () => CardHeader,
|
|
45
|
+
CardTitle: () => CardTitle,
|
|
46
|
+
Checkbox: () => Checkbox,
|
|
47
|
+
CollapsibleSection: () => CollapsibleSection,
|
|
48
|
+
ConfirmDialog: () => ConfirmDialog,
|
|
49
|
+
CopyButton: () => CopyButton,
|
|
50
|
+
DataTable: () => DataTable,
|
|
51
|
+
DateRangePicker: () => DateRangePicker,
|
|
52
|
+
FeatureAccessGate: () => FeatureAccessGate,
|
|
53
|
+
Field: () => Field,
|
|
54
|
+
ImageUploader: () => ImageUploader,
|
|
55
|
+
Input: () => Input,
|
|
56
|
+
Label: () => Label,
|
|
57
|
+
Modal: () => Modal,
|
|
58
|
+
PageHeader: () => PageHeader,
|
|
59
|
+
Pagination: () => Pagination,
|
|
60
|
+
PanelBrandMark: () => PanelBrandMark,
|
|
61
|
+
PanelSignIn: () => PanelSignIn,
|
|
62
|
+
PanelSignInSkeleton: () => PanelSignInSkeleton,
|
|
63
|
+
SegmentedControl: () => SegmentedControl,
|
|
64
|
+
Select: () => Select,
|
|
65
|
+
Separator: () => Separator,
|
|
66
|
+
SideDrawer: () => SideDrawer,
|
|
67
|
+
Spinner: () => Spinner,
|
|
68
|
+
SpreadsheetGrid: () => SpreadsheetGrid,
|
|
69
|
+
StatePanel: () => StatePanel,
|
|
70
|
+
Switch: () => Switch,
|
|
71
|
+
TSV_DELIMITER: () => TSV_DELIMITER,
|
|
72
|
+
TabPanel: () => TabPanel,
|
|
73
|
+
Table: () => Table,
|
|
74
|
+
TableBody: () => TableBody,
|
|
75
|
+
TableCaption: () => TableCaption,
|
|
76
|
+
TableCell: () => TableCell,
|
|
77
|
+
TableFooter: () => TableFooter,
|
|
78
|
+
TableHead: () => TableHead,
|
|
79
|
+
TableHeader: () => TableHeader,
|
|
80
|
+
TableRow: () => TableRow,
|
|
81
|
+
Tabs: () => Tabs,
|
|
82
|
+
Textarea: () => Textarea,
|
|
83
|
+
addDays: () => addDays,
|
|
84
|
+
addMonths: () => addMonths,
|
|
85
|
+
alertVariants: () => alertVariants,
|
|
86
|
+
badgeVariants: () => badgeVariants,
|
|
87
|
+
buildRangeText: () => buildRangeText,
|
|
88
|
+
checkboxClass: () => checkboxClass,
|
|
89
|
+
cn: () => cn,
|
|
90
|
+
countCells: () => countCells,
|
|
91
|
+
createdRangeMs: () => createdRangeMs,
|
|
92
|
+
describeRange: () => describeRange,
|
|
93
|
+
endAt2359Ms: () => endAt2359Ms,
|
|
94
|
+
endOfDayMs: () => endOfDayMs,
|
|
95
|
+
escapeCell: () => escapeCell,
|
|
96
|
+
formatDisplay: () => formatDisplay,
|
|
97
|
+
fromIsoDate: () => fromIsoDate,
|
|
98
|
+
fullRange: () => fullRange,
|
|
99
|
+
inputClass: () => inputClass,
|
|
100
|
+
isSameDay: () => isSameDay,
|
|
101
|
+
monthGrid: () => monthGrid,
|
|
102
|
+
monthLabel: () => monthLabel,
|
|
103
|
+
normalizeRange: () => normalizeRange,
|
|
104
|
+
startOfDayMs: () => startOfDayMs,
|
|
105
|
+
startOfMonth: () => startOfMonth,
|
|
106
|
+
textareaClass: () => textareaClass,
|
|
107
|
+
toIsoDate: () => toIsoDate,
|
|
108
|
+
useDialogLayer: () => useDialogLayer,
|
|
109
|
+
useHasMounted: () => useHasMounted,
|
|
110
|
+
writeToClipboard: () => writeToClipboard
|
|
111
|
+
});
|
|
112
|
+
module.exports = __toCommonJS(index_exports);
|
|
113
|
+
|
|
114
|
+
// src/alert.tsx
|
|
115
|
+
var React = __toESM(require("react"), 1);
|
|
116
|
+
var import_class_variance_authority = require("class-variance-authority");
|
|
117
|
+
|
|
118
|
+
// src/utils.ts
|
|
119
|
+
var import_clsx = require("clsx");
|
|
120
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
121
|
+
function cn(...inputs) {
|
|
122
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/alert.tsx
|
|
126
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
127
|
+
var alertVariants = (0, import_class_variance_authority.cva)("rounded-lg border px-3 py-2 text-sm", {
|
|
128
|
+
variants: {
|
|
129
|
+
variant: {
|
|
130
|
+
danger: "border-destructive/30 bg-destructive/5 text-destructive",
|
|
131
|
+
warning: "border-warning/30 bg-warning/5 text-warning",
|
|
132
|
+
success: "border-success/30 bg-success/5 text-success",
|
|
133
|
+
info: "border-info/30 bg-info/5 text-info",
|
|
134
|
+
/**
|
|
135
|
+
* The quiet state of a banner that also has loud ones — "no default
|
|
136
|
+
* campaign set" next to "this is the default". Without it those callers
|
|
137
|
+
* keep a ternary of raw class strings and the shared component only
|
|
138
|
+
* covers half of what they draw.
|
|
139
|
+
*/
|
|
140
|
+
neutral: "border-border bg-muted/40 text-muted-foreground"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
defaultVariants: {
|
|
144
|
+
// Failure is what a banner almost always reports here, and defaulting to
|
|
145
|
+
// it means the noisy case cannot be forgotten.
|
|
146
|
+
variant: "danger"
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
var Alert = React.forwardRef(
|
|
150
|
+
({ className, variant, action, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
151
|
+
"div",
|
|
152
|
+
{
|
|
153
|
+
ref,
|
|
154
|
+
role: variant === "danger" || variant == null ? "alert" : "status",
|
|
155
|
+
className: cn(
|
|
156
|
+
alertVariants({ variant }),
|
|
157
|
+
action && "flex flex-wrap items-center justify-between gap-3",
|
|
158
|
+
className
|
|
159
|
+
),
|
|
160
|
+
...props,
|
|
161
|
+
children: [
|
|
162
|
+
action ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children }) : children,
|
|
163
|
+
action
|
|
164
|
+
]
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
Alert.displayName = "Alert";
|
|
169
|
+
|
|
170
|
+
// src/autocomplete.tsx
|
|
171
|
+
var React4 = __toESM(require("react"), 1);
|
|
172
|
+
var import_react_dom2 = require("react-dom");
|
|
173
|
+
var import_lucide_react = require("lucide-react");
|
|
174
|
+
|
|
175
|
+
// src/modal.tsx
|
|
176
|
+
var React3 = __toESM(require("react"), 1);
|
|
177
|
+
var import_react_dom = require("react-dom");
|
|
178
|
+
|
|
179
|
+
// src/dialogLayer.ts
|
|
180
|
+
var React2 = __toESM(require("react"), 1);
|
|
181
|
+
var layers = [];
|
|
182
|
+
var FOCUSABLE = [
|
|
183
|
+
"a[href]",
|
|
184
|
+
"button:not([disabled])",
|
|
185
|
+
"input:not([disabled])",
|
|
186
|
+
"select:not([disabled])",
|
|
187
|
+
"textarea:not([disabled])",
|
|
188
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
189
|
+
].join(",");
|
|
190
|
+
function isVisible(element) {
|
|
191
|
+
if (element.closest("[hidden]")) return false;
|
|
192
|
+
if (element.getAttribute("aria-hidden") === "true") return false;
|
|
193
|
+
return typeof element.checkVisibility === "function" ? element.checkVisibility() : true;
|
|
194
|
+
}
|
|
195
|
+
function focusableWithin(container) {
|
|
196
|
+
return Array.from(container.querySelectorAll(FOCUSABLE)).filter(
|
|
197
|
+
isVisible
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
function useDialogLayer({
|
|
201
|
+
active,
|
|
202
|
+
containerRef,
|
|
203
|
+
onEscape
|
|
204
|
+
}) {
|
|
205
|
+
const escapeRef = React2.useRef(onEscape);
|
|
206
|
+
React2.useEffect(() => {
|
|
207
|
+
escapeRef.current = onEscape;
|
|
208
|
+
});
|
|
209
|
+
React2.useEffect(() => {
|
|
210
|
+
if (!active) return;
|
|
211
|
+
const layer = /* @__PURE__ */ Symbol("dialog-layer");
|
|
212
|
+
layers.push(layer);
|
|
213
|
+
const isTopLayer = () => layers[layers.length - 1] === layer;
|
|
214
|
+
const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
215
|
+
const container = containerRef.current;
|
|
216
|
+
if (container && !container.contains(document.activeElement)) {
|
|
217
|
+
const [first] = focusableWithin(container);
|
|
218
|
+
(container.hasAttribute("tabindex") ? container : first)?.focus();
|
|
219
|
+
}
|
|
220
|
+
function handleKeyDown(event) {
|
|
221
|
+
if (!isTopLayer()) return;
|
|
222
|
+
if (event.key === "Escape") {
|
|
223
|
+
escapeRef.current?.();
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (event.key !== "Tab") return;
|
|
227
|
+
const panel = containerRef.current;
|
|
228
|
+
if (!panel) return;
|
|
229
|
+
const items = focusableWithin(panel);
|
|
230
|
+
if (items.length === 0) {
|
|
231
|
+
event.preventDefault();
|
|
232
|
+
panel.focus();
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const first = items[0];
|
|
236
|
+
const last = items[items.length - 1];
|
|
237
|
+
const active2 = document.activeElement;
|
|
238
|
+
const outside = !panel.contains(active2);
|
|
239
|
+
if (event.shiftKey && (active2 === first || outside)) {
|
|
240
|
+
event.preventDefault();
|
|
241
|
+
last.focus();
|
|
242
|
+
} else if (!event.shiftKey && (active2 === last || outside)) {
|
|
243
|
+
event.preventDefault();
|
|
244
|
+
first.focus();
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
248
|
+
const previousOverflow = document.body.style.overflow;
|
|
249
|
+
document.body.style.overflow = "hidden";
|
|
250
|
+
return () => {
|
|
251
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
252
|
+
document.body.style.overflow = previousOverflow;
|
|
253
|
+
const index = layers.indexOf(layer);
|
|
254
|
+
if (index !== -1) layers.splice(index, 1);
|
|
255
|
+
if (previouslyFocused?.isConnected) previouslyFocused.focus();
|
|
256
|
+
};
|
|
257
|
+
}, [active, containerRef]);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// src/modal.tsx
|
|
261
|
+
var import_jsx_runtime2 = (
|
|
262
|
+
/*
|
|
263
|
+
`overflow-y-auto` on the overlay, `my-auto` on the panel — not
|
|
264
|
+
`items-center`. A flex item centred with `align-items` overflows equally
|
|
265
|
+
in both directions once it is taller than its container, and the half
|
|
266
|
+
above the top edge cannot be scrolled to: with the page behind it locked,
|
|
267
|
+
an over-tall dialog was simply unreachable at both ends. Auto margins
|
|
268
|
+
centre a short panel the same way and collapse to zero on a tall one,
|
|
269
|
+
which scrolls.
|
|
270
|
+
*/
|
|
271
|
+
require("react/jsx-runtime")
|
|
272
|
+
);
|
|
273
|
+
var emptySubscribe = () => () => {
|
|
274
|
+
};
|
|
275
|
+
function useHasMounted() {
|
|
276
|
+
return React3.useSyncExternalStore(
|
|
277
|
+
emptySubscribe,
|
|
278
|
+
() => true,
|
|
279
|
+
() => false
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
function Modal({
|
|
283
|
+
isOpen,
|
|
284
|
+
labelledBy,
|
|
285
|
+
describedBy,
|
|
286
|
+
closeLabel,
|
|
287
|
+
onClose,
|
|
288
|
+
children,
|
|
289
|
+
dismissible = true,
|
|
290
|
+
role = "dialog",
|
|
291
|
+
panelClassName
|
|
292
|
+
}) {
|
|
293
|
+
const mounted = useHasMounted();
|
|
294
|
+
const panelRef = React3.useRef(null);
|
|
295
|
+
useDialogLayer({
|
|
296
|
+
// Gated on `mounted` too: before that the panel is not rendered, so there
|
|
297
|
+
// would be nothing to move focus into.
|
|
298
|
+
active: isOpen && mounted,
|
|
299
|
+
containerRef: panelRef,
|
|
300
|
+
onEscape: dismissible ? onClose : void 0
|
|
301
|
+
});
|
|
302
|
+
if (!mounted || !isOpen) return null;
|
|
303
|
+
return (0, import_react_dom.createPortal)(
|
|
304
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "fixed inset-0 z-[100] flex justify-center overflow-y-auto p-4", children: [
|
|
305
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
306
|
+
"button",
|
|
307
|
+
{
|
|
308
|
+
type: "button",
|
|
309
|
+
"aria-label": closeLabel,
|
|
310
|
+
tabIndex: -1,
|
|
311
|
+
className: "fixed inset-0 bg-slate-950/50",
|
|
312
|
+
onClick: () => {
|
|
313
|
+
if (dismissible) onClose();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
),
|
|
317
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
318
|
+
"div",
|
|
319
|
+
{
|
|
320
|
+
ref: panelRef,
|
|
321
|
+
role,
|
|
322
|
+
"aria-modal": "true",
|
|
323
|
+
"aria-labelledby": labelledBy,
|
|
324
|
+
"aria-describedby": describedBy,
|
|
325
|
+
tabIndex: -1,
|
|
326
|
+
className: cn(
|
|
327
|
+
"border-border bg-background relative z-10 my-auto w-full rounded-lg border shadow-2xl outline-none",
|
|
328
|
+
panelClassName ?? "max-w-md p-6"
|
|
329
|
+
),
|
|
330
|
+
children
|
|
331
|
+
}
|
|
332
|
+
)
|
|
333
|
+
] }),
|
|
334
|
+
document.body
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/autocomplete.tsx
|
|
339
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
340
|
+
var PREFERRED_LIST_HEIGHT = 224;
|
|
341
|
+
var MIN_LIST_HEIGHT = 120;
|
|
342
|
+
var VIEWPORT_MARGIN = 8;
|
|
343
|
+
var ANCHOR_GAP = 4;
|
|
344
|
+
function normalizeQuery(query) {
|
|
345
|
+
return query.trim().toLowerCase();
|
|
346
|
+
}
|
|
347
|
+
function filterOptions(options, query) {
|
|
348
|
+
const normalized = normalizeQuery(query);
|
|
349
|
+
if (!normalized) return options;
|
|
350
|
+
return options.filter(
|
|
351
|
+
(option) => option.label.toLowerCase().includes(normalized) || option.value.toLowerCase().includes(normalized)
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
function getOptionLabel(options, value) {
|
|
355
|
+
return options.find((option) => option.value === value)?.label ?? value;
|
|
356
|
+
}
|
|
357
|
+
function parseTagTokens(raw) {
|
|
358
|
+
const seen = /* @__PURE__ */ new Set();
|
|
359
|
+
const tokens = [];
|
|
360
|
+
for (const part of raw.split(/[\s,]+/)) {
|
|
361
|
+
const token = part.trim();
|
|
362
|
+
if (!token || seen.has(token)) continue;
|
|
363
|
+
seen.add(token);
|
|
364
|
+
tokens.push(token);
|
|
365
|
+
}
|
|
366
|
+
return tokens;
|
|
367
|
+
}
|
|
368
|
+
function Autocomplete(props) {
|
|
369
|
+
const {
|
|
370
|
+
options,
|
|
371
|
+
placeholder = "Search\u2026",
|
|
372
|
+
disabled = false,
|
|
373
|
+
className,
|
|
374
|
+
emptyMessage = "No results found",
|
|
375
|
+
id,
|
|
376
|
+
ariaLabel,
|
|
377
|
+
size = "default",
|
|
378
|
+
creatable = false,
|
|
379
|
+
clearable = true
|
|
380
|
+
} = props;
|
|
381
|
+
const multiple = props.multiple ?? false;
|
|
382
|
+
const singleValue = multiple ? void 0 : props.value;
|
|
383
|
+
const multipleValue = multiple ? props.value : void 0;
|
|
384
|
+
const selectedValues = React4.useMemo(() => {
|
|
385
|
+
if (multiple) return multipleValue ?? [];
|
|
386
|
+
return singleValue ? [singleValue] : [];
|
|
387
|
+
}, [multiple, multipleValue, singleValue]);
|
|
388
|
+
const onSingleChange = !multiple ? props.onChange : void 0;
|
|
389
|
+
const onMultipleChange = multiple ? props.onChange : void 0;
|
|
390
|
+
const containerRef = React4.useRef(null);
|
|
391
|
+
const dropdownRef = React4.useRef(null);
|
|
392
|
+
const inputRef = React4.useRef(null);
|
|
393
|
+
const listRef = React4.useRef(null);
|
|
394
|
+
const ignoreBlurRef = React4.useRef(false);
|
|
395
|
+
const mounted = useHasMounted();
|
|
396
|
+
const [open, setOpen] = React4.useState(false);
|
|
397
|
+
const [position, setPosition] = React4.useState(null);
|
|
398
|
+
const [query, setQuery] = React4.useState("");
|
|
399
|
+
const [highlightedIndex, setHighlightedIndex] = React4.useState(0);
|
|
400
|
+
const filteredOptions = React4.useMemo(
|
|
401
|
+
() => filterOptions(options, query),
|
|
402
|
+
[options, query]
|
|
403
|
+
);
|
|
404
|
+
const safeHighlightedIndex = highlightedIndex >= filteredOptions.length ? Math.max(filteredOptions.length - 1, 0) : highlightedIndex;
|
|
405
|
+
const close = React4.useCallback(() => {
|
|
406
|
+
setOpen(false);
|
|
407
|
+
setQuery("");
|
|
408
|
+
setHighlightedIndex(0);
|
|
409
|
+
}, []);
|
|
410
|
+
const openDropdown = React4.useCallback(() => {
|
|
411
|
+
if (disabled) return;
|
|
412
|
+
setOpen(true);
|
|
413
|
+
setHighlightedIndex(0);
|
|
414
|
+
}, [disabled]);
|
|
415
|
+
const commitSingleValue = React4.useCallback(
|
|
416
|
+
(value) => {
|
|
417
|
+
if (!multiple) {
|
|
418
|
+
onSingleChange?.(value);
|
|
419
|
+
close();
|
|
420
|
+
}
|
|
421
|
+
},
|
|
422
|
+
[close, multiple, onSingleChange]
|
|
423
|
+
);
|
|
424
|
+
const toggleMultipleValue = React4.useCallback(
|
|
425
|
+
(value) => {
|
|
426
|
+
if (!multiple || !onMultipleChange) return;
|
|
427
|
+
onMultipleChange(
|
|
428
|
+
selectedValues.includes(value) ? selectedValues.filter((item) => item !== value) : [...selectedValues, value]
|
|
429
|
+
);
|
|
430
|
+
setQuery("");
|
|
431
|
+
setHighlightedIndex(0);
|
|
432
|
+
},
|
|
433
|
+
[multiple, onMultipleChange, selectedValues]
|
|
434
|
+
);
|
|
435
|
+
const commitCustomValues = React4.useCallback(
|
|
436
|
+
(raw) => {
|
|
437
|
+
if (!creatable) return;
|
|
438
|
+
if (!multiple) {
|
|
439
|
+
const value = raw.trim();
|
|
440
|
+
if (!value) return;
|
|
441
|
+
commitSingleValue(value);
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
if (!onMultipleChange) return;
|
|
445
|
+
const tokens = parseTagTokens(raw);
|
|
446
|
+
if (!tokens.length) return;
|
|
447
|
+
const next = [...selectedValues];
|
|
448
|
+
for (const token of tokens) {
|
|
449
|
+
if (!next.includes(token)) next.push(token);
|
|
450
|
+
}
|
|
451
|
+
onMultipleChange(next);
|
|
452
|
+
setQuery("");
|
|
453
|
+
setHighlightedIndex(0);
|
|
454
|
+
},
|
|
455
|
+
[commitSingleValue, creatable, multiple, onMultipleChange, selectedValues]
|
|
456
|
+
);
|
|
457
|
+
const removeValue = React4.useCallback(
|
|
458
|
+
(value) => {
|
|
459
|
+
if (!multiple || !onMultipleChange) return;
|
|
460
|
+
onMultipleChange(selectedValues.filter((item) => item !== value));
|
|
461
|
+
window.requestAnimationFrame(() => inputRef.current?.focus());
|
|
462
|
+
},
|
|
463
|
+
[multiple, onMultipleChange, selectedValues]
|
|
464
|
+
);
|
|
465
|
+
const selectOption = React4.useCallback(
|
|
466
|
+
(option) => {
|
|
467
|
+
if (option.disabled) return;
|
|
468
|
+
ignoreBlurRef.current = true;
|
|
469
|
+
window.setTimeout(() => {
|
|
470
|
+
ignoreBlurRef.current = false;
|
|
471
|
+
}, 0);
|
|
472
|
+
if (multiple) {
|
|
473
|
+
toggleMultipleValue(option.value);
|
|
474
|
+
window.requestAnimationFrame(() => inputRef.current?.focus());
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
commitSingleValue(option.value);
|
|
478
|
+
},
|
|
479
|
+
[commitSingleValue, multiple, toggleMultipleValue]
|
|
480
|
+
);
|
|
481
|
+
const selectHighlighted = React4.useCallback(() => {
|
|
482
|
+
const option = filteredOptions[safeHighlightedIndex];
|
|
483
|
+
if (!option) return;
|
|
484
|
+
selectOption(option);
|
|
485
|
+
}, [filteredOptions, safeHighlightedIndex, selectOption]);
|
|
486
|
+
React4.useEffect(() => {
|
|
487
|
+
if (!open) return;
|
|
488
|
+
function handlePointerDown(event) {
|
|
489
|
+
const target = event.target;
|
|
490
|
+
if (containerRef.current?.contains(target) || dropdownRef.current?.contains(target)) {
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
close();
|
|
494
|
+
}
|
|
495
|
+
document.addEventListener("pointerdown", handlePointerDown);
|
|
496
|
+
return () => document.removeEventListener("pointerdown", handlePointerDown);
|
|
497
|
+
}, [close, open]);
|
|
498
|
+
React4.useLayoutEffect(() => {
|
|
499
|
+
if (!open) return;
|
|
500
|
+
const update = () => {
|
|
501
|
+
const anchor = containerRef.current;
|
|
502
|
+
if (!anchor) return;
|
|
503
|
+
const rect = anchor.getBoundingClientRect();
|
|
504
|
+
const below = window.innerHeight - rect.bottom - ANCHOR_GAP - VIEWPORT_MARGIN;
|
|
505
|
+
const above = rect.top - ANCHOR_GAP - VIEWPORT_MARGIN;
|
|
506
|
+
const flip = below < Math.min(PREFERRED_LIST_HEIGHT, MIN_LIST_HEIGHT) && above > below;
|
|
507
|
+
const room = flip ? above : below;
|
|
508
|
+
const width = Math.max(rect.width, size === "compact" ? 220 : 0);
|
|
509
|
+
const left = Math.max(
|
|
510
|
+
VIEWPORT_MARGIN,
|
|
511
|
+
Math.min(rect.left, window.innerWidth - width - VIEWPORT_MARGIN)
|
|
512
|
+
);
|
|
513
|
+
setPosition({
|
|
514
|
+
left,
|
|
515
|
+
width,
|
|
516
|
+
maxHeight: Math.max(
|
|
517
|
+
MIN_LIST_HEIGHT,
|
|
518
|
+
Math.min(PREFERRED_LIST_HEIGHT, room)
|
|
519
|
+
),
|
|
520
|
+
...flip ? { bottom: window.innerHeight - rect.top + ANCHOR_GAP } : { top: rect.bottom + ANCHOR_GAP }
|
|
521
|
+
});
|
|
522
|
+
};
|
|
523
|
+
update();
|
|
524
|
+
window.addEventListener("scroll", update, true);
|
|
525
|
+
window.addEventListener("resize", update);
|
|
526
|
+
return () => {
|
|
527
|
+
window.removeEventListener("scroll", update, true);
|
|
528
|
+
window.removeEventListener("resize", update);
|
|
529
|
+
};
|
|
530
|
+
}, [open, size]);
|
|
531
|
+
React4.useEffect(() => {
|
|
532
|
+
if (!open || !listRef.current) return;
|
|
533
|
+
const highlighted = listRef.current.children[safeHighlightedIndex];
|
|
534
|
+
highlighted?.scrollIntoView({ block: "nearest" });
|
|
535
|
+
}, [safeHighlightedIndex, open]);
|
|
536
|
+
function handleInputKeyDown(event) {
|
|
537
|
+
if (disabled) return;
|
|
538
|
+
switch (event.key) {
|
|
539
|
+
case "ArrowDown":
|
|
540
|
+
event.preventDefault();
|
|
541
|
+
if (!open) {
|
|
542
|
+
openDropdown();
|
|
543
|
+
return;
|
|
544
|
+
}
|
|
545
|
+
setHighlightedIndex(
|
|
546
|
+
Math.min(safeHighlightedIndex + 1, filteredOptions.length - 1)
|
|
547
|
+
);
|
|
548
|
+
break;
|
|
549
|
+
case "ArrowUp":
|
|
550
|
+
event.preventDefault();
|
|
551
|
+
if (!open) {
|
|
552
|
+
openDropdown();
|
|
553
|
+
return;
|
|
554
|
+
}
|
|
555
|
+
setHighlightedIndex(Math.max(safeHighlightedIndex - 1, 0));
|
|
556
|
+
break;
|
|
557
|
+
case "Enter":
|
|
558
|
+
event.preventDefault();
|
|
559
|
+
if (creatable && query.trim()) {
|
|
560
|
+
if (multiple || filteredOptions.length === 0) {
|
|
561
|
+
commitCustomValues(query);
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
if (!open) {
|
|
566
|
+
openDropdown();
|
|
567
|
+
return;
|
|
568
|
+
}
|
|
569
|
+
selectHighlighted();
|
|
570
|
+
break;
|
|
571
|
+
case ",":
|
|
572
|
+
if (creatable && multiple && query.trim()) {
|
|
573
|
+
event.preventDefault();
|
|
574
|
+
commitCustomValues(query);
|
|
575
|
+
}
|
|
576
|
+
break;
|
|
577
|
+
case "Escape":
|
|
578
|
+
event.preventDefault();
|
|
579
|
+
close();
|
|
580
|
+
break;
|
|
581
|
+
case "Backspace":
|
|
582
|
+
if (multiple && query.length === 0 && selectedValues.length > 0) {
|
|
583
|
+
event.preventDefault();
|
|
584
|
+
removeValue(selectedValues[selectedValues.length - 1]);
|
|
585
|
+
}
|
|
586
|
+
break;
|
|
587
|
+
case "Tab":
|
|
588
|
+
close();
|
|
589
|
+
break;
|
|
590
|
+
default:
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
const displayValue = !multiple && !open && !query && selectedValues[0] ? getOptionLabel(options, selectedValues[0]) : query;
|
|
595
|
+
const inputPlaceholder = multiple && selectedValues.length > 0 ? "" : placeholder;
|
|
596
|
+
const createLabel = query.trim();
|
|
597
|
+
const canCreate = creatable && Boolean(createLabel) && !selectedValues.includes(createLabel);
|
|
598
|
+
const listboxId = id ? `${id}-listbox` : void 0;
|
|
599
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
600
|
+
"div",
|
|
601
|
+
{
|
|
602
|
+
ref: containerRef,
|
|
603
|
+
className: cn(
|
|
604
|
+
"relative",
|
|
605
|
+
size === "compact" ? "w-auto min-w-24" : "w-full",
|
|
606
|
+
className
|
|
607
|
+
),
|
|
608
|
+
children: [
|
|
609
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
610
|
+
"div",
|
|
611
|
+
{
|
|
612
|
+
className: cn(
|
|
613
|
+
"border-border bg-background flex w-full cursor-pointer items-center rounded-md border transition-colors",
|
|
614
|
+
"focus-within:border-ring focus-within:ring-ring/30 focus-within:ring-2",
|
|
615
|
+
size === "compact" ? "min-h-0 gap-0.5 border-transparent bg-transparent px-1 py-0.5 text-xs shadow-none" : "min-h-9 gap-1.5 px-2 py-1.5 text-sm shadow-sm",
|
|
616
|
+
disabled && "cursor-not-allowed opacity-50",
|
|
617
|
+
open && "border-ring ring-ring/30 ring-2"
|
|
618
|
+
),
|
|
619
|
+
onPointerDown: (event) => {
|
|
620
|
+
if (disabled) return;
|
|
621
|
+
if (event.target.closest("[data-option]")) return;
|
|
622
|
+
if (event.target.closest("[data-chip-remove]"))
|
|
623
|
+
return;
|
|
624
|
+
if (!event.target.closest("input")) {
|
|
625
|
+
event.preventDefault();
|
|
626
|
+
inputRef.current?.focus();
|
|
627
|
+
}
|
|
628
|
+
openDropdown();
|
|
629
|
+
},
|
|
630
|
+
children: [
|
|
631
|
+
size === "compact" ? null : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Search, { className: "text-muted-foreground size-4 shrink-0" }),
|
|
632
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "flex min-w-0 flex-1 flex-wrap items-center gap-1", children: [
|
|
633
|
+
multiple && selectedValues.map((value) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
634
|
+
"span",
|
|
635
|
+
{
|
|
636
|
+
className: "bg-primary/10 text-primary inline-flex max-w-full items-center gap-1 rounded-md px-2 py-0.5 text-xs font-medium",
|
|
637
|
+
children: [
|
|
638
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "truncate", children: getOptionLabel(options, value) }),
|
|
639
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
640
|
+
"button",
|
|
641
|
+
{
|
|
642
|
+
type: "button",
|
|
643
|
+
"data-chip-remove": true,
|
|
644
|
+
className: "text-primary/70 hover:bg-primary/15 hover:text-primary rounded-sm transition",
|
|
645
|
+
onPointerDown: (event) => {
|
|
646
|
+
event.preventDefault();
|
|
647
|
+
event.stopPropagation();
|
|
648
|
+
removeValue(value);
|
|
649
|
+
},
|
|
650
|
+
"aria-label": `Remove ${getOptionLabel(options, value)}`,
|
|
651
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.X, { className: "size-3" })
|
|
652
|
+
}
|
|
653
|
+
)
|
|
654
|
+
]
|
|
655
|
+
},
|
|
656
|
+
value
|
|
657
|
+
)),
|
|
658
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
659
|
+
"input",
|
|
660
|
+
{
|
|
661
|
+
ref: inputRef,
|
|
662
|
+
id,
|
|
663
|
+
type: "text",
|
|
664
|
+
role: "combobox",
|
|
665
|
+
"aria-label": ariaLabel,
|
|
666
|
+
"aria-expanded": open,
|
|
667
|
+
"aria-controls": listboxId,
|
|
668
|
+
"aria-autocomplete": "list",
|
|
669
|
+
disabled,
|
|
670
|
+
value: displayValue,
|
|
671
|
+
placeholder: inputPlaceholder,
|
|
672
|
+
className: cn(
|
|
673
|
+
"placeholder:text-muted-foreground flex-1 bg-transparent outline-none",
|
|
674
|
+
size === "compact" ? "min-w-0" : "min-w-[6rem]"
|
|
675
|
+
),
|
|
676
|
+
onFocus: openDropdown,
|
|
677
|
+
onBlur: () => {
|
|
678
|
+
if (ignoreBlurRef.current) return;
|
|
679
|
+
close();
|
|
680
|
+
},
|
|
681
|
+
onChange: (event) => {
|
|
682
|
+
setQuery(event.target.value);
|
|
683
|
+
setHighlightedIndex(0);
|
|
684
|
+
if (!open) setOpen(true);
|
|
685
|
+
},
|
|
686
|
+
onKeyDown: handleInputKeyDown,
|
|
687
|
+
onPaste: (event) => {
|
|
688
|
+
if (!creatable || !multiple) return;
|
|
689
|
+
const text = event.clipboardData.getData("text");
|
|
690
|
+
if (!/[\s,]/.test(text)) return;
|
|
691
|
+
event.preventDefault();
|
|
692
|
+
commitCustomValues(text);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
)
|
|
696
|
+
] }),
|
|
697
|
+
clearable && !multiple && selectedValues[0] && !disabled && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
698
|
+
"button",
|
|
699
|
+
{
|
|
700
|
+
type: "button",
|
|
701
|
+
className: "text-muted-foreground hover:bg-muted hover:text-foreground rounded-sm p-0.5 transition",
|
|
702
|
+
onPointerDown: (event) => {
|
|
703
|
+
event.preventDefault();
|
|
704
|
+
event.stopPropagation();
|
|
705
|
+
onSingleChange?.("");
|
|
706
|
+
setQuery("");
|
|
707
|
+
inputRef.current?.focus();
|
|
708
|
+
},
|
|
709
|
+
"aria-label": "Clear selection",
|
|
710
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.X, { className: "size-3.5" })
|
|
711
|
+
}
|
|
712
|
+
),
|
|
713
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
714
|
+
import_lucide_react.ChevronDown,
|
|
715
|
+
{
|
|
716
|
+
className: cn(
|
|
717
|
+
"text-muted-foreground shrink-0 transition-transform",
|
|
718
|
+
size === "compact" ? "size-3" : "size-4",
|
|
719
|
+
open && "rotate-180"
|
|
720
|
+
)
|
|
721
|
+
}
|
|
722
|
+
)
|
|
723
|
+
]
|
|
724
|
+
}
|
|
725
|
+
),
|
|
726
|
+
open && mounted && position ? (0, import_react_dom2.createPortal)(
|
|
727
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
728
|
+
"div",
|
|
729
|
+
{
|
|
730
|
+
ref: dropdownRef,
|
|
731
|
+
"data-autocomplete-dropdown": true,
|
|
732
|
+
style: {
|
|
733
|
+
position: "fixed",
|
|
734
|
+
left: position.left,
|
|
735
|
+
width: position.width,
|
|
736
|
+
top: position.top,
|
|
737
|
+
bottom: position.bottom,
|
|
738
|
+
// Above the modal shell (z-100) it is usually opened inside.
|
|
739
|
+
zIndex: 200
|
|
740
|
+
},
|
|
741
|
+
className: "border-border bg-background overflow-hidden rounded-md border shadow-lg",
|
|
742
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
743
|
+
"ul",
|
|
744
|
+
{
|
|
745
|
+
ref: listRef,
|
|
746
|
+
id: listboxId,
|
|
747
|
+
role: "listbox",
|
|
748
|
+
"aria-multiselectable": multiple || void 0,
|
|
749
|
+
className: "overflow-y-auto p-1",
|
|
750
|
+
style: { maxHeight: position.maxHeight },
|
|
751
|
+
children: filteredOptions.length === 0 && !canCreate ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { className: "text-muted-foreground px-3 py-6 text-center text-sm", children: emptyMessage }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
752
|
+
filteredOptions.map((option, index) => {
|
|
753
|
+
const isSelected = selectedValues.includes(option.value);
|
|
754
|
+
const isHighlighted = index === safeHighlightedIndex;
|
|
755
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
756
|
+
"li",
|
|
757
|
+
{
|
|
758
|
+
"data-option": true,
|
|
759
|
+
role: "option",
|
|
760
|
+
"aria-selected": isSelected,
|
|
761
|
+
"aria-disabled": option.disabled || void 0,
|
|
762
|
+
className: cn(
|
|
763
|
+
"flex cursor-pointer items-center gap-2 rounded-sm transition-colors",
|
|
764
|
+
size === "compact" ? "px-2 py-1 text-xs" : "px-2.5 py-2 text-sm",
|
|
765
|
+
isHighlighted && "bg-muted",
|
|
766
|
+
option.disabled && "cursor-not-allowed opacity-50"
|
|
767
|
+
),
|
|
768
|
+
onMouseEnter: () => setHighlightedIndex(index),
|
|
769
|
+
onPointerDown: (event) => {
|
|
770
|
+
event.preventDefault();
|
|
771
|
+
event.stopPropagation();
|
|
772
|
+
selectOption(option);
|
|
773
|
+
},
|
|
774
|
+
children: [
|
|
775
|
+
multiple ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
776
|
+
"span",
|
|
777
|
+
{
|
|
778
|
+
className: cn(
|
|
779
|
+
"border-border flex size-4 shrink-0 items-center justify-center rounded border",
|
|
780
|
+
isSelected && "border-primary bg-primary text-primary-foreground"
|
|
781
|
+
),
|
|
782
|
+
children: isSelected ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_lucide_react.Check, { className: "size-3" }) : null
|
|
783
|
+
}
|
|
784
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
785
|
+
import_lucide_react.Check,
|
|
786
|
+
{
|
|
787
|
+
className: cn(
|
|
788
|
+
"text-primary size-4 shrink-0",
|
|
789
|
+
isSelected ? "opacity-100" : "opacity-0"
|
|
790
|
+
)
|
|
791
|
+
}
|
|
792
|
+
),
|
|
793
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "truncate", children: option.label })
|
|
794
|
+
]
|
|
795
|
+
},
|
|
796
|
+
option.value
|
|
797
|
+
);
|
|
798
|
+
}),
|
|
799
|
+
canCreate ? /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
800
|
+
"li",
|
|
801
|
+
{
|
|
802
|
+
"data-option": true,
|
|
803
|
+
role: "option",
|
|
804
|
+
"aria-selected": false,
|
|
805
|
+
className: "hover:bg-muted flex cursor-pointer items-center gap-2 rounded-sm px-2.5 py-2 text-sm transition-colors",
|
|
806
|
+
onPointerDown: (event) => {
|
|
807
|
+
event.preventDefault();
|
|
808
|
+
event.stopPropagation();
|
|
809
|
+
ignoreBlurRef.current = true;
|
|
810
|
+
window.setTimeout(() => {
|
|
811
|
+
ignoreBlurRef.current = false;
|
|
812
|
+
}, 0);
|
|
813
|
+
commitCustomValues(query);
|
|
814
|
+
window.requestAnimationFrame(
|
|
815
|
+
() => inputRef.current?.focus()
|
|
816
|
+
);
|
|
817
|
+
},
|
|
818
|
+
children: [
|
|
819
|
+
"Add \u201C",
|
|
820
|
+
createLabel,
|
|
821
|
+
"\u201D"
|
|
822
|
+
]
|
|
823
|
+
}
|
|
824
|
+
) : null
|
|
825
|
+
] })
|
|
826
|
+
}
|
|
827
|
+
)
|
|
828
|
+
}
|
|
829
|
+
),
|
|
830
|
+
document.body
|
|
831
|
+
) : null
|
|
832
|
+
]
|
|
833
|
+
}
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// src/badge.tsx
|
|
838
|
+
var React5 = __toESM(require("react"), 1);
|
|
839
|
+
var import_class_variance_authority2 = require("class-variance-authority");
|
|
840
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
841
|
+
var badgeVariants = (0, import_class_variance_authority2.cva)(
|
|
842
|
+
"inline-flex items-center gap-1 rounded font-medium whitespace-nowrap",
|
|
843
|
+
{
|
|
844
|
+
variants: {
|
|
845
|
+
variant: {
|
|
846
|
+
neutral: "bg-muted text-muted-foreground",
|
|
847
|
+
success: "bg-success/15 text-success",
|
|
848
|
+
warning: "bg-warning/15 text-warning",
|
|
849
|
+
danger: "bg-destructive/15 text-destructive",
|
|
850
|
+
info: "bg-info/15 text-info"
|
|
851
|
+
},
|
|
852
|
+
size: {
|
|
853
|
+
/** Inline chips — a category, a tenant, a permission. */
|
|
854
|
+
sm: "px-1.5 py-0.5 text-xs",
|
|
855
|
+
/** A row's status. */
|
|
856
|
+
md: "px-2 py-0.5 text-xs"
|
|
857
|
+
}
|
|
858
|
+
},
|
|
859
|
+
defaultVariants: {
|
|
860
|
+
variant: "neutral",
|
|
861
|
+
size: "md"
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
);
|
|
865
|
+
var Badge = React5.forwardRef(
|
|
866
|
+
({ className, variant, size, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
867
|
+
"span",
|
|
868
|
+
{
|
|
869
|
+
ref,
|
|
870
|
+
className: cn(badgeVariants({ variant, size }), className),
|
|
871
|
+
...props
|
|
872
|
+
}
|
|
873
|
+
)
|
|
874
|
+
);
|
|
875
|
+
Badge.displayName = "Badge";
|
|
876
|
+
|
|
877
|
+
// src/breadcrumb.tsx
|
|
878
|
+
var import_lucide_react2 = require("lucide-react");
|
|
879
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
880
|
+
function Breadcrumb({ items, className }) {
|
|
881
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("nav", { "aria-label": "Breadcrumb", className: cn("text-sm", className), children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ol", { className: "flex flex-wrap items-center gap-1.5", children: items.map((item, index) => {
|
|
882
|
+
const isLast = index === items.length - 1;
|
|
883
|
+
const isInteractive = !isLast && (item.href || item.onClick);
|
|
884
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
885
|
+
"li",
|
|
886
|
+
{
|
|
887
|
+
className: "flex items-center gap-1.5",
|
|
888
|
+
children: [
|
|
889
|
+
index > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
890
|
+
import_lucide_react2.ChevronRight,
|
|
891
|
+
{
|
|
892
|
+
className: "text-muted-foreground/70 size-3.5 shrink-0",
|
|
893
|
+
"aria-hidden": true
|
|
894
|
+
}
|
|
895
|
+
),
|
|
896
|
+
isInteractive ? item.href ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
897
|
+
"a",
|
|
898
|
+
{
|
|
899
|
+
href: item.href,
|
|
900
|
+
className: "text-muted-foreground hover:text-foreground transition",
|
|
901
|
+
children: item.label
|
|
902
|
+
}
|
|
903
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
904
|
+
"button",
|
|
905
|
+
{
|
|
906
|
+
type: "button",
|
|
907
|
+
onClick: item.onClick,
|
|
908
|
+
className: "text-muted-foreground hover:text-foreground transition",
|
|
909
|
+
children: item.label
|
|
910
|
+
}
|
|
911
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
912
|
+
"span",
|
|
913
|
+
{
|
|
914
|
+
className: cn(
|
|
915
|
+
isLast ? "text-foreground font-medium" : "text-muted-foreground"
|
|
916
|
+
),
|
|
917
|
+
"aria-current": isLast ? "page" : void 0,
|
|
918
|
+
children: item.label
|
|
919
|
+
}
|
|
920
|
+
)
|
|
921
|
+
]
|
|
922
|
+
},
|
|
923
|
+
`${item.label}-${index}`
|
|
924
|
+
);
|
|
925
|
+
}) }) });
|
|
926
|
+
}
|
|
927
|
+
|
|
928
|
+
// src/button.tsx
|
|
929
|
+
var React6 = __toESM(require("react"), 1);
|
|
930
|
+
var import_class_variance_authority3 = require("class-variance-authority");
|
|
931
|
+
var import_react_slot = require("@radix-ui/react-slot");
|
|
932
|
+
|
|
933
|
+
// src/spinner.tsx
|
|
934
|
+
var import_lucide_react3 = require("lucide-react");
|
|
935
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
936
|
+
var SIZES = {
|
|
937
|
+
sm: "size-3.5",
|
|
938
|
+
md: "size-4",
|
|
939
|
+
lg: "size-5",
|
|
940
|
+
xl: "size-10 border-2"
|
|
941
|
+
};
|
|
942
|
+
function Spinner({ size = "md", className, ...props }) {
|
|
943
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
944
|
+
import_lucide_react3.Loader2,
|
|
945
|
+
{
|
|
946
|
+
"aria-hidden": true,
|
|
947
|
+
className: cn("animate-spin", SIZES[size], className),
|
|
948
|
+
...props
|
|
949
|
+
}
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// src/button.tsx
|
|
954
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
955
|
+
var buttonVariants = (0, import_class_variance_authority3.cva)(
|
|
956
|
+
"inline-flex h-9 cursor-pointer items-center justify-center gap-2 whitespace-nowrap rounded-md px-3 text-sm font-medium transition duration-200 active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50",
|
|
957
|
+
{
|
|
958
|
+
variants: {
|
|
959
|
+
variant: {
|
|
960
|
+
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
|
961
|
+
secondary: "bg-muted text-foreground hover:bg-muted/80",
|
|
962
|
+
ghost: "hover:bg-muted",
|
|
963
|
+
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
|
964
|
+
outline: "border border-border bg-background hover:bg-muted"
|
|
965
|
+
},
|
|
966
|
+
size: {
|
|
967
|
+
sm: "h-8 px-2.5",
|
|
968
|
+
md: "h-9 px-3",
|
|
969
|
+
lg: "h-10 px-4",
|
|
970
|
+
icon: "h-9 w-9 px-0",
|
|
971
|
+
// Square, matching `sm`'s height — for an icon-only control sitting in
|
|
972
|
+
// a table row or beside `sm` buttons, where `icon` is a row taller.
|
|
973
|
+
"icon-sm": "h-8 w-8 px-0"
|
|
974
|
+
}
|
|
975
|
+
},
|
|
976
|
+
defaultVariants: {
|
|
977
|
+
variant: "default",
|
|
978
|
+
size: "md"
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
);
|
|
982
|
+
var ICON_SIZES = /* @__PURE__ */ new Set(["icon", "icon-sm"]);
|
|
983
|
+
var Button = React6.forwardRef(
|
|
984
|
+
({
|
|
985
|
+
className,
|
|
986
|
+
variant,
|
|
987
|
+
size,
|
|
988
|
+
asChild = false,
|
|
989
|
+
loading,
|
|
990
|
+
disabled,
|
|
991
|
+
children,
|
|
992
|
+
...props
|
|
993
|
+
}, ref) => {
|
|
994
|
+
const Comp = asChild ? import_react_slot.Slot : "button";
|
|
995
|
+
if (asChild) {
|
|
996
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
997
|
+
Comp,
|
|
998
|
+
{
|
|
999
|
+
ref,
|
|
1000
|
+
className: cn(buttonVariants({ variant, size }), className),
|
|
1001
|
+
...props,
|
|
1002
|
+
children
|
|
1003
|
+
}
|
|
1004
|
+
);
|
|
1005
|
+
}
|
|
1006
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
1007
|
+
"button",
|
|
1008
|
+
{
|
|
1009
|
+
ref,
|
|
1010
|
+
disabled: disabled || loading,
|
|
1011
|
+
"aria-busy": loading || void 0,
|
|
1012
|
+
className: cn(buttonVariants({ variant, size }), className),
|
|
1013
|
+
...props,
|
|
1014
|
+
children: [
|
|
1015
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Spinner, { size: "sm" }) : null,
|
|
1016
|
+
loading && size != null && ICON_SIZES.has(size) ? null : children
|
|
1017
|
+
]
|
|
1018
|
+
}
|
|
1019
|
+
);
|
|
1020
|
+
}
|
|
1021
|
+
);
|
|
1022
|
+
Button.displayName = "Button";
|
|
1023
|
+
|
|
1024
|
+
// src/card.tsx
|
|
1025
|
+
var React7 = __toESM(require("react"), 1);
|
|
1026
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
1027
|
+
var Card = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1028
|
+
"div",
|
|
1029
|
+
{
|
|
1030
|
+
ref,
|
|
1031
|
+
className: cn(
|
|
1032
|
+
"bg-card text-card-foreground rounded-xl border shadow",
|
|
1033
|
+
className
|
|
1034
|
+
),
|
|
1035
|
+
...props
|
|
1036
|
+
}
|
|
1037
|
+
));
|
|
1038
|
+
Card.displayName = "Card";
|
|
1039
|
+
var CardHeader = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1040
|
+
"div",
|
|
1041
|
+
{
|
|
1042
|
+
ref,
|
|
1043
|
+
className: cn("flex flex-col space-y-1.5 p-6", className),
|
|
1044
|
+
...props
|
|
1045
|
+
}
|
|
1046
|
+
));
|
|
1047
|
+
CardHeader.displayName = "CardHeader";
|
|
1048
|
+
var CardTitle = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1049
|
+
"div",
|
|
1050
|
+
{
|
|
1051
|
+
ref,
|
|
1052
|
+
className: cn("leading-none font-semibold tracking-tight", className),
|
|
1053
|
+
...props
|
|
1054
|
+
}
|
|
1055
|
+
));
|
|
1056
|
+
CardTitle.displayName = "CardTitle";
|
|
1057
|
+
var CardDescription = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1058
|
+
"div",
|
|
1059
|
+
{
|
|
1060
|
+
ref,
|
|
1061
|
+
className: cn("text-muted-foreground text-sm", className),
|
|
1062
|
+
...props
|
|
1063
|
+
}
|
|
1064
|
+
));
|
|
1065
|
+
CardDescription.displayName = "CardDescription";
|
|
1066
|
+
var CardContent = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("div", { ref, className: cn("p-6 pt-0", className), ...props }));
|
|
1067
|
+
CardContent.displayName = "CardContent";
|
|
1068
|
+
var CardFooter = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
|
|
1069
|
+
"div",
|
|
1070
|
+
{
|
|
1071
|
+
ref,
|
|
1072
|
+
className: cn("flex items-center p-6 pt-0", className),
|
|
1073
|
+
...props
|
|
1074
|
+
}
|
|
1075
|
+
));
|
|
1076
|
+
CardFooter.displayName = "CardFooter";
|
|
1077
|
+
|
|
1078
|
+
// src/checkbox.tsx
|
|
1079
|
+
var React8 = __toESM(require("react"), 1);
|
|
1080
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
1081
|
+
var checkboxClass = "accent-primary border-border focus-visible:ring-ring size-4 shrink-0 cursor-pointer rounded border focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50";
|
|
1082
|
+
var Checkbox = React8.forwardRef(
|
|
1083
|
+
({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
1084
|
+
"input",
|
|
1085
|
+
{
|
|
1086
|
+
ref,
|
|
1087
|
+
type: "checkbox",
|
|
1088
|
+
className: cn(checkboxClass, className),
|
|
1089
|
+
...props
|
|
1090
|
+
}
|
|
1091
|
+
)
|
|
1092
|
+
);
|
|
1093
|
+
Checkbox.displayName = "Checkbox";
|
|
1094
|
+
|
|
1095
|
+
// src/clipboard.ts
|
|
1096
|
+
var TSV_DELIMITER = " ";
|
|
1097
|
+
var CSV_DELIMITER = ",";
|
|
1098
|
+
function normalizeRange(anchor, focus) {
|
|
1099
|
+
if (!anchor || !focus) return null;
|
|
1100
|
+
return {
|
|
1101
|
+
r1: Math.min(anchor.r, focus.r),
|
|
1102
|
+
r2: Math.max(anchor.r, focus.r),
|
|
1103
|
+
c1: Math.min(anchor.c, focus.c),
|
|
1104
|
+
c2: Math.max(anchor.c, focus.c)
|
|
1105
|
+
};
|
|
1106
|
+
}
|
|
1107
|
+
function escapeCell(raw, delimiter) {
|
|
1108
|
+
const value = raw == null ? "" : String(raw);
|
|
1109
|
+
if (value.includes(delimiter) || value.includes("\n") || value.includes("\r") || value.includes('"')) {
|
|
1110
|
+
return `"${value.replace(/"/g, '""')}"`;
|
|
1111
|
+
}
|
|
1112
|
+
return value;
|
|
1113
|
+
}
|
|
1114
|
+
function buildRangeText(range, columns, rows, delimiter, includeHeaders) {
|
|
1115
|
+
if (!range) return "";
|
|
1116
|
+
const lines = [];
|
|
1117
|
+
if (includeHeaders) {
|
|
1118
|
+
const header = [];
|
|
1119
|
+
for (let c = range.c1; c <= range.c2; c++) {
|
|
1120
|
+
header.push(escapeCell(columns[c]?.title, delimiter));
|
|
1121
|
+
}
|
|
1122
|
+
lines.push(header.join(delimiter));
|
|
1123
|
+
}
|
|
1124
|
+
for (let r = range.r1; r <= range.r2; r++) {
|
|
1125
|
+
const line = [];
|
|
1126
|
+
const row = rows[r];
|
|
1127
|
+
for (let c = range.c1; c <= range.c2; c++) {
|
|
1128
|
+
const column = columns[c];
|
|
1129
|
+
line.push(
|
|
1130
|
+
escapeCell(
|
|
1131
|
+
column && row !== void 0 ? column.value(row) : "",
|
|
1132
|
+
delimiter
|
|
1133
|
+
)
|
|
1134
|
+
);
|
|
1135
|
+
}
|
|
1136
|
+
lines.push(line.join(delimiter));
|
|
1137
|
+
}
|
|
1138
|
+
return lines.join("\n");
|
|
1139
|
+
}
|
|
1140
|
+
function fullRange(columns, rows) {
|
|
1141
|
+
if (!rows.length || !columns.length) return null;
|
|
1142
|
+
return { r1: 0, r2: rows.length - 1, c1: 0, c2: columns.length - 1 };
|
|
1143
|
+
}
|
|
1144
|
+
function describeRange(range) {
|
|
1145
|
+
if (!range) return "No selection";
|
|
1146
|
+
const rowCount = range.r2 - range.r1 + 1;
|
|
1147
|
+
const colCount = range.c2 - range.c1 + 1;
|
|
1148
|
+
if (rowCount === 1 && colCount === 1) return "1 cell selected";
|
|
1149
|
+
return `${rowCount} \xD7 ${colCount} selected`;
|
|
1150
|
+
}
|
|
1151
|
+
function countCells(range) {
|
|
1152
|
+
return {
|
|
1153
|
+
rows: range.r2 - range.r1 + 1,
|
|
1154
|
+
columns: range.c2 - range.c1 + 1
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
async function writeToClipboard(text) {
|
|
1158
|
+
if (navigator.clipboard?.writeText) {
|
|
1159
|
+
return navigator.clipboard.writeText(text);
|
|
1160
|
+
}
|
|
1161
|
+
const textarea = document.createElement("textarea");
|
|
1162
|
+
textarea.value = text;
|
|
1163
|
+
textarea.style.position = "fixed";
|
|
1164
|
+
textarea.style.top = "-1000px";
|
|
1165
|
+
document.body.appendChild(textarea);
|
|
1166
|
+
textarea.select();
|
|
1167
|
+
try {
|
|
1168
|
+
if (!document.execCommand("copy")) {
|
|
1169
|
+
throw new Error("Could not write to the clipboard");
|
|
1170
|
+
}
|
|
1171
|
+
} finally {
|
|
1172
|
+
document.body.removeChild(textarea);
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// src/collapsible.tsx
|
|
1177
|
+
var import_lucide_react4 = require("lucide-react");
|
|
1178
|
+
var React9 = __toESM(require("react"), 1);
|
|
1179
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1180
|
+
function CollapsibleSection({
|
|
1181
|
+
title,
|
|
1182
|
+
icon,
|
|
1183
|
+
defaultOpen = true,
|
|
1184
|
+
right,
|
|
1185
|
+
className,
|
|
1186
|
+
children
|
|
1187
|
+
}) {
|
|
1188
|
+
const [open, setOpen] = React9.useState(defaultOpen);
|
|
1189
|
+
const bodyId = React9.useId();
|
|
1190
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: cn("border-border rounded-lg border", className), children: [
|
|
1191
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
|
|
1192
|
+
"button",
|
|
1193
|
+
{
|
|
1194
|
+
type: "button",
|
|
1195
|
+
"aria-expanded": open,
|
|
1196
|
+
"aria-controls": bodyId,
|
|
1197
|
+
onClick: () => setOpen((current) => !current),
|
|
1198
|
+
className: "hover:bg-muted/50 flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm font-semibold transition",
|
|
1199
|
+
children: [
|
|
1200
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1201
|
+
import_lucide_react4.ChevronDown,
|
|
1202
|
+
{
|
|
1203
|
+
size: 14,
|
|
1204
|
+
"aria-hidden": true,
|
|
1205
|
+
className: cn(
|
|
1206
|
+
"shrink-0 transition-transform",
|
|
1207
|
+
open ? "" : "-rotate-90"
|
|
1208
|
+
)
|
|
1209
|
+
}
|
|
1210
|
+
),
|
|
1211
|
+
icon,
|
|
1212
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "flex-1", children: title }),
|
|
1213
|
+
right
|
|
1214
|
+
]
|
|
1215
|
+
}
|
|
1216
|
+
),
|
|
1217
|
+
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { id: bodyId, hidden: !open, className: "space-y-3 px-3 pt-1 pb-3", children })
|
|
1218
|
+
] });
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
// src/confirm-dialog.tsx
|
|
1222
|
+
var React10 = __toESM(require("react"), 1);
|
|
1223
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1224
|
+
function ConfirmDialog({
|
|
1225
|
+
isOpen,
|
|
1226
|
+
title,
|
|
1227
|
+
description,
|
|
1228
|
+
confirmLabel = "Delete",
|
|
1229
|
+
cancelLabel = "Cancel",
|
|
1230
|
+
isConfirming,
|
|
1231
|
+
error,
|
|
1232
|
+
onConfirm,
|
|
1233
|
+
onClose
|
|
1234
|
+
}) {
|
|
1235
|
+
const titleId = React10.useId();
|
|
1236
|
+
const descriptionId = React10.useId();
|
|
1237
|
+
const errorId = React10.useId();
|
|
1238
|
+
const describedBy = [
|
|
1239
|
+
description ? descriptionId : null,
|
|
1240
|
+
error ? errorId : null
|
|
1241
|
+
].filter(Boolean).join(" ");
|
|
1242
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1243
|
+
Modal,
|
|
1244
|
+
{
|
|
1245
|
+
isOpen,
|
|
1246
|
+
role: "alertdialog",
|
|
1247
|
+
labelledBy: titleId,
|
|
1248
|
+
describedBy: describedBy || void 0,
|
|
1249
|
+
closeLabel: "Close dialog",
|
|
1250
|
+
onClose,
|
|
1251
|
+
children: [
|
|
1252
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)("h3", { id: titleId, className: "text-lg font-semibold", children: title }),
|
|
1253
|
+
description ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { id: descriptionId, className: "text-muted-foreground mt-2 text-sm", children: description }) : null,
|
|
1254
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1255
|
+
"div",
|
|
1256
|
+
{
|
|
1257
|
+
id: errorId,
|
|
1258
|
+
role: "alert",
|
|
1259
|
+
className: "border-destructive/30 bg-destructive/5 text-destructive mt-4 rounded-lg border px-3 py-2 text-sm",
|
|
1260
|
+
children: error
|
|
1261
|
+
}
|
|
1262
|
+
) : null,
|
|
1263
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "mt-6 flex justify-end gap-2", children: [
|
|
1264
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { variant: "outline", onClick: onClose, disabled: isConfirming, children: cancelLabel }),
|
|
1265
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1266
|
+
Button,
|
|
1267
|
+
{
|
|
1268
|
+
variant: "destructive",
|
|
1269
|
+
onClick: onConfirm,
|
|
1270
|
+
loading: isConfirming,
|
|
1271
|
+
children: confirmLabel
|
|
1272
|
+
}
|
|
1273
|
+
)
|
|
1274
|
+
] })
|
|
1275
|
+
]
|
|
1276
|
+
}
|
|
1277
|
+
);
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
// src/copy-button.tsx
|
|
1281
|
+
var import_lucide_react5 = require("lucide-react");
|
|
1282
|
+
var React11 = __toESM(require("react"), 1);
|
|
1283
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
1284
|
+
function CopyButton({
|
|
1285
|
+
value,
|
|
1286
|
+
label,
|
|
1287
|
+
className
|
|
1288
|
+
}) {
|
|
1289
|
+
const [copied, setCopied] = React11.useState(false);
|
|
1290
|
+
React11.useEffect(() => {
|
|
1291
|
+
if (!copied) return;
|
|
1292
|
+
const timer = window.setTimeout(() => setCopied(false), 1500);
|
|
1293
|
+
return () => window.clearTimeout(timer);
|
|
1294
|
+
}, [copied]);
|
|
1295
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1296
|
+
"button",
|
|
1297
|
+
{
|
|
1298
|
+
type: "button",
|
|
1299
|
+
"aria-label": copied ? `${label} copied` : `Copy ${label}`,
|
|
1300
|
+
title: copied ? "Copied" : `Copy ${label}`,
|
|
1301
|
+
className: cn(
|
|
1302
|
+
"text-muted-foreground hover:text-foreground hover:bg-muted focus-visible:ring-ring shrink-0 cursor-pointer rounded p-1 transition focus-visible:ring-2 focus-visible:outline-none",
|
|
1303
|
+
className
|
|
1304
|
+
),
|
|
1305
|
+
onClick: () => {
|
|
1306
|
+
void writeToClipboard(value).then(() => setCopied(true)).catch(() => void 0);
|
|
1307
|
+
},
|
|
1308
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.Check, { className: "size-3.5 text-success", "aria-hidden": true }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(import_lucide_react5.Copy, { className: "size-3.5", "aria-hidden": true })
|
|
1309
|
+
}
|
|
1310
|
+
);
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
// src/data-table.tsx
|
|
1314
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1315
|
+
var HEADER_VARIANTS = {
|
|
1316
|
+
uppercase: "border-border bg-muted/40 text-muted-foreground border-b text-xs tracking-wide uppercase",
|
|
1317
|
+
plain: "text-muted-foreground border-border border-b text-left"
|
|
1318
|
+
};
|
|
1319
|
+
var DENSITY = {
|
|
1320
|
+
comfortable: "px-4 py-3",
|
|
1321
|
+
compact: "px-3 py-2"
|
|
1322
|
+
};
|
|
1323
|
+
var ALIGN = {
|
|
1324
|
+
left: "text-left",
|
|
1325
|
+
right: "text-right",
|
|
1326
|
+
center: "text-center"
|
|
1327
|
+
};
|
|
1328
|
+
function DataTable({
|
|
1329
|
+
columns,
|
|
1330
|
+
rows,
|
|
1331
|
+
rowKey,
|
|
1332
|
+
variant = "uppercase",
|
|
1333
|
+
density = "comfortable",
|
|
1334
|
+
stickyHeader = false,
|
|
1335
|
+
rowClassName,
|
|
1336
|
+
emptyMessage,
|
|
1337
|
+
footer,
|
|
1338
|
+
ariaLabel,
|
|
1339
|
+
className,
|
|
1340
|
+
tableClassName
|
|
1341
|
+
}) {
|
|
1342
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1343
|
+
"div",
|
|
1344
|
+
{
|
|
1345
|
+
className: cn(
|
|
1346
|
+
"border-border bg-background/80 overflow-x-auto rounded-lg border",
|
|
1347
|
+
className
|
|
1348
|
+
),
|
|
1349
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1350
|
+
"table",
|
|
1351
|
+
{
|
|
1352
|
+
"aria-label": ariaLabel,
|
|
1353
|
+
className: cn("min-w-full text-left text-sm", tableClassName),
|
|
1354
|
+
children: [
|
|
1355
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1356
|
+
"thead",
|
|
1357
|
+
{
|
|
1358
|
+
className: cn(
|
|
1359
|
+
HEADER_VARIANTS[variant],
|
|
1360
|
+
stickyHeader && "bg-muted sticky top-0 z-10"
|
|
1361
|
+
),
|
|
1362
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tr", { children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1363
|
+
"th",
|
|
1364
|
+
{
|
|
1365
|
+
scope: "col",
|
|
1366
|
+
"aria-sort": column.ariaSort,
|
|
1367
|
+
className: cn(
|
|
1368
|
+
DENSITY[density],
|
|
1369
|
+
"font-medium",
|
|
1370
|
+
ALIGN[column.align ?? "left"],
|
|
1371
|
+
column.headerClassName
|
|
1372
|
+
),
|
|
1373
|
+
children: column.title
|
|
1374
|
+
},
|
|
1375
|
+
column.key
|
|
1376
|
+
)) })
|
|
1377
|
+
}
|
|
1378
|
+
),
|
|
1379
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tbody", { children: rows.length === 0 && emptyMessage != null ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1380
|
+
"td",
|
|
1381
|
+
{
|
|
1382
|
+
colSpan: columns.length,
|
|
1383
|
+
className: "text-muted-foreground px-4 py-6 text-center text-sm",
|
|
1384
|
+
children: emptyMessage
|
|
1385
|
+
}
|
|
1386
|
+
) }) : rows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1387
|
+
"tr",
|
|
1388
|
+
{
|
|
1389
|
+
className: cn(
|
|
1390
|
+
"border-border/70 border-b last:border-0",
|
|
1391
|
+
rowClassName?.(row, index)
|
|
1392
|
+
),
|
|
1393
|
+
children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1394
|
+
"td",
|
|
1395
|
+
{
|
|
1396
|
+
className: cn(
|
|
1397
|
+
DENSITY[density],
|
|
1398
|
+
ALIGN[column.align ?? "left"],
|
|
1399
|
+
column.className
|
|
1400
|
+
),
|
|
1401
|
+
children: column.cell(row, index)
|
|
1402
|
+
},
|
|
1403
|
+
column.key
|
|
1404
|
+
))
|
|
1405
|
+
},
|
|
1406
|
+
rowKey(row, index)
|
|
1407
|
+
)) }),
|
|
1408
|
+
footer != null ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("tfoot", { children: footer }) : null
|
|
1409
|
+
]
|
|
1410
|
+
}
|
|
1411
|
+
)
|
|
1412
|
+
}
|
|
1413
|
+
);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
// src/date-range-picker/index.tsx
|
|
1417
|
+
var import_lucide_react6 = require("lucide-react");
|
|
1418
|
+
var React12 = __toESM(require("react"), 1);
|
|
1419
|
+
|
|
1420
|
+
// src/date-range-picker/dateRange.ts
|
|
1421
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
1422
|
+
function toIsoDate(date) {
|
|
1423
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
1424
|
+
}
|
|
1425
|
+
function fromIsoDate(value) {
|
|
1426
|
+
if (!value) return null;
|
|
1427
|
+
const trimmed = value.trim();
|
|
1428
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed);
|
|
1429
|
+
if (!match) return null;
|
|
1430
|
+
const date = new Date(
|
|
1431
|
+
Number(match[1]),
|
|
1432
|
+
Number(match[2]) - 1,
|
|
1433
|
+
Number(match[3])
|
|
1434
|
+
);
|
|
1435
|
+
return toIsoDate(date) === trimmed ? date : null;
|
|
1436
|
+
}
|
|
1437
|
+
function startOfMonth(date) {
|
|
1438
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
1439
|
+
}
|
|
1440
|
+
function addMonths(date, count) {
|
|
1441
|
+
return new Date(date.getFullYear(), date.getMonth() + count, 1);
|
|
1442
|
+
}
|
|
1443
|
+
function addDays(date, count) {
|
|
1444
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + count);
|
|
1445
|
+
}
|
|
1446
|
+
function isSameDay(a, b) {
|
|
1447
|
+
if (!a || !b) return false;
|
|
1448
|
+
return toIsoDate(a) === toIsoDate(b);
|
|
1449
|
+
}
|
|
1450
|
+
function monthGrid(month) {
|
|
1451
|
+
const first = startOfMonth(month);
|
|
1452
|
+
const start = addDays(first, -first.getDay());
|
|
1453
|
+
return Array.from({ length: 42 }, (_, index) => addDays(start, index));
|
|
1454
|
+
}
|
|
1455
|
+
function monthLabel(month, locale = "en-IN") {
|
|
1456
|
+
return month.toLocaleDateString(locale, { month: "long", year: "numeric" });
|
|
1457
|
+
}
|
|
1458
|
+
function formatDisplay(value, locale = "en-IN") {
|
|
1459
|
+
const date = fromIsoDate(value);
|
|
1460
|
+
if (!date) return "";
|
|
1461
|
+
return date.toLocaleDateString(locale, {
|
|
1462
|
+
day: "numeric",
|
|
1463
|
+
month: "short",
|
|
1464
|
+
year: "numeric"
|
|
1465
|
+
});
|
|
1466
|
+
}
|
|
1467
|
+
function startOfDayMs(value) {
|
|
1468
|
+
const date = fromIsoDate(value);
|
|
1469
|
+
return date ? date.getTime() : 0;
|
|
1470
|
+
}
|
|
1471
|
+
function endOfDayMs(value) {
|
|
1472
|
+
const date = fromIsoDate(value);
|
|
1473
|
+
if (!date) return 0;
|
|
1474
|
+
return new Date(
|
|
1475
|
+
date.getFullYear(),
|
|
1476
|
+
date.getMonth(),
|
|
1477
|
+
date.getDate(),
|
|
1478
|
+
23,
|
|
1479
|
+
59,
|
|
1480
|
+
59,
|
|
1481
|
+
999
|
|
1482
|
+
).getTime();
|
|
1483
|
+
}
|
|
1484
|
+
function endAt2359Ms(value) {
|
|
1485
|
+
const date = fromIsoDate(value);
|
|
1486
|
+
if (!date) return 0;
|
|
1487
|
+
return new Date(
|
|
1488
|
+
date.getFullYear(),
|
|
1489
|
+
date.getMonth(),
|
|
1490
|
+
date.getDate(),
|
|
1491
|
+
23,
|
|
1492
|
+
59,
|
|
1493
|
+
59,
|
|
1494
|
+
0
|
|
1495
|
+
).getTime();
|
|
1496
|
+
}
|
|
1497
|
+
function createdRangeMs(from, to) {
|
|
1498
|
+
const startDate = from.trim() || to.trim();
|
|
1499
|
+
const endDate = to.trim() || from.trim();
|
|
1500
|
+
return {
|
|
1501
|
+
start_time: startOfDayMs(startDate),
|
|
1502
|
+
end_time: endAt2359Ms(endDate)
|
|
1503
|
+
};
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
// src/date-range-picker/index.tsx
|
|
1507
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
1508
|
+
var PRESETS = [
|
|
1509
|
+
{
|
|
1510
|
+
label: "Today",
|
|
1511
|
+
range: () => {
|
|
1512
|
+
const today = toIsoDate(/* @__PURE__ */ new Date());
|
|
1513
|
+
return { from: today, to: today };
|
|
1514
|
+
}
|
|
1515
|
+
},
|
|
1516
|
+
{
|
|
1517
|
+
label: "Yesterday",
|
|
1518
|
+
range: () => {
|
|
1519
|
+
const day = toIsoDate(addDays(/* @__PURE__ */ new Date(), -1));
|
|
1520
|
+
return { from: day, to: day };
|
|
1521
|
+
}
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
label: "Last 7 days",
|
|
1525
|
+
range: () => ({
|
|
1526
|
+
from: toIsoDate(addDays(/* @__PURE__ */ new Date(), -6)),
|
|
1527
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
1528
|
+
})
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
label: "Last 30 days",
|
|
1532
|
+
range: () => ({
|
|
1533
|
+
from: toIsoDate(addDays(/* @__PURE__ */ new Date(), -29)),
|
|
1534
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
1535
|
+
})
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
label: "This month",
|
|
1539
|
+
range: () => ({
|
|
1540
|
+
from: toIsoDate(startOfMonth(/* @__PURE__ */ new Date())),
|
|
1541
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
1542
|
+
})
|
|
1543
|
+
}
|
|
1544
|
+
];
|
|
1545
|
+
var WEEKDAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
1546
|
+
function DateRangePicker({
|
|
1547
|
+
value,
|
|
1548
|
+
onChange,
|
|
1549
|
+
disabled,
|
|
1550
|
+
placeholder = "Any date",
|
|
1551
|
+
className,
|
|
1552
|
+
ariaLabel = "Date range"
|
|
1553
|
+
}) {
|
|
1554
|
+
const [open, setOpen] = React12.useState(false);
|
|
1555
|
+
const [hovered, setHovered] = React12.useState(null);
|
|
1556
|
+
const [pendingFrom, setPendingFrom] = React12.useState(null);
|
|
1557
|
+
const rootRef = React12.useRef(null);
|
|
1558
|
+
const from = fromIsoDate(value.from);
|
|
1559
|
+
const to = fromIsoDate(value.to);
|
|
1560
|
+
const [viewMonth, setViewMonth] = React12.useState(
|
|
1561
|
+
() => startOfMonth(from ?? /* @__PURE__ */ new Date())
|
|
1562
|
+
);
|
|
1563
|
+
React12.useEffect(() => {
|
|
1564
|
+
if (!open) return void 0;
|
|
1565
|
+
const onPointerDown = (event) => {
|
|
1566
|
+
if (!rootRef.current?.contains(event.target)) setOpen(false);
|
|
1567
|
+
};
|
|
1568
|
+
const onKeyDown = (event) => {
|
|
1569
|
+
if (event.key === "Escape") setOpen(false);
|
|
1570
|
+
};
|
|
1571
|
+
document.addEventListener("mousedown", onPointerDown);
|
|
1572
|
+
document.addEventListener("keydown", onKeyDown);
|
|
1573
|
+
return () => {
|
|
1574
|
+
document.removeEventListener("mousedown", onPointerDown);
|
|
1575
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
1576
|
+
};
|
|
1577
|
+
}, [open]);
|
|
1578
|
+
function openPicker() {
|
|
1579
|
+
setViewMonth(startOfMonth(fromIsoDate(value.from) ?? /* @__PURE__ */ new Date()));
|
|
1580
|
+
setPendingFrom(null);
|
|
1581
|
+
setHovered(null);
|
|
1582
|
+
setOpen(true);
|
|
1583
|
+
}
|
|
1584
|
+
const anchor = pendingFrom ?? (to ? null : from);
|
|
1585
|
+
const previewEnd = pendingFrom ? hovered : null;
|
|
1586
|
+
function rangeBounds() {
|
|
1587
|
+
if (pendingFrom) {
|
|
1588
|
+
if (!previewEnd) return [pendingFrom, pendingFrom];
|
|
1589
|
+
return previewEnd.getTime() < pendingFrom.getTime() ? [previewEnd, pendingFrom] : [pendingFrom, previewEnd];
|
|
1590
|
+
}
|
|
1591
|
+
return [from, to];
|
|
1592
|
+
}
|
|
1593
|
+
const [rangeStart, rangeEnd] = rangeBounds();
|
|
1594
|
+
function selectDay(day) {
|
|
1595
|
+
if (!anchor) {
|
|
1596
|
+
setPendingFrom(day);
|
|
1597
|
+
onChange({ from: toIsoDate(day), to: "" });
|
|
1598
|
+
return;
|
|
1599
|
+
}
|
|
1600
|
+
const [start, end] = day.getTime() < anchor.getTime() ? [day, anchor] : [anchor, day];
|
|
1601
|
+
onChange({ from: toIsoDate(start), to: toIsoDate(end) });
|
|
1602
|
+
setPendingFrom(null);
|
|
1603
|
+
setHovered(null);
|
|
1604
|
+
setOpen(false);
|
|
1605
|
+
}
|
|
1606
|
+
function onGridKeyDown(event) {
|
|
1607
|
+
const offsets = {
|
|
1608
|
+
ArrowLeft: -1,
|
|
1609
|
+
ArrowRight: 1,
|
|
1610
|
+
ArrowUp: -7,
|
|
1611
|
+
ArrowDown: 7
|
|
1612
|
+
};
|
|
1613
|
+
const offset = offsets[event.key];
|
|
1614
|
+
if (offset === void 0) return;
|
|
1615
|
+
const focused = document.activeElement;
|
|
1616
|
+
const iso = focused?.dataset?.day;
|
|
1617
|
+
const current = fromIsoDate(iso);
|
|
1618
|
+
if (!current) return;
|
|
1619
|
+
event.preventDefault();
|
|
1620
|
+
const next = addDays(current, offset);
|
|
1621
|
+
const nextIso = toIsoDate(next);
|
|
1622
|
+
if (!rootRef.current?.querySelector(`[data-day="${nextIso}"]`)) {
|
|
1623
|
+
setViewMonth(startOfMonth(offset < 0 ? next : addMonths(next, -1)));
|
|
1624
|
+
}
|
|
1625
|
+
window.requestAnimationFrame(() => {
|
|
1626
|
+
rootRef.current?.querySelector(`[data-day="${nextIso}"]`)?.focus();
|
|
1627
|
+
});
|
|
1628
|
+
}
|
|
1629
|
+
const label = value.from || value.to ? `${formatDisplay(value.from) || "Any"} \u2192 ${formatDisplay(value.to) || "Any"}` : placeholder;
|
|
1630
|
+
const today = /* @__PURE__ */ new Date();
|
|
1631
|
+
function renderMonth(month) {
|
|
1632
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "w-[15.75rem] shrink-0", children: [
|
|
1633
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "text-foreground mb-2 text-center text-sm font-medium whitespace-nowrap", children: monthLabel(month) }),
|
|
1634
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "text-muted-foreground grid grid-cols-7 text-center text-[11px]", children: WEEKDAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "grid size-9 place-items-center", children: day }, day)) }),
|
|
1635
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { className: "grid grid-cols-7", children: monthGrid(month).map((day) => {
|
|
1636
|
+
const iso = toIsoDate(day);
|
|
1637
|
+
const outside = day.getMonth() !== month.getMonth();
|
|
1638
|
+
const isStart = isSameDay(day, rangeStart);
|
|
1639
|
+
const isEnd = isSameDay(day, rangeEnd);
|
|
1640
|
+
const inRange = rangeStart != null && rangeEnd != null && day.getTime() > rangeStart.getTime() && day.getTime() < rangeEnd.getTime();
|
|
1641
|
+
const isToday = isSameDay(day, today);
|
|
1642
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1643
|
+
"button",
|
|
1644
|
+
{
|
|
1645
|
+
type: "button",
|
|
1646
|
+
"data-day": iso,
|
|
1647
|
+
onClick: () => selectDay(day),
|
|
1648
|
+
onMouseEnter: () => setHovered(day),
|
|
1649
|
+
"aria-label": day.toDateString(),
|
|
1650
|
+
"aria-pressed": isStart || isEnd,
|
|
1651
|
+
className: cn(
|
|
1652
|
+
"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",
|
|
1653
|
+
outside ? "text-muted-foreground/50" : "text-foreground",
|
|
1654
|
+
inRange && "bg-primary/10 rounded-none",
|
|
1655
|
+
(isStart || isEnd) && "bg-primary text-primary-foreground font-medium",
|
|
1656
|
+
// Square off the inner edge so a range reads as one bar
|
|
1657
|
+
// rather than two pills with a gap.
|
|
1658
|
+
isStart && rangeEnd && !isEnd && "rounded-r-none",
|
|
1659
|
+
isEnd && rangeStart && !isStart && "rounded-l-none",
|
|
1660
|
+
!isStart && !isEnd && "hover:bg-muted",
|
|
1661
|
+
isToday && !isStart && !isEnd && "ring-border font-semibold ring-1"
|
|
1662
|
+
),
|
|
1663
|
+
children: day.getDate()
|
|
1664
|
+
},
|
|
1665
|
+
iso
|
|
1666
|
+
);
|
|
1667
|
+
}) })
|
|
1668
|
+
] }, monthLabel(month));
|
|
1669
|
+
}
|
|
1670
|
+
return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { ref: rootRef, className: cn("relative", className), children: [
|
|
1671
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1672
|
+
"div",
|
|
1673
|
+
{
|
|
1674
|
+
className: cn(
|
|
1675
|
+
"border-border bg-background flex items-center rounded-md border",
|
|
1676
|
+
"focus-within:ring-ring/50 focus-within:border-ring focus-within:ring-2",
|
|
1677
|
+
disabled && "opacity-50"
|
|
1678
|
+
),
|
|
1679
|
+
children: [
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1681
|
+
"button",
|
|
1682
|
+
{
|
|
1683
|
+
type: "button",
|
|
1684
|
+
disabled,
|
|
1685
|
+
"aria-haspopup": "dialog",
|
|
1686
|
+
"aria-expanded": open,
|
|
1687
|
+
"aria-label": ariaLabel,
|
|
1688
|
+
onClick: () => open ? setOpen(false) : openPicker(),
|
|
1689
|
+
className: "flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5 text-left text-sm",
|
|
1690
|
+
children: [
|
|
1691
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1692
|
+
import_lucide_react6.CalendarDays,
|
|
1693
|
+
{
|
|
1694
|
+
className: "text-muted-foreground size-4 shrink-0",
|
|
1695
|
+
"aria-hidden": true
|
|
1696
|
+
}
|
|
1697
|
+
),
|
|
1698
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1699
|
+
"span",
|
|
1700
|
+
{
|
|
1701
|
+
className: cn(
|
|
1702
|
+
"truncate",
|
|
1703
|
+
!value.from && !value.to && "text-muted-foreground"
|
|
1704
|
+
),
|
|
1705
|
+
children: label
|
|
1706
|
+
}
|
|
1707
|
+
)
|
|
1708
|
+
]
|
|
1709
|
+
}
|
|
1710
|
+
),
|
|
1711
|
+
(value.from || value.to) && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1712
|
+
"button",
|
|
1713
|
+
{
|
|
1714
|
+
type: "button",
|
|
1715
|
+
"aria-label": "Clear date range",
|
|
1716
|
+
onClick: () => {
|
|
1717
|
+
onChange({ from: "", to: "" });
|
|
1718
|
+
setPendingFrom(null);
|
|
1719
|
+
},
|
|
1720
|
+
className: "text-muted-foreground hover:text-foreground shrink-0 px-2",
|
|
1721
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.X, { className: "size-3.5", "aria-hidden": true })
|
|
1722
|
+
}
|
|
1723
|
+
) : null
|
|
1724
|
+
]
|
|
1725
|
+
}
|
|
1726
|
+
),
|
|
1727
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
|
|
1728
|
+
"div",
|
|
1729
|
+
{
|
|
1730
|
+
role: "dialog",
|
|
1731
|
+
"aria-label": ariaLabel,
|
|
1732
|
+
className: "border-border bg-background absolute top-full right-0 z-50 mt-1 flex w-max rounded-lg border p-3 shadow-lg",
|
|
1733
|
+
children: [
|
|
1734
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.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__ */ (0, import_jsx_runtime14.jsx)(
|
|
1735
|
+
"button",
|
|
1736
|
+
{
|
|
1737
|
+
type: "button",
|
|
1738
|
+
className: "hover:bg-muted text-foreground rounded-md px-2 py-1.5 text-left text-xs",
|
|
1739
|
+
onClick: () => {
|
|
1740
|
+
onChange(preset.range());
|
|
1741
|
+
setPendingFrom(null);
|
|
1742
|
+
setOpen(false);
|
|
1743
|
+
},
|
|
1744
|
+
children: preset.label
|
|
1745
|
+
},
|
|
1746
|
+
preset.label
|
|
1747
|
+
)) }),
|
|
1748
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { onKeyDown: onGridKeyDown, children: [
|
|
1749
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "mb-2 flex items-center justify-between", children: [
|
|
1750
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1751
|
+
"button",
|
|
1752
|
+
{
|
|
1753
|
+
type: "button",
|
|
1754
|
+
"aria-label": "Previous month",
|
|
1755
|
+
className: "hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5",
|
|
1756
|
+
onClick: () => setViewMonth(addMonths(viewMonth, -1)),
|
|
1757
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.ChevronLeft, { className: "size-4", "aria-hidden": true })
|
|
1758
|
+
}
|
|
1759
|
+
),
|
|
1760
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
|
|
1761
|
+
"button",
|
|
1762
|
+
{
|
|
1763
|
+
type: "button",
|
|
1764
|
+
"aria-label": "Next month",
|
|
1765
|
+
className: "hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5",
|
|
1766
|
+
onClick: () => setViewMonth(addMonths(viewMonth, 1)),
|
|
1767
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(import_lucide_react6.ChevronRight, { className: "size-4", "aria-hidden": true })
|
|
1768
|
+
}
|
|
1769
|
+
)
|
|
1770
|
+
] }),
|
|
1771
|
+
/* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("div", { className: "flex gap-5", onMouseLeave: () => setHovered(null), children: [
|
|
1772
|
+
renderMonth(viewMonth),
|
|
1773
|
+
renderMonth(addMonths(viewMonth, 1))
|
|
1774
|
+
] })
|
|
1775
|
+
] })
|
|
1776
|
+
]
|
|
1777
|
+
}
|
|
1778
|
+
) : null
|
|
1779
|
+
] });
|
|
1780
|
+
}
|
|
1781
|
+
|
|
1782
|
+
// src/state-panel.tsx
|
|
1783
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1784
|
+
function StatePanel({
|
|
1785
|
+
loading,
|
|
1786
|
+
className,
|
|
1787
|
+
children,
|
|
1788
|
+
...props
|
|
1789
|
+
}) {
|
|
1790
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
|
|
1791
|
+
"div",
|
|
1792
|
+
{
|
|
1793
|
+
role: loading ? "status" : void 0,
|
|
1794
|
+
"aria-live": loading ? "polite" : void 0,
|
|
1795
|
+
className: cn(
|
|
1796
|
+
"border-border bg-background/80 text-muted-foreground rounded-lg border px-4 py-6 text-center text-sm",
|
|
1797
|
+
loading && "flex items-center justify-center gap-2",
|
|
1798
|
+
className
|
|
1799
|
+
),
|
|
1800
|
+
...props,
|
|
1801
|
+
children: [
|
|
1802
|
+
loading ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Spinner, { size: "md" }) : null,
|
|
1803
|
+
children
|
|
1804
|
+
]
|
|
1805
|
+
}
|
|
1806
|
+
);
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
// src/feature-access-gate.tsx
|
|
1810
|
+
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
1811
|
+
function FeatureAccessGate({
|
|
1812
|
+
isLoading,
|
|
1813
|
+
allowed,
|
|
1814
|
+
deniedMessage,
|
|
1815
|
+
children
|
|
1816
|
+
}) {
|
|
1817
|
+
if (isLoading) {
|
|
1818
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StatePanel, { loading: true, className: "p-6", children: "Checking permissions\u2026" });
|
|
1819
|
+
}
|
|
1820
|
+
if (!allowed) {
|
|
1821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Alert, { children: deniedMessage });
|
|
1822
|
+
}
|
|
1823
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
// src/field.tsx
|
|
1827
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
1828
|
+
function Field({
|
|
1829
|
+
label,
|
|
1830
|
+
required,
|
|
1831
|
+
htmlFor,
|
|
1832
|
+
as = "div",
|
|
1833
|
+
className,
|
|
1834
|
+
children
|
|
1835
|
+
}) {
|
|
1836
|
+
const Wrapper = as;
|
|
1837
|
+
const labelNode = /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
1838
|
+
label,
|
|
1839
|
+
required ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-destructive ml-0.5", "aria-hidden": "true", children: "*" }) : null
|
|
1840
|
+
] });
|
|
1841
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Wrapper, { className: cn("space-y-1 text-sm", className), children: [
|
|
1842
|
+
htmlFor && as === "div" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { htmlFor, className: "text-muted-foreground", children: labelNode }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "text-muted-foreground", children: labelNode }),
|
|
1843
|
+
children
|
|
1844
|
+
] });
|
|
1845
|
+
}
|
|
1846
|
+
|
|
1847
|
+
// src/image-uploader.tsx
|
|
1848
|
+
var import_lucide_react7 = require("lucide-react");
|
|
1849
|
+
var React14 = __toESM(require("react"), 1);
|
|
1850
|
+
|
|
1851
|
+
// src/input.tsx
|
|
1852
|
+
var React13 = __toESM(require("react"), 1);
|
|
1853
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
1854
|
+
var inputClass = "h-9 w-full rounded-md border border-border bg-background px-3 text-sm focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50";
|
|
1855
|
+
var Input = React13.forwardRef(
|
|
1856
|
+
({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { ref, className: cn(inputClass, className), ...props })
|
|
1857
|
+
);
|
|
1858
|
+
Input.displayName = "Input";
|
|
1859
|
+
|
|
1860
|
+
// src/image-uploader.tsx
|
|
1861
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
1862
|
+
function ImageUploader({
|
|
1863
|
+
value = "",
|
|
1864
|
+
onChange,
|
|
1865
|
+
disabled,
|
|
1866
|
+
label,
|
|
1867
|
+
className,
|
|
1868
|
+
allowUrlPaste = true,
|
|
1869
|
+
accept = "image/*,.gif",
|
|
1870
|
+
uploadFile,
|
|
1871
|
+
uploadFromUrl
|
|
1872
|
+
}) {
|
|
1873
|
+
const inputRef = React14.useRef(null);
|
|
1874
|
+
const [uploading, setUploading] = React14.useState(false);
|
|
1875
|
+
const [error, setError] = React14.useState(null);
|
|
1876
|
+
const busy = Boolean(disabled || uploading);
|
|
1877
|
+
const handleFile = async (file) => {
|
|
1878
|
+
if (!uploadFile) {
|
|
1879
|
+
setError("File upload is not configured for this panel.");
|
|
1880
|
+
return;
|
|
1881
|
+
}
|
|
1882
|
+
setUploading(true);
|
|
1883
|
+
setError(null);
|
|
1884
|
+
try {
|
|
1885
|
+
onChange(await uploadFile(file));
|
|
1886
|
+
} catch (err) {
|
|
1887
|
+
setError(err instanceof Error ? err.message : "Upload failed");
|
|
1888
|
+
} finally {
|
|
1889
|
+
setUploading(false);
|
|
1890
|
+
if (inputRef.current) inputRef.current.value = "";
|
|
1891
|
+
}
|
|
1892
|
+
};
|
|
1893
|
+
const handleUrl = async (imageUrl) => {
|
|
1894
|
+
const trimmed = imageUrl.trim();
|
|
1895
|
+
if (!trimmed) {
|
|
1896
|
+
onChange("");
|
|
1897
|
+
return;
|
|
1898
|
+
}
|
|
1899
|
+
if (trimmed === value) return;
|
|
1900
|
+
if (!uploadFromUrl || /^https?:\/\//i.test(trimmed)) {
|
|
1901
|
+
setError(null);
|
|
1902
|
+
onChange(trimmed);
|
|
1903
|
+
return;
|
|
1904
|
+
}
|
|
1905
|
+
setUploading(true);
|
|
1906
|
+
setError(null);
|
|
1907
|
+
try {
|
|
1908
|
+
onChange(await uploadFromUrl(trimmed));
|
|
1909
|
+
} catch (err) {
|
|
1910
|
+
setError(err instanceof Error ? err.message : "Upload failed");
|
|
1911
|
+
} finally {
|
|
1912
|
+
setUploading(false);
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: cn("space-y-2", className), children: [
|
|
1916
|
+
label ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { className: "text-muted-foreground text-xs font-medium", children: label }) : null,
|
|
1917
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "flex flex-wrap items-center gap-2", children: [
|
|
1918
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1919
|
+
"input",
|
|
1920
|
+
{
|
|
1921
|
+
ref: inputRef,
|
|
1922
|
+
type: "file",
|
|
1923
|
+
accept,
|
|
1924
|
+
className: "hidden",
|
|
1925
|
+
disabled: busy,
|
|
1926
|
+
onChange: (e) => {
|
|
1927
|
+
const file = e.target.files?.[0];
|
|
1928
|
+
if (file) void handleFile(file);
|
|
1929
|
+
}
|
|
1930
|
+
}
|
|
1931
|
+
),
|
|
1932
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1933
|
+
Button,
|
|
1934
|
+
{
|
|
1935
|
+
type: "button",
|
|
1936
|
+
variant: "outline",
|
|
1937
|
+
size: "sm",
|
|
1938
|
+
disabled: busy,
|
|
1939
|
+
onClick: () => inputRef.current?.click(),
|
|
1940
|
+
children: [
|
|
1941
|
+
uploading ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react7.Loader2, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react7.ImagePlus, { className: "h-4 w-4" }),
|
|
1942
|
+
uploading ? "Uploading\u2026" : "Upload"
|
|
1943
|
+
]
|
|
1944
|
+
}
|
|
1945
|
+
),
|
|
1946
|
+
value ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
1947
|
+
Button,
|
|
1948
|
+
{
|
|
1949
|
+
type: "button",
|
|
1950
|
+
variant: "ghost",
|
|
1951
|
+
size: "sm",
|
|
1952
|
+
disabled: busy,
|
|
1953
|
+
onClick: () => onChange(""),
|
|
1954
|
+
"aria-label": "Clear image",
|
|
1955
|
+
children: [
|
|
1956
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(import_lucide_react7.X, { className: "h-4 w-4" }),
|
|
1957
|
+
"Clear"
|
|
1958
|
+
]
|
|
1959
|
+
}
|
|
1960
|
+
) : null
|
|
1961
|
+
] }),
|
|
1962
|
+
allowUrlPaste ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1963
|
+
Input,
|
|
1964
|
+
{
|
|
1965
|
+
defaultValue: value,
|
|
1966
|
+
disabled: busy,
|
|
1967
|
+
placeholder: "Or paste image URL\u2026",
|
|
1968
|
+
onBlur: (e) => {
|
|
1969
|
+
void handleUrl(e.target.value);
|
|
1970
|
+
},
|
|
1971
|
+
onKeyDown: (e) => {
|
|
1972
|
+
if (e.key === "Enter") {
|
|
1973
|
+
e.preventDefault();
|
|
1974
|
+
void handleUrl(e.target.value);
|
|
1975
|
+
}
|
|
1976
|
+
}
|
|
1977
|
+
},
|
|
1978
|
+
value || "empty"
|
|
1979
|
+
) : null,
|
|
1980
|
+
value ? (
|
|
1981
|
+
// eslint-disable-next-line @next/next/no-img-element -- CDN URLs vary
|
|
1982
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1983
|
+
"img",
|
|
1984
|
+
{
|
|
1985
|
+
src: value,
|
|
1986
|
+
alt: "",
|
|
1987
|
+
className: "border-border max-h-24 rounded border bg-white object-contain p-1"
|
|
1988
|
+
}
|
|
1989
|
+
)
|
|
1990
|
+
) : null,
|
|
1991
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { className: "text-destructive text-xs", role: "alert", children: error }) : null
|
|
1992
|
+
] });
|
|
1993
|
+
}
|
|
1994
|
+
|
|
1995
|
+
// src/label.tsx
|
|
1996
|
+
var React15 = __toESM(require("react"), 1);
|
|
1997
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
1998
|
+
var Label = React15.forwardRef(
|
|
1999
|
+
({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
2000
|
+
"label",
|
|
2001
|
+
{
|
|
2002
|
+
ref,
|
|
2003
|
+
className: cn(
|
|
2004
|
+
"text-sm leading-none font-medium peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
|
|
2005
|
+
className
|
|
2006
|
+
),
|
|
2007
|
+
...props
|
|
2008
|
+
}
|
|
2009
|
+
)
|
|
2010
|
+
);
|
|
2011
|
+
Label.displayName = "Label";
|
|
2012
|
+
|
|
2013
|
+
// src/page-header.tsx
|
|
2014
|
+
var import_jsx_runtime21 = require("react/jsx-runtime");
|
|
2015
|
+
function PageHeader({
|
|
2016
|
+
title,
|
|
2017
|
+
description,
|
|
2018
|
+
eyebrow,
|
|
2019
|
+
actions,
|
|
2020
|
+
className
|
|
2021
|
+
}) {
|
|
2022
|
+
const heading = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)("div", { className: "min-w-0", children: [
|
|
2023
|
+
eyebrow,
|
|
2024
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2025
|
+
"h1",
|
|
2026
|
+
{
|
|
2027
|
+
className: cn(
|
|
2028
|
+
"text-2xl font-semibold tracking-tight",
|
|
2029
|
+
eyebrow != null && "mt-1"
|
|
2030
|
+
),
|
|
2031
|
+
children: title
|
|
2032
|
+
}
|
|
2033
|
+
),
|
|
2034
|
+
description != null ? /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("p", { className: "text-muted-foreground mt-1 text-sm", children: description }) : null
|
|
2035
|
+
] });
|
|
2036
|
+
if (!actions) {
|
|
2037
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)("div", { className, children: heading });
|
|
2038
|
+
}
|
|
2039
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(
|
|
2040
|
+
"div",
|
|
2041
|
+
{
|
|
2042
|
+
className: cn(
|
|
2043
|
+
"flex flex-wrap items-center justify-between gap-3",
|
|
2044
|
+
className
|
|
2045
|
+
),
|
|
2046
|
+
children: [
|
|
2047
|
+
heading,
|
|
2048
|
+
actions
|
|
2049
|
+
]
|
|
2050
|
+
}
|
|
2051
|
+
);
|
|
2052
|
+
}
|
|
2053
|
+
|
|
2054
|
+
// src/panel-brand-mark.tsx
|
|
2055
|
+
var import_jsx_runtime22 = require("react/jsx-runtime");
|
|
2056
|
+
function PanelBrandMark({
|
|
2057
|
+
children,
|
|
2058
|
+
size = "md",
|
|
2059
|
+
className,
|
|
2060
|
+
...props
|
|
2061
|
+
}) {
|
|
2062
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2063
|
+
"div",
|
|
2064
|
+
{
|
|
2065
|
+
className: cn(
|
|
2066
|
+
"bg-primary text-primary-foreground grid shrink-0 place-items-center rounded-lg",
|
|
2067
|
+
size === "sm" ? "h-9 w-9" : "h-10 w-10",
|
|
2068
|
+
className
|
|
2069
|
+
),
|
|
2070
|
+
...props,
|
|
2071
|
+
children
|
|
2072
|
+
}
|
|
2073
|
+
);
|
|
2074
|
+
}
|
|
2075
|
+
|
|
2076
|
+
// src/panel-sign-in.tsx
|
|
2077
|
+
var import_lucide_react8 = require("lucide-react");
|
|
2078
|
+
var import_jsx_runtime23 = require("react/jsx-runtime");
|
|
2079
|
+
function PanelSignIn({
|
|
2080
|
+
appName,
|
|
2081
|
+
eyebrow = "Secure Google sign-in",
|
|
2082
|
+
description = "Use your work Google account to continue.",
|
|
2083
|
+
features,
|
|
2084
|
+
brandIcon,
|
|
2085
|
+
error,
|
|
2086
|
+
refused = false,
|
|
2087
|
+
refusedTitle = "Access denied",
|
|
2088
|
+
refusedMessage = "This Google account is signed in, but it is not provisioned for this panel.",
|
|
2089
|
+
isSessionLoading = false,
|
|
2090
|
+
isSigningIn = false,
|
|
2091
|
+
onSignIn,
|
|
2092
|
+
signInLabel = "Continue with Google",
|
|
2093
|
+
className
|
|
2094
|
+
}) {
|
|
2095
|
+
const busy = isSessionLoading || isSigningIn;
|
|
2096
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2097
|
+
"main",
|
|
2098
|
+
{
|
|
2099
|
+
className: cn(
|
|
2100
|
+
"bg-background text-foreground grid min-h-screen place-items-center p-4 sm:p-8",
|
|
2101
|
+
className
|
|
2102
|
+
),
|
|
2103
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("section", { className: "border-border bg-card w-full max-w-md space-y-6 rounded-lg border p-8 shadow-sm", children: [
|
|
2104
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "flex items-center gap-3", children: [
|
|
2105
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(PanelBrandMark, { children: brandIcon ?? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-sm font-semibold", "aria-hidden": true, children: appName.slice(0, 1).toUpperCase() }) }),
|
|
2106
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "min-w-0", children: [
|
|
2107
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-title truncate font-semibold", children: appName }),
|
|
2108
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-muted-foreground text-meta", children: eyebrow })
|
|
2109
|
+
] })
|
|
2110
|
+
] }),
|
|
2111
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "space-y-2", children: [
|
|
2112
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("h1", { className: "text-display font-semibold tracking-tight", children: refused ? refusedTitle : "Sign in" }),
|
|
2113
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("p", { className: "text-muted-foreground text-body", children: refused ? refusedMessage : description })
|
|
2114
|
+
] }),
|
|
2115
|
+
features && features.length > 0 && !refused ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("ul", { className: "text-muted-foreground text-body space-y-1.5", children: features.slice(0, 3).map((feature) => /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("li", { className: "flex gap-2", children: [
|
|
2116
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "text-foreground mt-1.5 h-1 w-1 shrink-0 rounded-full bg-current" }),
|
|
2117
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { children: feature })
|
|
2118
|
+
] }, feature)) }) : null,
|
|
2119
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2120
|
+
"p",
|
|
2121
|
+
{
|
|
2122
|
+
role: "alert",
|
|
2123
|
+
className: "border-destructive/30 bg-destructive/5 text-destructive rounded-md border px-3 py-2 text-sm",
|
|
2124
|
+
children: error
|
|
2125
|
+
}
|
|
2126
|
+
) : null,
|
|
2127
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2128
|
+
Button,
|
|
2129
|
+
{
|
|
2130
|
+
className: "w-full",
|
|
2131
|
+
disabled: busy,
|
|
2132
|
+
onClick: onSignIn,
|
|
2133
|
+
"aria-busy": busy,
|
|
2134
|
+
children: [
|
|
2135
|
+
busy ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(import_lucide_react8.Loader2, { className: "mr-2 h-4 w-4 animate-spin", "aria-hidden": true }) : null,
|
|
2136
|
+
isSigningIn ? "Redirecting\u2026" : signInLabel
|
|
2137
|
+
]
|
|
2138
|
+
}
|
|
2139
|
+
)
|
|
2140
|
+
] })
|
|
2141
|
+
}
|
|
2142
|
+
);
|
|
2143
|
+
}
|
|
2144
|
+
function PanelSignInSkeleton({ className }) {
|
|
2145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2146
|
+
"main",
|
|
2147
|
+
{
|
|
2148
|
+
className: cn(
|
|
2149
|
+
"bg-background grid min-h-screen place-items-center p-4 sm:p-8",
|
|
2150
|
+
className
|
|
2151
|
+
),
|
|
2152
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)("div", { className: "border-border bg-card w-full max-w-md space-y-4 rounded-lg border p-8 shadow-sm", children: [
|
|
2153
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "bg-muted h-3 w-24 animate-pulse rounded" }),
|
|
2154
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "bg-muted h-8 w-48 animate-pulse rounded" }),
|
|
2155
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)("div", { className: "bg-muted mt-7 h-10 w-full animate-pulse rounded-md" })
|
|
2156
|
+
] })
|
|
2157
|
+
}
|
|
2158
|
+
);
|
|
2159
|
+
}
|
|
2160
|
+
|
|
2161
|
+
// src/pagination.tsx
|
|
2162
|
+
var import_lucide_react9 = require("lucide-react");
|
|
2163
|
+
var React16 = __toESM(require("react"), 1);
|
|
2164
|
+
var import_jsx_runtime24 = require("react/jsx-runtime");
|
|
2165
|
+
function Pagination({
|
|
2166
|
+
currentPage,
|
|
2167
|
+
totalPages,
|
|
2168
|
+
onPageChange,
|
|
2169
|
+
loading = false,
|
|
2170
|
+
showPageInfo = true
|
|
2171
|
+
}) {
|
|
2172
|
+
const visiblePages = React16.useMemo(() => {
|
|
2173
|
+
const delta = 2;
|
|
2174
|
+
const range = [];
|
|
2175
|
+
const rangeWithDots = [];
|
|
2176
|
+
for (let i = Math.max(2, currentPage - delta); i <= Math.min(totalPages - 1, currentPage + delta); i++) {
|
|
2177
|
+
range.push(i);
|
|
2178
|
+
}
|
|
2179
|
+
if (currentPage - delta > 2) {
|
|
2180
|
+
rangeWithDots.push(1, "...");
|
|
2181
|
+
} else {
|
|
2182
|
+
rangeWithDots.push(1);
|
|
2183
|
+
}
|
|
2184
|
+
rangeWithDots.push(...range);
|
|
2185
|
+
if (currentPage + delta < totalPages - 1) {
|
|
2186
|
+
rangeWithDots.push("...", totalPages);
|
|
2187
|
+
} else if (totalPages > 1) {
|
|
2188
|
+
rangeWithDots.push(totalPages);
|
|
2189
|
+
}
|
|
2190
|
+
return rangeWithDots;
|
|
2191
|
+
}, [currentPage, totalPages]);
|
|
2192
|
+
if (totalPages <= 1) return null;
|
|
2193
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "flex flex-col items-center justify-between gap-4 sm:flex-row", children: [
|
|
2194
|
+
showPageInfo ? /* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "text-muted-foreground order-2 text-sm sm:order-1", children: [
|
|
2195
|
+
"Page ",
|
|
2196
|
+
currentPage,
|
|
2197
|
+
" of ",
|
|
2198
|
+
totalPages
|
|
2199
|
+
] }) : null,
|
|
2200
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsxs)("div", { className: "order-1 flex items-center space-x-1 sm:order-2 sm:space-x-2", children: [
|
|
2201
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2202
|
+
Button,
|
|
2203
|
+
{
|
|
2204
|
+
variant: "outline",
|
|
2205
|
+
size: "sm",
|
|
2206
|
+
onClick: () => onPageChange(currentPage - 1),
|
|
2207
|
+
disabled: currentPage <= 1 || loading,
|
|
2208
|
+
className: "h-8 min-w-8 px-2",
|
|
2209
|
+
"aria-label": "Previous page",
|
|
2210
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react9.ChevronLeft, { className: "h-4 w-4" })
|
|
2211
|
+
}
|
|
2212
|
+
),
|
|
2213
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)("div", { className: "flex max-w-[200px] items-center space-x-1 overflow-x-auto sm:max-w-none", children: visiblePages.map(
|
|
2214
|
+
(page, index) => page === "..." ? /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2215
|
+
"div",
|
|
2216
|
+
{
|
|
2217
|
+
className: "flex h-8 w-8 shrink-0 items-center justify-center",
|
|
2218
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react9.MoreHorizontal, { className: "h-4 w-4" })
|
|
2219
|
+
},
|
|
2220
|
+
`dots-${index}`
|
|
2221
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2222
|
+
Button,
|
|
2223
|
+
{
|
|
2224
|
+
variant: page === currentPage ? "default" : "outline",
|
|
2225
|
+
size: "sm",
|
|
2226
|
+
onClick: () => onPageChange(page),
|
|
2227
|
+
disabled: loading,
|
|
2228
|
+
className: "h-8 min-w-8 shrink-0 px-2",
|
|
2229
|
+
"aria-current": page === currentPage ? "page" : void 0,
|
|
2230
|
+
children: page
|
|
2231
|
+
},
|
|
2232
|
+
page
|
|
2233
|
+
)
|
|
2234
|
+
) }),
|
|
2235
|
+
/* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2236
|
+
Button,
|
|
2237
|
+
{
|
|
2238
|
+
variant: "outline",
|
|
2239
|
+
size: "sm",
|
|
2240
|
+
onClick: () => onPageChange(currentPage + 1),
|
|
2241
|
+
disabled: currentPage >= totalPages || loading,
|
|
2242
|
+
className: "h-8 min-w-8 px-2",
|
|
2243
|
+
"aria-label": "Next page",
|
|
2244
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(import_lucide_react9.ChevronRight, { className: "h-4 w-4" })
|
|
2245
|
+
}
|
|
2246
|
+
)
|
|
2247
|
+
] })
|
|
2248
|
+
] });
|
|
2249
|
+
}
|
|
2250
|
+
|
|
2251
|
+
// src/segmented-control.tsx
|
|
2252
|
+
var React17 = __toESM(require("react"), 1);
|
|
2253
|
+
var import_jsx_runtime25 = require("react/jsx-runtime");
|
|
2254
|
+
var TONES = {
|
|
2255
|
+
emphasis: {
|
|
2256
|
+
on: "bg-slate-950 text-white dark:bg-white dark:text-slate-950",
|
|
2257
|
+
off: "text-muted-foreground hover:bg-muted"
|
|
2258
|
+
},
|
|
2259
|
+
primary: {
|
|
2260
|
+
on: "bg-primary text-primary-foreground",
|
|
2261
|
+
off: "text-muted-foreground hover:bg-muted"
|
|
2262
|
+
}
|
|
2263
|
+
};
|
|
2264
|
+
var TRACKS = {
|
|
2265
|
+
contained: "border-border inline-flex rounded-md border p-0.5",
|
|
2266
|
+
loose: "flex flex-wrap gap-2"
|
|
2267
|
+
};
|
|
2268
|
+
function SegmentedControl({
|
|
2269
|
+
options,
|
|
2270
|
+
value,
|
|
2271
|
+
onChange,
|
|
2272
|
+
ariaLabel,
|
|
2273
|
+
variant = "contained",
|
|
2274
|
+
tone = "emphasis",
|
|
2275
|
+
fill = false,
|
|
2276
|
+
className
|
|
2277
|
+
}) {
|
|
2278
|
+
const refs = React17.useRef(/* @__PURE__ */ new Map());
|
|
2279
|
+
function onKeyDown(event) {
|
|
2280
|
+
const step = event.key === "ArrowRight" || event.key === "ArrowDown" ? 1 : event.key === "ArrowLeft" || event.key === "ArrowUp" ? -1 : 0;
|
|
2281
|
+
if (step === 0) return;
|
|
2282
|
+
const selectable = options.filter((option) => !option.disabled);
|
|
2283
|
+
if (selectable.length < 2) return;
|
|
2284
|
+
const current = selectable.findIndex((option) => option.value === value);
|
|
2285
|
+
const next = selectable[(current + step + selectable.length) % selectable.length];
|
|
2286
|
+
event.preventDefault();
|
|
2287
|
+
onChange(next.value);
|
|
2288
|
+
refs.current.get(next.value)?.focus();
|
|
2289
|
+
}
|
|
2290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2291
|
+
"div",
|
|
2292
|
+
{
|
|
2293
|
+
role: "radiogroup",
|
|
2294
|
+
"aria-label": ariaLabel,
|
|
2295
|
+
onKeyDown,
|
|
2296
|
+
className: cn(TRACKS[variant], className),
|
|
2297
|
+
children: options.map((option) => {
|
|
2298
|
+
const checked = option.value === value;
|
|
2299
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2300
|
+
"button",
|
|
2301
|
+
{
|
|
2302
|
+
ref: (node) => {
|
|
2303
|
+
refs.current.set(option.value, node);
|
|
2304
|
+
},
|
|
2305
|
+
type: "button",
|
|
2306
|
+
role: "radio",
|
|
2307
|
+
"aria-checked": checked,
|
|
2308
|
+
disabled: option.disabled,
|
|
2309
|
+
title: option.title,
|
|
2310
|
+
tabIndex: checked ? 0 : -1,
|
|
2311
|
+
onClick: () => onChange(option.value),
|
|
2312
|
+
className: cn(
|
|
2313
|
+
"cursor-pointer rounded px-3 py-1 text-sm font-medium transition",
|
|
2314
|
+
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
|
|
2315
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
2316
|
+
fill && "flex-1",
|
|
2317
|
+
checked ? TONES[tone].on : TONES[tone].off
|
|
2318
|
+
),
|
|
2319
|
+
children: option.label
|
|
2320
|
+
},
|
|
2321
|
+
option.value
|
|
2322
|
+
);
|
|
2323
|
+
})
|
|
2324
|
+
}
|
|
2325
|
+
);
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
// src/select.tsx
|
|
2329
|
+
var React18 = __toESM(require("react"), 1);
|
|
2330
|
+
var import_jsx_runtime26 = require("react/jsx-runtime");
|
|
2331
|
+
function optionText(node) {
|
|
2332
|
+
if (node == null || typeof node === "boolean") return "";
|
|
2333
|
+
if (typeof node === "string" || typeof node === "number") return String(node);
|
|
2334
|
+
if (Array.isArray(node)) return node.map(optionText).join("");
|
|
2335
|
+
if (React18.isValidElement(node)) {
|
|
2336
|
+
return optionText(node.props.children);
|
|
2337
|
+
}
|
|
2338
|
+
return "";
|
|
2339
|
+
}
|
|
2340
|
+
function optionsFromChildren(children) {
|
|
2341
|
+
const options = [];
|
|
2342
|
+
React18.Children.forEach(children, (child) => {
|
|
2343
|
+
if (!React18.isValidElement(child)) return;
|
|
2344
|
+
if (child.type === React18.Fragment) {
|
|
2345
|
+
options.push(
|
|
2346
|
+
...optionsFromChildren(
|
|
2347
|
+
child.props.children
|
|
2348
|
+
)
|
|
2349
|
+
);
|
|
2350
|
+
return;
|
|
2351
|
+
}
|
|
2352
|
+
const props = child.props;
|
|
2353
|
+
const value = props.value == null ? "" : String(props.value);
|
|
2354
|
+
options.push({
|
|
2355
|
+
value,
|
|
2356
|
+
label: optionText(props.children).trim() || value,
|
|
2357
|
+
disabled: Boolean(props.disabled)
|
|
2358
|
+
});
|
|
2359
|
+
});
|
|
2360
|
+
return options;
|
|
2361
|
+
}
|
|
2362
|
+
function Select({
|
|
2363
|
+
id,
|
|
2364
|
+
className,
|
|
2365
|
+
disabled,
|
|
2366
|
+
value,
|
|
2367
|
+
placeholder,
|
|
2368
|
+
children,
|
|
2369
|
+
onChange,
|
|
2370
|
+
size = "default",
|
|
2371
|
+
"aria-label": ariaLabel
|
|
2372
|
+
}) {
|
|
2373
|
+
const options = optionsFromChildren(children);
|
|
2374
|
+
const current = Array.isArray(value) ? String(value[0] ?? "") : value == null ? "" : String(value);
|
|
2375
|
+
const blank = options.find((option) => option.value === "");
|
|
2376
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2377
|
+
Autocomplete,
|
|
2378
|
+
{
|
|
2379
|
+
id,
|
|
2380
|
+
className,
|
|
2381
|
+
disabled: Boolean(disabled),
|
|
2382
|
+
ariaLabel,
|
|
2383
|
+
size,
|
|
2384
|
+
options,
|
|
2385
|
+
value: current,
|
|
2386
|
+
clearable: false,
|
|
2387
|
+
placeholder: placeholder ?? blank?.label ?? "Search\u2026",
|
|
2388
|
+
onChange: (next) => onChange?.({
|
|
2389
|
+
target: { value: next },
|
|
2390
|
+
currentTarget: { value: next }
|
|
2391
|
+
})
|
|
2392
|
+
}
|
|
2393
|
+
);
|
|
2394
|
+
}
|
|
2395
|
+
|
|
2396
|
+
// src/separator.tsx
|
|
2397
|
+
var React19 = __toESM(require("react"), 1);
|
|
2398
|
+
var import_jsx_runtime27 = require("react/jsx-runtime");
|
|
2399
|
+
var Separator = React19.forwardRef(
|
|
2400
|
+
({ className, orientation = "horizontal", decorative = true, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2401
|
+
"div",
|
|
2402
|
+
{
|
|
2403
|
+
ref,
|
|
2404
|
+
role: decorative ? "none" : "separator",
|
|
2405
|
+
"aria-orientation": orientation,
|
|
2406
|
+
className: cn(
|
|
2407
|
+
"bg-border shrink-0",
|
|
2408
|
+
orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
|
|
2409
|
+
className
|
|
2410
|
+
),
|
|
2411
|
+
...props
|
|
2412
|
+
}
|
|
2413
|
+
)
|
|
2414
|
+
);
|
|
2415
|
+
Separator.displayName = "Separator";
|
|
2416
|
+
|
|
2417
|
+
// src/side-drawer.tsx
|
|
2418
|
+
var import_lucide_react10 = require("lucide-react");
|
|
2419
|
+
var React20 = __toESM(require("react"), 1);
|
|
2420
|
+
var import_react_dom3 = require("react-dom");
|
|
2421
|
+
var import_jsx_runtime28 = require("react/jsx-runtime");
|
|
2422
|
+
function SideDrawer({
|
|
2423
|
+
isOpen,
|
|
2424
|
+
title,
|
|
2425
|
+
onClose,
|
|
2426
|
+
children,
|
|
2427
|
+
panelClassName
|
|
2428
|
+
}) {
|
|
2429
|
+
const mounted = useHasMounted();
|
|
2430
|
+
const headingId = React20.useId();
|
|
2431
|
+
const panelRef = React20.useRef(null);
|
|
2432
|
+
useDialogLayer({
|
|
2433
|
+
// Gated on `mounted` too: before that the panel is not rendered, so there
|
|
2434
|
+
// would be nothing to move focus into.
|
|
2435
|
+
active: isOpen && mounted,
|
|
2436
|
+
containerRef: panelRef,
|
|
2437
|
+
onEscape: onClose
|
|
2438
|
+
});
|
|
2439
|
+
if (!mounted || !isOpen) return null;
|
|
2440
|
+
return (0, import_react_dom3.createPortal)(
|
|
2441
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(import_jsx_runtime28.Fragment, { children: [
|
|
2442
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2443
|
+
"div",
|
|
2444
|
+
{
|
|
2445
|
+
"aria-hidden": true,
|
|
2446
|
+
onClick: onClose,
|
|
2447
|
+
className: "fixed inset-0 z-[90] bg-slate-950/30"
|
|
2448
|
+
}
|
|
2449
|
+
),
|
|
2450
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2451
|
+
"aside",
|
|
2452
|
+
{
|
|
2453
|
+
ref: panelRef,
|
|
2454
|
+
role: "dialog",
|
|
2455
|
+
"aria-modal": "true",
|
|
2456
|
+
"aria-labelledby": headingId,
|
|
2457
|
+
tabIndex: -1,
|
|
2458
|
+
className: cn(
|
|
2459
|
+
"border-border bg-background fixed inset-y-0 right-0 z-[95] flex flex-col border-l shadow-2xl outline-none",
|
|
2460
|
+
panelClassName ?? "w-full max-w-md"
|
|
2461
|
+
),
|
|
2462
|
+
children: [
|
|
2463
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)("div", { className: "border-border flex items-center justify-between gap-3 border-b px-4 py-3", children: [
|
|
2464
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("h2", { id: headingId, className: "truncate text-base font-semibold", children: title }),
|
|
2465
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2466
|
+
Button,
|
|
2467
|
+
{
|
|
2468
|
+
variant: "ghost",
|
|
2469
|
+
size: "icon",
|
|
2470
|
+
"aria-label": "Close panel",
|
|
2471
|
+
onClick: onClose,
|
|
2472
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_lucide_react10.X, { className: "h-4 w-4", "aria-hidden": true })
|
|
2473
|
+
}
|
|
2474
|
+
)
|
|
2475
|
+
] }),
|
|
2476
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)("div", { className: "min-h-0 flex-1 overflow-y-auto p-4", children })
|
|
2477
|
+
]
|
|
2478
|
+
}
|
|
2479
|
+
)
|
|
2480
|
+
] }),
|
|
2481
|
+
document.body
|
|
2482
|
+
);
|
|
2483
|
+
}
|
|
2484
|
+
|
|
2485
|
+
// src/spreadsheet-grid.tsx
|
|
2486
|
+
var React21 = __toESM(require("react"), 1);
|
|
2487
|
+
var import_jsx_runtime29 = require("react/jsx-runtime");
|
|
2488
|
+
function isInRange(range, r, c) {
|
|
2489
|
+
if (!range) return false;
|
|
2490
|
+
return r >= range.r1 && r <= range.r2 && c >= range.c1 && c <= range.c2;
|
|
2491
|
+
}
|
|
2492
|
+
function SpreadsheetGrid({
|
|
2493
|
+
columns,
|
|
2494
|
+
rows,
|
|
2495
|
+
rowKey,
|
|
2496
|
+
loading,
|
|
2497
|
+
emptyMessage = "Nothing to show.",
|
|
2498
|
+
loadingMessage = "Loading\u2026",
|
|
2499
|
+
ariaLabel = "Data grid",
|
|
2500
|
+
range,
|
|
2501
|
+
onRangeChange,
|
|
2502
|
+
onCopy
|
|
2503
|
+
}) {
|
|
2504
|
+
const gridRef = React21.useRef(null);
|
|
2505
|
+
const anchorRef = React21.useRef(null);
|
|
2506
|
+
const focusRef = React21.useRef(null);
|
|
2507
|
+
const [dragging, setDragging] = React21.useState(false);
|
|
2508
|
+
const setSelection = React21.useCallback(
|
|
2509
|
+
(anchor, focus) => {
|
|
2510
|
+
anchorRef.current = anchor;
|
|
2511
|
+
focusRef.current = focus;
|
|
2512
|
+
onRangeChange({ anchor, focus });
|
|
2513
|
+
},
|
|
2514
|
+
[onRangeChange]
|
|
2515
|
+
);
|
|
2516
|
+
const selectCell = React21.useCallback(
|
|
2517
|
+
(r, c, extend) => {
|
|
2518
|
+
if (extend && anchorRef.current)
|
|
2519
|
+
setSelection(anchorRef.current, { r, c });
|
|
2520
|
+
else setSelection({ r, c }, { r, c });
|
|
2521
|
+
},
|
|
2522
|
+
[setSelection]
|
|
2523
|
+
);
|
|
2524
|
+
const selectColumn = React21.useCallback(
|
|
2525
|
+
(c, extend) => {
|
|
2526
|
+
const lastRow = Math.max(rows.length - 1, 0);
|
|
2527
|
+
const anchorCol = extend && anchorRef.current ? anchorRef.current.c : c;
|
|
2528
|
+
setSelection({ r: 0, c: anchorCol }, { r: lastRow, c });
|
|
2529
|
+
},
|
|
2530
|
+
[rows.length, setSelection]
|
|
2531
|
+
);
|
|
2532
|
+
const selectRow = React21.useCallback(
|
|
2533
|
+
(r, extend) => {
|
|
2534
|
+
const lastCol = columns.length - 1;
|
|
2535
|
+
const anchorRow = extend && anchorRef.current ? anchorRef.current.r : r;
|
|
2536
|
+
setSelection({ r: anchorRow, c: 0 }, { r, c: lastCol });
|
|
2537
|
+
},
|
|
2538
|
+
[columns.length, setSelection]
|
|
2539
|
+
);
|
|
2540
|
+
const selectAll = React21.useCallback(() => {
|
|
2541
|
+
if (!rows.length || !columns.length) return;
|
|
2542
|
+
setSelection({ r: 0, c: 0 }, { r: rows.length - 1, c: columns.length - 1 });
|
|
2543
|
+
}, [rows.length, columns.length, setSelection]);
|
|
2544
|
+
const scrollCellIntoView = React21.useCallback((r, c) => {
|
|
2545
|
+
const cell = gridRef.current?.querySelector(`[data-cell="${r}-${c}"]`);
|
|
2546
|
+
cell?.scrollIntoView({ block: "nearest", inline: "nearest" });
|
|
2547
|
+
}, []);
|
|
2548
|
+
const moveFocus = React21.useCallback(
|
|
2549
|
+
(dr, dc, extend) => {
|
|
2550
|
+
if (!rows.length || !columns.length) return;
|
|
2551
|
+
const base = focusRef.current || { r: 0, c: 0 };
|
|
2552
|
+
const r = Math.min(Math.max(base.r + dr, 0), rows.length - 1);
|
|
2553
|
+
const c = Math.min(Math.max(base.c + dc, 0), columns.length - 1);
|
|
2554
|
+
selectCell(r, c, extend);
|
|
2555
|
+
scrollCellIntoView(r, c);
|
|
2556
|
+
},
|
|
2557
|
+
[rows.length, columns.length, selectCell, scrollCellIntoView]
|
|
2558
|
+
);
|
|
2559
|
+
React21.useEffect(() => {
|
|
2560
|
+
if (!dragging) return;
|
|
2561
|
+
const stop = () => setDragging(false);
|
|
2562
|
+
window.addEventListener("mouseup", stop);
|
|
2563
|
+
return () => window.removeEventListener("mouseup", stop);
|
|
2564
|
+
}, [dragging]);
|
|
2565
|
+
const handleKeyDown = (event) => {
|
|
2566
|
+
const meta = event.metaKey || event.ctrlKey;
|
|
2567
|
+
if (meta && event.key.toLowerCase() === "c") {
|
|
2568
|
+
event.preventDefault();
|
|
2569
|
+
onCopy();
|
|
2570
|
+
return;
|
|
2571
|
+
}
|
|
2572
|
+
if (meta && event.key.toLowerCase() === "a") {
|
|
2573
|
+
event.preventDefault();
|
|
2574
|
+
selectAll();
|
|
2575
|
+
return;
|
|
2576
|
+
}
|
|
2577
|
+
switch (event.key) {
|
|
2578
|
+
case "ArrowUp":
|
|
2579
|
+
event.preventDefault();
|
|
2580
|
+
moveFocus(-1, 0, event.shiftKey);
|
|
2581
|
+
break;
|
|
2582
|
+
case "ArrowDown":
|
|
2583
|
+
event.preventDefault();
|
|
2584
|
+
moveFocus(1, 0, event.shiftKey);
|
|
2585
|
+
break;
|
|
2586
|
+
case "ArrowLeft":
|
|
2587
|
+
event.preventDefault();
|
|
2588
|
+
moveFocus(0, -1, event.shiftKey);
|
|
2589
|
+
break;
|
|
2590
|
+
case "ArrowRight":
|
|
2591
|
+
case "Tab":
|
|
2592
|
+
event.preventDefault();
|
|
2593
|
+
moveFocus(0, 1, event.shiftKey && event.key !== "Tab");
|
|
2594
|
+
break;
|
|
2595
|
+
case "Escape":
|
|
2596
|
+
setSelection(null, null);
|
|
2597
|
+
break;
|
|
2598
|
+
default:
|
|
2599
|
+
break;
|
|
2600
|
+
}
|
|
2601
|
+
};
|
|
2602
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2603
|
+
"div",
|
|
2604
|
+
{
|
|
2605
|
+
ref: gridRef,
|
|
2606
|
+
tabIndex: 0,
|
|
2607
|
+
role: "grid",
|
|
2608
|
+
"aria-label": ariaLabel,
|
|
2609
|
+
onKeyDown: handleKeyDown,
|
|
2610
|
+
className: "border-border bg-background/80 overflow-x-auto rounded-lg border outline-none",
|
|
2611
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("table", { className: "w-full text-sm whitespace-nowrap select-none", children: [
|
|
2612
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("thead", { className: "text-muted-foreground border-border border-b text-left", children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)("tr", { children: [
|
|
2613
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2614
|
+
"th",
|
|
2615
|
+
{
|
|
2616
|
+
scope: "col",
|
|
2617
|
+
className: "w-10 cursor-pointer px-2 py-2 text-center font-medium",
|
|
2618
|
+
title: "Select everything",
|
|
2619
|
+
onMouseDown: () => selectAll(),
|
|
2620
|
+
children: "#"
|
|
2621
|
+
}
|
|
2622
|
+
),
|
|
2623
|
+
columns.map((column, c) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2624
|
+
"th",
|
|
2625
|
+
{
|
|
2626
|
+
scope: "col",
|
|
2627
|
+
className: "cursor-pointer px-3 py-2 font-medium",
|
|
2628
|
+
title: `Select the ${column.title} column`,
|
|
2629
|
+
onMouseDown: (event) => selectColumn(c, event.shiftKey),
|
|
2630
|
+
children: column.title
|
|
2631
|
+
},
|
|
2632
|
+
column.key
|
|
2633
|
+
))
|
|
2634
|
+
] }) }),
|
|
2635
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)("tbody", { children: rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime29.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2636
|
+
"td",
|
|
2637
|
+
{
|
|
2638
|
+
colSpan: columns.length + 1,
|
|
2639
|
+
className: "text-muted-foreground px-3 py-6 text-center",
|
|
2640
|
+
children: loading ? loadingMessage : emptyMessage
|
|
2641
|
+
}
|
|
2642
|
+
) }) : rows.map((row, r) => /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
2643
|
+
"tr",
|
|
2644
|
+
{
|
|
2645
|
+
className: "border-border border-b",
|
|
2646
|
+
children: [
|
|
2647
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2648
|
+
"td",
|
|
2649
|
+
{
|
|
2650
|
+
className: "text-muted-foreground w-10 cursor-pointer px-2 py-2 text-center text-xs",
|
|
2651
|
+
title: "Select this row",
|
|
2652
|
+
onMouseDown: (event) => selectRow(r, event.shiftKey),
|
|
2653
|
+
children: r + 1
|
|
2654
|
+
}
|
|
2655
|
+
),
|
|
2656
|
+
columns.map((column, c) => /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
2657
|
+
"td",
|
|
2658
|
+
{
|
|
2659
|
+
"data-cell": `${r}-${c}`,
|
|
2660
|
+
onMouseDown: (event) => {
|
|
2661
|
+
selectCell(r, c, event.shiftKey);
|
|
2662
|
+
setDragging(true);
|
|
2663
|
+
gridRef.current?.focus();
|
|
2664
|
+
},
|
|
2665
|
+
onMouseEnter: () => {
|
|
2666
|
+
if (dragging) setSelection(anchorRef.current, { r, c });
|
|
2667
|
+
},
|
|
2668
|
+
className: `px-3 py-2 ${column.className || ""} ${isInRange(range, r, c) ? "bg-primary/15" : ""}`,
|
|
2669
|
+
title: column.className?.includes("truncate") ? column.value(row) : void 0,
|
|
2670
|
+
children: column.render ? column.render(row) : column.value(row)
|
|
2671
|
+
},
|
|
2672
|
+
column.key
|
|
2673
|
+
))
|
|
2674
|
+
]
|
|
2675
|
+
},
|
|
2676
|
+
rowKey ? rowKey(row, r) : String(r)
|
|
2677
|
+
)) })
|
|
2678
|
+
] })
|
|
2679
|
+
}
|
|
2680
|
+
);
|
|
2681
|
+
}
|
|
2682
|
+
|
|
2683
|
+
// src/switch.tsx
|
|
2684
|
+
var React22 = __toESM(require("react"), 1);
|
|
2685
|
+
var import_jsx_runtime30 = require("react/jsx-runtime");
|
|
2686
|
+
var Switch = React22.forwardRef(
|
|
2687
|
+
({ checked, onCheckedChange, className, disabled, id, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2688
|
+
"button",
|
|
2689
|
+
{
|
|
2690
|
+
ref,
|
|
2691
|
+
id,
|
|
2692
|
+
type: "button",
|
|
2693
|
+
role: "switch",
|
|
2694
|
+
"aria-checked": checked,
|
|
2695
|
+
disabled,
|
|
2696
|
+
onClick: () => onCheckedChange(!checked),
|
|
2697
|
+
className: cn(
|
|
2698
|
+
// 24×44px track meets DESIGN.md 24px minimum target size.
|
|
2699
|
+
"relative inline-flex h-6 w-11 shrink-0 cursor-pointer items-center rounded-full border transition-colors",
|
|
2700
|
+
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
|
|
2701
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
2702
|
+
checked ? "border-primary bg-primary" : "border-border bg-muted",
|
|
2703
|
+
className
|
|
2704
|
+
),
|
|
2705
|
+
...props,
|
|
2706
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
2707
|
+
"span",
|
|
2708
|
+
{
|
|
2709
|
+
"aria-hidden": true,
|
|
2710
|
+
className: cn(
|
|
2711
|
+
"bg-background pointer-events-none block size-5 rounded-full shadow-sm transition-transform",
|
|
2712
|
+
checked ? "translate-x-5" : "translate-x-0.5"
|
|
2713
|
+
)
|
|
2714
|
+
}
|
|
2715
|
+
)
|
|
2716
|
+
}
|
|
2717
|
+
)
|
|
2718
|
+
);
|
|
2719
|
+
Switch.displayName = "Switch";
|
|
2720
|
+
|
|
2721
|
+
// src/table.tsx
|
|
2722
|
+
var React23 = __toESM(require("react"), 1);
|
|
2723
|
+
var import_jsx_runtime31 = require("react/jsx-runtime");
|
|
2724
|
+
var Table = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("div", { className: "relative w-full overflow-auto", children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2725
|
+
"table",
|
|
2726
|
+
{
|
|
2727
|
+
ref,
|
|
2728
|
+
className: cn("w-full caption-bottom text-sm", className),
|
|
2729
|
+
...props
|
|
2730
|
+
}
|
|
2731
|
+
) }));
|
|
2732
|
+
Table.displayName = "Table";
|
|
2733
|
+
var TableHeader = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)("thead", { ref, className: cn("[&_tr]:border-b", className), ...props }));
|
|
2734
|
+
TableHeader.displayName = "TableHeader";
|
|
2735
|
+
var TableBody = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2736
|
+
"tbody",
|
|
2737
|
+
{
|
|
2738
|
+
ref,
|
|
2739
|
+
className: cn("[&_tr:last-child]:border-0", className),
|
|
2740
|
+
...props
|
|
2741
|
+
}
|
|
2742
|
+
));
|
|
2743
|
+
TableBody.displayName = "TableBody";
|
|
2744
|
+
var TableFooter = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2745
|
+
"tfoot",
|
|
2746
|
+
{
|
|
2747
|
+
ref,
|
|
2748
|
+
className: cn(
|
|
2749
|
+
"bg-muted/50 border-t font-medium [&>tr]:last:border-b-0",
|
|
2750
|
+
className
|
|
2751
|
+
),
|
|
2752
|
+
...props
|
|
2753
|
+
}
|
|
2754
|
+
));
|
|
2755
|
+
TableFooter.displayName = "TableFooter";
|
|
2756
|
+
var TableRow = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2757
|
+
"tr",
|
|
2758
|
+
{
|
|
2759
|
+
ref,
|
|
2760
|
+
className: cn(
|
|
2761
|
+
"hover:bg-muted/50 data-[state=selected]:bg-muted border-b transition-colors",
|
|
2762
|
+
className
|
|
2763
|
+
),
|
|
2764
|
+
...props
|
|
2765
|
+
}
|
|
2766
|
+
));
|
|
2767
|
+
TableRow.displayName = "TableRow";
|
|
2768
|
+
var TableHead = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2769
|
+
"th",
|
|
2770
|
+
{
|
|
2771
|
+
ref,
|
|
2772
|
+
className: cn(
|
|
2773
|
+
"text-muted-foreground h-12 px-4 text-left align-middle font-medium [&:has([role=checkbox])]:pr-0",
|
|
2774
|
+
className
|
|
2775
|
+
),
|
|
2776
|
+
...props
|
|
2777
|
+
}
|
|
2778
|
+
));
|
|
2779
|
+
TableHead.displayName = "TableHead";
|
|
2780
|
+
var TableCell = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2781
|
+
"td",
|
|
2782
|
+
{
|
|
2783
|
+
ref,
|
|
2784
|
+
className: cn("p-4 align-middle [&:has([role=checkbox])]:pr-0", className),
|
|
2785
|
+
...props
|
|
2786
|
+
}
|
|
2787
|
+
));
|
|
2788
|
+
TableCell.displayName = "TableCell";
|
|
2789
|
+
var TableCaption = React23.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
2790
|
+
"caption",
|
|
2791
|
+
{
|
|
2792
|
+
ref,
|
|
2793
|
+
className: cn("text-muted-foreground mt-4 text-sm", className),
|
|
2794
|
+
...props
|
|
2795
|
+
}
|
|
2796
|
+
));
|
|
2797
|
+
TableCaption.displayName = "TableCaption";
|
|
2798
|
+
|
|
2799
|
+
// src/tabs.tsx
|
|
2800
|
+
var React24 = __toESM(require("react"), 1);
|
|
2801
|
+
var import_jsx_runtime32 = require("react/jsx-runtime");
|
|
2802
|
+
function TabPanel({
|
|
2803
|
+
id,
|
|
2804
|
+
labelledBy,
|
|
2805
|
+
active,
|
|
2806
|
+
children,
|
|
2807
|
+
className
|
|
2808
|
+
}) {
|
|
2809
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2810
|
+
"div",
|
|
2811
|
+
{
|
|
2812
|
+
role: "tabpanel",
|
|
2813
|
+
id,
|
|
2814
|
+
"aria-labelledby": labelledBy,
|
|
2815
|
+
hidden: !active,
|
|
2816
|
+
className,
|
|
2817
|
+
children: active ? children : null
|
|
2818
|
+
}
|
|
2819
|
+
);
|
|
2820
|
+
}
|
|
2821
|
+
function Tabs({
|
|
2822
|
+
tabs,
|
|
2823
|
+
value,
|
|
2824
|
+
onChange,
|
|
2825
|
+
ariaLabel,
|
|
2826
|
+
className
|
|
2827
|
+
}) {
|
|
2828
|
+
const refs = React24.useRef(/* @__PURE__ */ new Map());
|
|
2829
|
+
const reactId = React24.useId();
|
|
2830
|
+
const hasInlinePanels = tabs.some((tab) => tab.panel != null);
|
|
2831
|
+
function tabDomId(key) {
|
|
2832
|
+
return `${reactId}-tab-${key}`;
|
|
2833
|
+
}
|
|
2834
|
+
function panelDomId(tab) {
|
|
2835
|
+
return tab.panelId ?? `${reactId}-panel-${tab.key}`;
|
|
2836
|
+
}
|
|
2837
|
+
function focusTab(key) {
|
|
2838
|
+
onChange(key);
|
|
2839
|
+
refs.current.get(key)?.focus();
|
|
2840
|
+
}
|
|
2841
|
+
function onKeyDown(event) {
|
|
2842
|
+
const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
|
|
2843
|
+
if (step === 0) return;
|
|
2844
|
+
const selectable = tabs.filter((tab) => !tab.disabled);
|
|
2845
|
+
if (selectable.length < 2) return;
|
|
2846
|
+
const current = selectable.findIndex((tab) => tab.key === value);
|
|
2847
|
+
const next = selectable[(current + step + selectable.length) % selectable.length];
|
|
2848
|
+
event.preventDefault();
|
|
2849
|
+
focusTab(next.key);
|
|
2850
|
+
}
|
|
2851
|
+
const tablist = /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2852
|
+
"div",
|
|
2853
|
+
{
|
|
2854
|
+
role: "tablist",
|
|
2855
|
+
"aria-label": ariaLabel,
|
|
2856
|
+
onKeyDown,
|
|
2857
|
+
className: cn(
|
|
2858
|
+
"border-border flex flex-wrap gap-1 border-b",
|
|
2859
|
+
!hasInlinePanels ? className : void 0
|
|
2860
|
+
),
|
|
2861
|
+
children: tabs.map((tab) => {
|
|
2862
|
+
const active = tab.key === value;
|
|
2863
|
+
const id = tabDomId(tab.key);
|
|
2864
|
+
const controls = tab.panel != null || tab.panelId ? panelDomId(tab) : void 0;
|
|
2865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
|
|
2866
|
+
"button",
|
|
2867
|
+
{
|
|
2868
|
+
id,
|
|
2869
|
+
ref: (node) => {
|
|
2870
|
+
refs.current.set(tab.key, node);
|
|
2871
|
+
},
|
|
2872
|
+
type: "button",
|
|
2873
|
+
role: "tab",
|
|
2874
|
+
"aria-selected": active,
|
|
2875
|
+
"aria-controls": controls,
|
|
2876
|
+
disabled: tab.disabled,
|
|
2877
|
+
tabIndex: active ? 0 : -1,
|
|
2878
|
+
onClick: () => onChange(tab.key),
|
|
2879
|
+
className: cn(
|
|
2880
|
+
"cursor-pointer rounded-t-md px-3 py-1.5 text-sm font-medium transition",
|
|
2881
|
+
"focus-visible:ring-ring focus-visible:ring-2 focus-visible:outline-none",
|
|
2882
|
+
"disabled:cursor-not-allowed disabled:opacity-50",
|
|
2883
|
+
// The filled-pill active state the five hand-rolled strips
|
|
2884
|
+
// already used. Adopting it keeps this a deduplication rather
|
|
2885
|
+
// than a restyle of every panel that has tabs.
|
|
2886
|
+
active ? "bg-primary text-primary-foreground" : "text-muted-foreground hover:bg-muted"
|
|
2887
|
+
),
|
|
2888
|
+
children: [
|
|
2889
|
+
tab.label,
|
|
2890
|
+
tab.badge != null ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("span", { className: "text-muted-foreground ml-1.5 text-xs", children: tab.badge }) : null
|
|
2891
|
+
]
|
|
2892
|
+
},
|
|
2893
|
+
tab.key
|
|
2894
|
+
);
|
|
2895
|
+
})
|
|
2896
|
+
}
|
|
2897
|
+
);
|
|
2898
|
+
if (!hasInlinePanels) return tablist;
|
|
2899
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: cn("space-y-3", className), children: [
|
|
2900
|
+
tablist,
|
|
2901
|
+
tabs.map(
|
|
2902
|
+
(tab) => tab.panel != null ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
2903
|
+
TabPanel,
|
|
2904
|
+
{
|
|
2905
|
+
id: panelDomId(tab),
|
|
2906
|
+
labelledBy: tabDomId(tab.key),
|
|
2907
|
+
active: tab.key === value,
|
|
2908
|
+
children: tab.panel
|
|
2909
|
+
},
|
|
2910
|
+
tab.key
|
|
2911
|
+
) : null
|
|
2912
|
+
)
|
|
2913
|
+
] });
|
|
2914
|
+
}
|
|
2915
|
+
|
|
2916
|
+
// src/textarea.tsx
|
|
2917
|
+
var React25 = __toESM(require("react"), 1);
|
|
2918
|
+
var import_jsx_runtime33 = require("react/jsx-runtime");
|
|
2919
|
+
var textareaClass = "border-border bg-background focus-visible:ring-ring w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50";
|
|
2920
|
+
var Textarea = React25.forwardRef(
|
|
2921
|
+
({ className, rows = 3, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(
|
|
2922
|
+
"textarea",
|
|
2923
|
+
{
|
|
2924
|
+
ref,
|
|
2925
|
+
rows,
|
|
2926
|
+
className: cn(textareaClass, className),
|
|
2927
|
+
...props
|
|
2928
|
+
}
|
|
2929
|
+
)
|
|
2930
|
+
);
|
|
2931
|
+
Textarea.displayName = "Textarea";
|
|
2932
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
2933
|
+
0 && (module.exports = {
|
|
2934
|
+
Alert,
|
|
2935
|
+
Autocomplete,
|
|
2936
|
+
Badge,
|
|
2937
|
+
Breadcrumb,
|
|
2938
|
+
Button,
|
|
2939
|
+
CSV_DELIMITER,
|
|
2940
|
+
Card,
|
|
2941
|
+
CardContent,
|
|
2942
|
+
CardDescription,
|
|
2943
|
+
CardFooter,
|
|
2944
|
+
CardHeader,
|
|
2945
|
+
CardTitle,
|
|
2946
|
+
Checkbox,
|
|
2947
|
+
CollapsibleSection,
|
|
2948
|
+
ConfirmDialog,
|
|
2949
|
+
CopyButton,
|
|
2950
|
+
DataTable,
|
|
2951
|
+
DateRangePicker,
|
|
2952
|
+
FeatureAccessGate,
|
|
2953
|
+
Field,
|
|
2954
|
+
ImageUploader,
|
|
2955
|
+
Input,
|
|
2956
|
+
Label,
|
|
2957
|
+
Modal,
|
|
2958
|
+
PageHeader,
|
|
2959
|
+
Pagination,
|
|
2960
|
+
PanelBrandMark,
|
|
2961
|
+
PanelSignIn,
|
|
2962
|
+
PanelSignInSkeleton,
|
|
2963
|
+
SegmentedControl,
|
|
2964
|
+
Select,
|
|
2965
|
+
Separator,
|
|
2966
|
+
SideDrawer,
|
|
2967
|
+
Spinner,
|
|
2968
|
+
SpreadsheetGrid,
|
|
2969
|
+
StatePanel,
|
|
2970
|
+
Switch,
|
|
2971
|
+
TSV_DELIMITER,
|
|
2972
|
+
TabPanel,
|
|
2973
|
+
Table,
|
|
2974
|
+
TableBody,
|
|
2975
|
+
TableCaption,
|
|
2976
|
+
TableCell,
|
|
2977
|
+
TableFooter,
|
|
2978
|
+
TableHead,
|
|
2979
|
+
TableHeader,
|
|
2980
|
+
TableRow,
|
|
2981
|
+
Tabs,
|
|
2982
|
+
Textarea,
|
|
2983
|
+
addDays,
|
|
2984
|
+
addMonths,
|
|
2985
|
+
alertVariants,
|
|
2986
|
+
badgeVariants,
|
|
2987
|
+
buildRangeText,
|
|
2988
|
+
checkboxClass,
|
|
2989
|
+
cn,
|
|
2990
|
+
countCells,
|
|
2991
|
+
createdRangeMs,
|
|
2992
|
+
describeRange,
|
|
2993
|
+
endAt2359Ms,
|
|
2994
|
+
endOfDayMs,
|
|
2995
|
+
escapeCell,
|
|
2996
|
+
formatDisplay,
|
|
2997
|
+
fromIsoDate,
|
|
2998
|
+
fullRange,
|
|
2999
|
+
inputClass,
|
|
3000
|
+
isSameDay,
|
|
3001
|
+
monthGrid,
|
|
3002
|
+
monthLabel,
|
|
3003
|
+
normalizeRange,
|
|
3004
|
+
startOfDayMs,
|
|
3005
|
+
startOfMonth,
|
|
3006
|
+
textareaClass,
|
|
3007
|
+
toIsoDate,
|
|
3008
|
+
useDialogLayer,
|
|
3009
|
+
useHasMounted,
|
|
3010
|
+
writeToClipboard
|
|
3011
|
+
});
|
|
3012
|
+
//# sourceMappingURL=index.cjs.map
|