@inshorts/glint-ui 0.5.3 → 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/LICENSE +13 -0
- package/README.md +3 -9
- 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 +395 -19
- 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 -46
- package/src/table.tsx +0 -110
- package/src/tabs.tsx +0 -201
- package/src/textarea.tsx +0 -32
- package/src/utils.ts +0 -6
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
"use strict";
|
|
3
|
+
"use client";
|
|
4
|
+
var __create = Object.create;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
7
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __export = (target, all) => {
|
|
11
|
+
for (var name in all)
|
|
12
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
+
mod
|
|
29
|
+
));
|
|
30
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
31
|
+
|
|
32
|
+
// src/copy-button.tsx
|
|
33
|
+
var copy_button_exports = {};
|
|
34
|
+
__export(copy_button_exports, {
|
|
35
|
+
CopyButton: () => CopyButton
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(copy_button_exports);
|
|
38
|
+
var import_lucide_react = require("lucide-react");
|
|
39
|
+
var React = __toESM(require("react"), 1);
|
|
40
|
+
|
|
41
|
+
// src/clipboard.ts
|
|
42
|
+
async function writeToClipboard(text) {
|
|
43
|
+
if (navigator.clipboard?.writeText) {
|
|
44
|
+
return navigator.clipboard.writeText(text);
|
|
45
|
+
}
|
|
46
|
+
const textarea = document.createElement("textarea");
|
|
47
|
+
textarea.value = text;
|
|
48
|
+
textarea.style.position = "fixed";
|
|
49
|
+
textarea.style.top = "-1000px";
|
|
50
|
+
document.body.appendChild(textarea);
|
|
51
|
+
textarea.select();
|
|
52
|
+
try {
|
|
53
|
+
if (!document.execCommand("copy")) {
|
|
54
|
+
throw new Error("Could not write to the clipboard");
|
|
55
|
+
}
|
|
56
|
+
} finally {
|
|
57
|
+
document.body.removeChild(textarea);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/utils.ts
|
|
62
|
+
var import_clsx = require("clsx");
|
|
63
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
64
|
+
function cn(...inputs) {
|
|
65
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// src/copy-button.tsx
|
|
69
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
70
|
+
function CopyButton({
|
|
71
|
+
value,
|
|
72
|
+
label,
|
|
73
|
+
className
|
|
74
|
+
}) {
|
|
75
|
+
const [copied, setCopied] = React.useState(false);
|
|
76
|
+
React.useEffect(() => {
|
|
77
|
+
if (!copied) return;
|
|
78
|
+
const timer = window.setTimeout(() => setCopied(false), 1500);
|
|
79
|
+
return () => window.clearTimeout(timer);
|
|
80
|
+
}, [copied]);
|
|
81
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
82
|
+
"button",
|
|
83
|
+
{
|
|
84
|
+
type: "button",
|
|
85
|
+
"aria-label": copied ? `${label} copied` : `Copy ${label}`,
|
|
86
|
+
title: copied ? "Copied" : `Copy ${label}`,
|
|
87
|
+
className: cn(
|
|
88
|
+
"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",
|
|
89
|
+
className
|
|
90
|
+
),
|
|
91
|
+
onClick: () => {
|
|
92
|
+
void writeToClipboard(value).then(() => setCopied(true)).catch(() => void 0);
|
|
93
|
+
},
|
|
94
|
+
children: copied ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Check, { className: "size-3.5 text-success", "aria-hidden": true }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Copy, { className: "size-3.5", "aria-hidden": true })
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
99
|
+
0 && (module.exports = {
|
|
100
|
+
CopyButton
|
|
101
|
+
});
|
|
102
|
+
//# sourceMappingURL=copy-button.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/copy-button.tsx","../src/clipboard.ts","../src/utils.ts"],"sourcesContent":["\"use client\";\n\nimport { Check, Copy } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { writeToClipboard } from \"./clipboard\";\nimport { cn } from \"./utils\";\n\n/**\n * Copies one short string — an id, a title, a URL — and says so for a moment.\n *\n * The panel had this three times over, each with its own timeout and its own\n * silent-failure story. `writeToClipboard` is used rather than\n * `navigator.clipboard` directly because the latter is undefined on http\n * origins, which is exactly where this panel runs in local dev.\n */\nexport function CopyButton({\n value,\n label,\n className,\n}: {\n value: string;\n /** What is being copied, for the accessible name: \"card id\", \"title\". */\n label: string;\n className?: string;\n}) {\n const [copied, setCopied] = React.useState(false);\n\n React.useEffect(() => {\n if (!copied) return;\n const timer = window.setTimeout(() => setCopied(false), 1500);\n return () => window.clearTimeout(timer);\n }, [copied]);\n\n return (\n <button\n type=\"button\"\n aria-label={copied ? `${label} copied` : `Copy ${label}`}\n title={copied ? \"Copied\" : `Copy ${label}`}\n className={cn(\n \"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\",\n className,\n )}\n onClick={() => {\n // A denied clipboard permission should not throw into the row.\n void writeToClipboard(value)\n .then(() => setCopied(true))\n .catch(() => undefined);\n }}\n >\n {copied ? (\n <Check className=\"size-3.5 text-success\" aria-hidden />\n ) : (\n <Copy className=\"size-3.5\" aria-hidden />\n )}\n </button>\n );\n}\n","/**\n * Range maths and clipboard text for the card table's spreadsheet selection.\n *\n * Ported from video-shorts-panel `app/src/common/components/ExcelTable.jsx`.\n * Kept free of React and the DOM (except `writeToClipboard`) so the escaping\n * and range rules are unit-testable.\n */\n\nexport type CellRef = { r: number; c: number };\n\nexport type CellRange = { r1: number; r2: number; c1: number; c2: number };\n\n/** Tab for the clipboard (Excel/Sheets split on it), comma for a .csv file. */\nexport const TSV_DELIMITER = \"\\t\";\nexport const CSV_DELIMITER = \",\";\n\n/**\n * Anchor and focus can be dragged in any direction, so the range is whichever\n * corners they happen to be — normalize to top-left / bottom-right.\n */\nexport function normalizeRange(\n anchor: CellRef | null | undefined,\n focus: CellRef | null | undefined,\n): CellRange | null {\n if (!anchor || !focus) return null;\n return {\n r1: Math.min(anchor.r, focus.r),\n r2: Math.max(anchor.r, focus.r),\n c1: Math.min(anchor.c, focus.c),\n c2: Math.max(anchor.c, focus.c),\n };\n}\n\n/**\n * A cell needs quoting once it carries the delimiters themselves — the same\n * rule Excel uses when it parses the clipboard. Without it, a title containing\n * a tab or a newline silently becomes extra columns or rows on paste.\n */\nexport function escapeCell(raw: unknown, delimiter: string): string {\n const value = raw == null ? \"\" : String(raw);\n if (\n value.includes(delimiter) ||\n value.includes(\"\\n\") ||\n value.includes(\"\\r\") ||\n value.includes('\"')\n ) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\nexport type TextColumn<Row> = {\n title: string;\n value: (row: Row) => string;\n};\n\n/** Renders a range as delimited text, optionally with a header line. */\nexport function buildRangeText<Row>(\n range: CellRange | null,\n columns: TextColumn<Row>[],\n rows: Row[],\n delimiter: string,\n includeHeaders: boolean,\n): string {\n if (!range) return \"\";\n const lines: string[] = [];\n\n if (includeHeaders) {\n const header: string[] = [];\n for (let c = range.c1; c <= range.c2; c++) {\n header.push(escapeCell(columns[c]?.title, delimiter));\n }\n lines.push(header.join(delimiter));\n }\n\n for (let r = range.r1; r <= range.r2; r++) {\n const line: string[] = [];\n const row = rows[r];\n for (let c = range.c1; c <= range.c2; c++) {\n const column = columns[c];\n line.push(\n escapeCell(\n column && row !== undefined ? column.value(row) : \"\",\n delimiter,\n ),\n );\n }\n lines.push(line.join(delimiter));\n }\n\n return lines.join(\"\\n\");\n}\n\n/** The whole grid, or null when there is nothing to select. */\nexport function fullRange<Row>(\n columns: TextColumn<Row>[],\n rows: Row[],\n): CellRange | null {\n if (!rows.length || !columns.length) return null;\n return { r1: 0, r2: rows.length - 1, c1: 0, c2: columns.length - 1 };\n}\n\n/** \"3 × 2 selected\" — what the toolbar reports back to the user. */\nexport function describeRange(range: CellRange | null): string {\n if (!range) return \"No selection\";\n const rowCount = range.r2 - range.r1 + 1;\n const colCount = range.c2 - range.c1 + 1;\n if (rowCount === 1 && colCount === 1) return \"1 cell selected\";\n return `${rowCount} × ${colCount} selected`;\n}\n\nexport function countCells(range: CellRange): {\n rows: number;\n columns: number;\n} {\n return {\n rows: range.r2 - range.r1 + 1,\n columns: range.c2 - range.c1 + 1,\n };\n}\n\n/**\n * `navigator.clipboard` is unavailable on http origins and older browsers, so\n * fall back to a hidden textarea + execCommand rather than failing the copy.\n */\nexport async function writeToClipboard(text: string): Promise<void> {\n if (navigator.clipboard?.writeText) {\n return navigator.clipboard.writeText(text);\n }\n\n const textarea = document.createElement(\"textarea\");\n textarea.value = text;\n textarea.style.position = \"fixed\";\n textarea.style.top = \"-1000px\";\n document.body.appendChild(textarea);\n textarea.select();\n try {\n if (!document.execCommand(\"copy\")) {\n throw new Error(\"Could not write to the clipboard\");\n }\n } finally {\n document.body.removeChild(textarea);\n }\n}\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,0BAA4B;AAC5B,YAAuB;;;AC0HvB,eAAsB,iBAAiB,MAA6B;AAClE,MAAI,UAAU,WAAW,WAAW;AAClC,WAAO,UAAU,UAAU,UAAU,IAAI;AAAA,EAC3C;AAEA,QAAM,WAAW,SAAS,cAAc,UAAU;AAClD,WAAS,QAAQ;AACjB,WAAS,MAAM,WAAW;AAC1B,WAAS,MAAM,MAAM;AACrB,WAAS,KAAK,YAAY,QAAQ;AAClC,WAAS,OAAO;AAChB,MAAI;AACF,QAAI,CAAC,SAAS,YAAY,MAAM,GAAG;AACjC,YAAM,IAAI,MAAM,kCAAkC;AAAA,IACpD;AAAA,EACF,UAAE;AACA,aAAS,KAAK,YAAY,QAAQ;AAAA,EACpC;AACF;;;AC/IA,kBAAsC;AACtC,4BAAwB;AAEjB,SAAS,MAAM,QAAsB;AAC1C,aAAO,mCAAQ,kBAAK,MAAM,CAAC;AAC7B;;;AF8CQ;AAnCD,SAAS,WAAW;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,QAAM,CAAC,QAAQ,SAAS,IAAU,eAAS,KAAK;AAEhD,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,OAAQ;AACb,UAAM,QAAQ,OAAO,WAAW,MAAM,UAAU,KAAK,GAAG,IAAI;AAC5D,WAAO,MAAM,OAAO,aAAa,KAAK;AAAA,EACxC,GAAG,CAAC,MAAM,CAAC;AAEX,SACE;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,cAAY,SAAS,GAAG,KAAK,YAAY,QAAQ,KAAK;AAAA,MACtD,OAAO,SAAS,WAAW,QAAQ,KAAK;AAAA,MACxC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MACA,SAAS,MAAM;AAEb,aAAK,iBAAiB,KAAK,EACxB,KAAK,MAAM,UAAU,IAAI,CAAC,EAC1B,MAAM,MAAM,MAAS;AAAA,MAC1B;AAAA,MAEC,mBACC,4CAAC,6BAAM,WAAU,yBAAwB,eAAW,MAAC,IAErD,4CAAC,4BAAK,WAAU,YAAW,eAAW,MAAC;AAAA;AAAA,EAE3C;AAEJ;","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copies one short string — an id, a title, a URL — and says so for a moment.
|
|
5
|
+
*
|
|
6
|
+
* The panel had this three times over, each with its own timeout and its own
|
|
7
|
+
* silent-failure story. `writeToClipboard` is used rather than
|
|
8
|
+
* `navigator.clipboard` directly because the latter is undefined on http
|
|
9
|
+
* origins, which is exactly where this panel runs in local dev.
|
|
10
|
+
*/
|
|
11
|
+
declare function CopyButton({ value, label, className, }: {
|
|
12
|
+
value: string;
|
|
13
|
+
/** What is being copied, for the accessible name: "card id", "title". */
|
|
14
|
+
label: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { CopyButton };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Copies one short string — an id, a title, a URL — and says so for a moment.
|
|
5
|
+
*
|
|
6
|
+
* The panel had this three times over, each with its own timeout and its own
|
|
7
|
+
* silent-failure story. `writeToClipboard` is used rather than
|
|
8
|
+
* `navigator.clipboard` directly because the latter is undefined on http
|
|
9
|
+
* origins, which is exactly where this panel runs in local dev.
|
|
10
|
+
*/
|
|
11
|
+
declare function CopyButton({ value, label, className, }: {
|
|
12
|
+
value: string;
|
|
13
|
+
/** What is being copied, for the accessible name: "card id", "title". */
|
|
14
|
+
label: string;
|
|
15
|
+
className?: string;
|
|
16
|
+
}): React.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { CopyButton };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/data-table.tsx
|
|
21
|
+
var data_table_exports = {};
|
|
22
|
+
__export(data_table_exports, {
|
|
23
|
+
DataTable: () => DataTable
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(data_table_exports);
|
|
26
|
+
|
|
27
|
+
// src/utils.ts
|
|
28
|
+
var import_clsx = require("clsx");
|
|
29
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
30
|
+
function cn(...inputs) {
|
|
31
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// src/data-table.tsx
|
|
35
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
36
|
+
var HEADER_VARIANTS = {
|
|
37
|
+
uppercase: "border-border bg-muted/40 text-muted-foreground border-b text-xs tracking-wide uppercase",
|
|
38
|
+
plain: "text-muted-foreground border-border border-b text-left"
|
|
39
|
+
};
|
|
40
|
+
var DENSITY = {
|
|
41
|
+
comfortable: "px-4 py-3",
|
|
42
|
+
compact: "px-3 py-2"
|
|
43
|
+
};
|
|
44
|
+
var ALIGN = {
|
|
45
|
+
left: "text-left",
|
|
46
|
+
right: "text-right",
|
|
47
|
+
center: "text-center"
|
|
48
|
+
};
|
|
49
|
+
function DataTable({
|
|
50
|
+
columns,
|
|
51
|
+
rows,
|
|
52
|
+
rowKey,
|
|
53
|
+
variant = "uppercase",
|
|
54
|
+
density = "comfortable",
|
|
55
|
+
stickyHeader = false,
|
|
56
|
+
rowClassName,
|
|
57
|
+
emptyMessage,
|
|
58
|
+
footer,
|
|
59
|
+
ariaLabel,
|
|
60
|
+
className,
|
|
61
|
+
tableClassName
|
|
62
|
+
}) {
|
|
63
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
64
|
+
"div",
|
|
65
|
+
{
|
|
66
|
+
className: cn(
|
|
67
|
+
"border-border bg-background/80 overflow-x-auto rounded-lg border",
|
|
68
|
+
className
|
|
69
|
+
),
|
|
70
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
71
|
+
"table",
|
|
72
|
+
{
|
|
73
|
+
"aria-label": ariaLabel,
|
|
74
|
+
className: cn("min-w-full text-left text-sm", tableClassName),
|
|
75
|
+
children: [
|
|
76
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
77
|
+
"thead",
|
|
78
|
+
{
|
|
79
|
+
className: cn(
|
|
80
|
+
HEADER_VARIANTS[variant],
|
|
81
|
+
stickyHeader && "bg-muted sticky top-0 z-10"
|
|
82
|
+
),
|
|
83
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
84
|
+
"th",
|
|
85
|
+
{
|
|
86
|
+
scope: "col",
|
|
87
|
+
"aria-sort": column.ariaSort,
|
|
88
|
+
className: cn(
|
|
89
|
+
DENSITY[density],
|
|
90
|
+
"font-medium",
|
|
91
|
+
ALIGN[column.align ?? "left"],
|
|
92
|
+
column.headerClassName
|
|
93
|
+
),
|
|
94
|
+
children: column.title
|
|
95
|
+
},
|
|
96
|
+
column.key
|
|
97
|
+
)) })
|
|
98
|
+
}
|
|
99
|
+
),
|
|
100
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: rows.length === 0 && emptyMessage != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
101
|
+
"td",
|
|
102
|
+
{
|
|
103
|
+
colSpan: columns.length,
|
|
104
|
+
className: "text-muted-foreground px-4 py-6 text-center text-sm",
|
|
105
|
+
children: emptyMessage
|
|
106
|
+
}
|
|
107
|
+
) }) : rows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
108
|
+
"tr",
|
|
109
|
+
{
|
|
110
|
+
className: cn(
|
|
111
|
+
"border-border/70 border-b last:border-0",
|
|
112
|
+
rowClassName?.(row, index)
|
|
113
|
+
),
|
|
114
|
+
children: columns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
115
|
+
"td",
|
|
116
|
+
{
|
|
117
|
+
className: cn(
|
|
118
|
+
DENSITY[density],
|
|
119
|
+
ALIGN[column.align ?? "left"],
|
|
120
|
+
column.className
|
|
121
|
+
),
|
|
122
|
+
children: column.cell(row, index)
|
|
123
|
+
},
|
|
124
|
+
column.key
|
|
125
|
+
))
|
|
126
|
+
},
|
|
127
|
+
rowKey(row, index)
|
|
128
|
+
)) }),
|
|
129
|
+
footer != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tfoot", { children: footer }) : null
|
|
130
|
+
]
|
|
131
|
+
}
|
|
132
|
+
)
|
|
133
|
+
}
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
137
|
+
0 && (module.exports = {
|
|
138
|
+
DataTable
|
|
139
|
+
});
|
|
140
|
+
//# sourceMappingURL=data-table.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data-table.tsx","../src/utils.ts"],"sourcesContent":["import * as React from \"react\";\n\nimport { cn } from \"./utils\";\n\n/**\n * The list table every feature panel was hand-rolling.\n *\n * Seventeen files repeated the same wrapper string\n * (`border-border bg-background/80 overflow-x-auto rounded-lg border`) and the\n * header had already drifted into two incompatible looks, so Campaigns and\n * Targets did not resemble each other. Both are kept as `variant` rather than\n * unified here: collapsing them is a visual change to ten panels and belongs in\n * its own reviewable diff, not smuggled in with a refactor.\n *\n * The column contract deliberately echoes `GridColumn` in\n * `spreadsheet-grid.tsx` — `key`, `title`, a renderer, an optional class — so\n * the repo has one shape to learn. It drops that type's `value: (row) => string`\n * because there is no clipboard or CSV here; nothing would keep it honest, and\n * a required field nobody reads gets filled in with lies.\n *\n * **Not for every table.** `GroupTable` renders parent and child rows with\n * different column counts, and `BusinessTable`'s rows are dnd-kit sortables that\n * own their own refs and transforms. `PublishModal`, `BulkCreateModal` and the\n * clone queue in `MetaAdSetsPanel` are grids of inputs rather than lists of\n * values — every cell is an editable control, and they size their header and\n * body rows differently on purpose. All five are legitimately tables of a\n * different kind; bending this component around them would cost more than it\n * saves.\n */\nexport type TableColumn<Row> = {\n key: string;\n /** Node, not string: a header can carry a select-all box or a sort control. */\n title: React.ReactNode;\n cell: (row: Row, index: number) => React.ReactNode;\n align?: \"left\" | \"right\" | \"center\";\n /**\n * Set on a sortable column so a screen reader announces the current sort.\n * Only the sorted column says `ascending`/`descending`; the rest say `none`,\n * which is what marks them as sortable at all.\n */\n ariaSort?: \"ascending\" | \"descending\" | \"none\";\n /** Extra classes for this column's `<td>`. */\n className?: string;\n /** Extra classes for this column's `<th>`. */\n headerClassName?: string;\n};\n\nexport interface DataTableProps<Row> {\n columns: TableColumn<Row>[];\n rows: Row[];\n /** Stable React key per row. */\n rowKey: (row: Row, index: number) => string;\n /**\n * `uppercase` — the tinted small-caps header (campaigns, showcase, filters).\n * `plain` — the quieter left-aligned header (ads, targets, creatives).\n */\n variant?: \"uppercase\" | \"plain\";\n /**\n * `comfortable` — the roomy default, for tables of a handful of columns.\n * `compact` — what every table of eight columns or more had already chosen by\n * hand, because the roomy padding pushes them into a horizontal scroll.\n */\n density?: \"comfortable\" | \"compact\";\n /** Pins the header for a table inside its own scroll container. */\n stickyHeader?: boolean;\n rowClassName?: (row: Row, index: number) => string | undefined;\n /** Rendered in place of `<tbody>` rows when there are none. */\n emptyMessage?: React.ReactNode;\n /**\n * Rows for a `<tfoot>` — a totals line, typically. The caller supplies the\n * `<tr>` itself because a summary row rarely lines up with the columns above\n * it; designer-counts spans its first two.\n */\n footer?: React.ReactNode;\n /** Names the table for screen readers when no visible caption fits. */\n ariaLabel?: string;\n /** Classes for the scroll wrapper. */\n className?: string;\n /** Classes for the `<table>`. */\n tableClassName?: string;\n}\n\nconst HEADER_VARIANTS = {\n uppercase:\n \"border-border bg-muted/40 text-muted-foreground border-b text-xs tracking-wide uppercase\",\n plain: \"text-muted-foreground border-border border-b text-left\",\n} as const;\n\nconst DENSITY = {\n comfortable: \"px-4 py-3\",\n compact: \"px-3 py-2\",\n} as const;\n\nconst ALIGN = {\n left: \"text-left\",\n right: \"text-right\",\n center: \"text-center\",\n} as const;\n\nexport function DataTable<Row>({\n columns,\n rows,\n rowKey,\n variant = \"uppercase\",\n density = \"comfortable\",\n stickyHeader = false,\n rowClassName,\n emptyMessage,\n footer,\n ariaLabel,\n className,\n tableClassName,\n}: DataTableProps<Row>) {\n return (\n <div\n className={cn(\n \"border-border bg-background/80 overflow-x-auto rounded-lg border\",\n className,\n )}\n >\n <table\n aria-label={ariaLabel}\n className={cn(\"min-w-full text-left text-sm\", tableClassName)}\n >\n <thead\n className={cn(\n HEADER_VARIANTS[variant],\n stickyHeader && \"bg-muted sticky top-0 z-10\",\n )}\n >\n <tr>\n {columns.map((column) => (\n <th\n key={column.key}\n scope=\"col\"\n aria-sort={column.ariaSort}\n className={cn(\n DENSITY[density],\n \"font-medium\",\n ALIGN[column.align ?? \"left\"],\n column.headerClassName,\n )}\n >\n {column.title}\n </th>\n ))}\n </tr>\n </thead>\n <tbody>\n {rows.length === 0 && emptyMessage != null ? (\n <tr>\n {/* One cell across the whole width — a short row would otherwise\n leave the message sitting under the first column. */}\n <td\n colSpan={columns.length}\n className=\"text-muted-foreground px-4 py-6 text-center text-sm\"\n >\n {emptyMessage}\n </td>\n </tr>\n ) : (\n rows.map((row, index) => (\n <tr\n key={rowKey(row, index)}\n className={cn(\n \"border-border/70 border-b last:border-0\",\n rowClassName?.(row, index),\n )}\n >\n {columns.map((column) => (\n <td\n key={column.key}\n className={cn(\n DENSITY[density],\n ALIGN[column.align ?? \"left\"],\n column.className,\n )}\n >\n {column.cell(row, index)}\n </td>\n ))}\n </tr>\n ))\n )}\n </tbody>\n {footer != null ? <tfoot>{footer}</tfoot> : null}\n </table>\n </div>\n );\n}\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,kBAAsC;AACtC,4BAAwB;AAEjB,SAAS,MAAM,QAAsB;AAC1C,aAAO,mCAAQ,kBAAK,MAAM,CAAC;AAC7B;;;ADmHM;AAtCN,IAAM,kBAAkB;AAAA,EACtB,WACE;AAAA,EACF,OAAO;AACT;AAEA,IAAM,UAAU;AAAA,EACd,aAAa;AAAA,EACb,SAAS;AACX;AAEA,IAAM,QAAQ;AAAA,EACZ,MAAM;AAAA,EACN,OAAO;AAAA,EACP,QAAQ;AACV;AAEO,SAAS,UAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,UAAU;AAAA,EACV,eAAe;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAAwB;AACtB,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACA;AAAA,MACF;AAAA,MAEA;AAAA,QAAC;AAAA;AAAA,UACC,cAAY;AAAA,UACZ,WAAW,GAAG,gCAAgC,cAAc;AAAA,UAE5D;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAW;AAAA,kBACT,gBAAgB,OAAO;AAAA,kBACvB,gBAAgB;AAAA,gBAClB;AAAA,gBAEA,sDAAC,QACE,kBAAQ,IAAI,CAAC,WACZ;AAAA,kBAAC;AAAA;AAAA,oBAEC,OAAM;AAAA,oBACN,aAAW,OAAO;AAAA,oBAClB,WAAW;AAAA,sBACT,QAAQ,OAAO;AAAA,sBACf;AAAA,sBACA,MAAM,OAAO,SAAS,MAAM;AAAA,sBAC5B,OAAO;AAAA,oBACT;AAAA,oBAEC,iBAAO;AAAA;AAAA,kBAVH,OAAO;AAAA,gBAWd,CACD,GACH;AAAA;AAAA,YACF;AAAA,YACA,4CAAC,WACE,eAAK,WAAW,KAAK,gBAAgB,OACpC,4CAAC,QAGC;AAAA,cAAC;AAAA;AAAA,gBACC,SAAS,QAAQ;AAAA,gBACjB,WAAU;AAAA,gBAET;AAAA;AAAA,YACH,GACF,IAEA,KAAK,IAAI,CAAC,KAAK,UACb;AAAA,cAAC;AAAA;AAAA,gBAEC,WAAW;AAAA,kBACT;AAAA,kBACA,eAAe,KAAK,KAAK;AAAA,gBAC3B;AAAA,gBAEC,kBAAQ,IAAI,CAAC,WACZ;AAAA,kBAAC;AAAA;AAAA,oBAEC,WAAW;AAAA,sBACT,QAAQ,OAAO;AAAA,sBACf,MAAM,OAAO,SAAS,MAAM;AAAA,sBAC5B,OAAO;AAAA,oBACT;AAAA,oBAEC,iBAAO,KAAK,KAAK,KAAK;AAAA;AAAA,kBAPlB,OAAO;AAAA,gBAQd,CACD;AAAA;AAAA,cAjBI,OAAO,KAAK,KAAK;AAAA,YAkBxB,CACD,GAEL;AAAA,YACC,UAAU,OAAO,4CAAC,WAAO,kBAAO,IAAW;AAAA;AAAA;AAAA,MAC9C;AAAA;AAAA,EACF;AAEJ;","names":[]}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The list table every feature panel was hand-rolling.
|
|
5
|
+
*
|
|
6
|
+
* Seventeen files repeated the same wrapper string
|
|
7
|
+
* (`border-border bg-background/80 overflow-x-auto rounded-lg border`) and the
|
|
8
|
+
* header had already drifted into two incompatible looks, so Campaigns and
|
|
9
|
+
* Targets did not resemble each other. Both are kept as `variant` rather than
|
|
10
|
+
* unified here: collapsing them is a visual change to ten panels and belongs in
|
|
11
|
+
* its own reviewable diff, not smuggled in with a refactor.
|
|
12
|
+
*
|
|
13
|
+
* The column contract deliberately echoes `GridColumn` in
|
|
14
|
+
* `spreadsheet-grid.tsx` — `key`, `title`, a renderer, an optional class — so
|
|
15
|
+
* the repo has one shape to learn. It drops that type's `value: (row) => string`
|
|
16
|
+
* because there is no clipboard or CSV here; nothing would keep it honest, and
|
|
17
|
+
* a required field nobody reads gets filled in with lies.
|
|
18
|
+
*
|
|
19
|
+
* **Not for every table.** `GroupTable` renders parent and child rows with
|
|
20
|
+
* different column counts, and `BusinessTable`'s rows are dnd-kit sortables that
|
|
21
|
+
* own their own refs and transforms. `PublishModal`, `BulkCreateModal` and the
|
|
22
|
+
* clone queue in `MetaAdSetsPanel` are grids of inputs rather than lists of
|
|
23
|
+
* values — every cell is an editable control, and they size their header and
|
|
24
|
+
* body rows differently on purpose. All five are legitimately tables of a
|
|
25
|
+
* different kind; bending this component around them would cost more than it
|
|
26
|
+
* saves.
|
|
27
|
+
*/
|
|
28
|
+
type TableColumn<Row> = {
|
|
29
|
+
key: string;
|
|
30
|
+
/** Node, not string: a header can carry a select-all box or a sort control. */
|
|
31
|
+
title: React.ReactNode;
|
|
32
|
+
cell: (row: Row, index: number) => React.ReactNode;
|
|
33
|
+
align?: "left" | "right" | "center";
|
|
34
|
+
/**
|
|
35
|
+
* Set on a sortable column so a screen reader announces the current sort.
|
|
36
|
+
* Only the sorted column says `ascending`/`descending`; the rest say `none`,
|
|
37
|
+
* which is what marks them as sortable at all.
|
|
38
|
+
*/
|
|
39
|
+
ariaSort?: "ascending" | "descending" | "none";
|
|
40
|
+
/** Extra classes for this column's `<td>`. */
|
|
41
|
+
className?: string;
|
|
42
|
+
/** Extra classes for this column's `<th>`. */
|
|
43
|
+
headerClassName?: string;
|
|
44
|
+
};
|
|
45
|
+
interface DataTableProps<Row> {
|
|
46
|
+
columns: TableColumn<Row>[];
|
|
47
|
+
rows: Row[];
|
|
48
|
+
/** Stable React key per row. */
|
|
49
|
+
rowKey: (row: Row, index: number) => string;
|
|
50
|
+
/**
|
|
51
|
+
* `uppercase` — the tinted small-caps header (campaigns, showcase, filters).
|
|
52
|
+
* `plain` — the quieter left-aligned header (ads, targets, creatives).
|
|
53
|
+
*/
|
|
54
|
+
variant?: "uppercase" | "plain";
|
|
55
|
+
/**
|
|
56
|
+
* `comfortable` — the roomy default, for tables of a handful of columns.
|
|
57
|
+
* `compact` — what every table of eight columns or more had already chosen by
|
|
58
|
+
* hand, because the roomy padding pushes them into a horizontal scroll.
|
|
59
|
+
*/
|
|
60
|
+
density?: "comfortable" | "compact";
|
|
61
|
+
/** Pins the header for a table inside its own scroll container. */
|
|
62
|
+
stickyHeader?: boolean;
|
|
63
|
+
rowClassName?: (row: Row, index: number) => string | undefined;
|
|
64
|
+
/** Rendered in place of `<tbody>` rows when there are none. */
|
|
65
|
+
emptyMessage?: React.ReactNode;
|
|
66
|
+
/**
|
|
67
|
+
* Rows for a `<tfoot>` — a totals line, typically. The caller supplies the
|
|
68
|
+
* `<tr>` itself because a summary row rarely lines up with the columns above
|
|
69
|
+
* it; designer-counts spans its first two.
|
|
70
|
+
*/
|
|
71
|
+
footer?: React.ReactNode;
|
|
72
|
+
/** Names the table for screen readers when no visible caption fits. */
|
|
73
|
+
ariaLabel?: string;
|
|
74
|
+
/** Classes for the scroll wrapper. */
|
|
75
|
+
className?: string;
|
|
76
|
+
/** Classes for the `<table>`. */
|
|
77
|
+
tableClassName?: string;
|
|
78
|
+
}
|
|
79
|
+
declare function DataTable<Row>({ columns, rows, rowKey, variant, density, stickyHeader, rowClassName, emptyMessage, footer, ariaLabel, className, tableClassName, }: DataTableProps<Row>): React.JSX.Element;
|
|
80
|
+
|
|
81
|
+
export { DataTable, type DataTableProps, type TableColumn };
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The list table every feature panel was hand-rolling.
|
|
5
|
+
*
|
|
6
|
+
* Seventeen files repeated the same wrapper string
|
|
7
|
+
* (`border-border bg-background/80 overflow-x-auto rounded-lg border`) and the
|
|
8
|
+
* header had already drifted into two incompatible looks, so Campaigns and
|
|
9
|
+
* Targets did not resemble each other. Both are kept as `variant` rather than
|
|
10
|
+
* unified here: collapsing them is a visual change to ten panels and belongs in
|
|
11
|
+
* its own reviewable diff, not smuggled in with a refactor.
|
|
12
|
+
*
|
|
13
|
+
* The column contract deliberately echoes `GridColumn` in
|
|
14
|
+
* `spreadsheet-grid.tsx` — `key`, `title`, a renderer, an optional class — so
|
|
15
|
+
* the repo has one shape to learn. It drops that type's `value: (row) => string`
|
|
16
|
+
* because there is no clipboard or CSV here; nothing would keep it honest, and
|
|
17
|
+
* a required field nobody reads gets filled in with lies.
|
|
18
|
+
*
|
|
19
|
+
* **Not for every table.** `GroupTable` renders parent and child rows with
|
|
20
|
+
* different column counts, and `BusinessTable`'s rows are dnd-kit sortables that
|
|
21
|
+
* own their own refs and transforms. `PublishModal`, `BulkCreateModal` and the
|
|
22
|
+
* clone queue in `MetaAdSetsPanel` are grids of inputs rather than lists of
|
|
23
|
+
* values — every cell is an editable control, and they size their header and
|
|
24
|
+
* body rows differently on purpose. All five are legitimately tables of a
|
|
25
|
+
* different kind; bending this component around them would cost more than it
|
|
26
|
+
* saves.
|
|
27
|
+
*/
|
|
28
|
+
type TableColumn<Row> = {
|
|
29
|
+
key: string;
|
|
30
|
+
/** Node, not string: a header can carry a select-all box or a sort control. */
|
|
31
|
+
title: React.ReactNode;
|
|
32
|
+
cell: (row: Row, index: number) => React.ReactNode;
|
|
33
|
+
align?: "left" | "right" | "center";
|
|
34
|
+
/**
|
|
35
|
+
* Set on a sortable column so a screen reader announces the current sort.
|
|
36
|
+
* Only the sorted column says `ascending`/`descending`; the rest say `none`,
|
|
37
|
+
* which is what marks them as sortable at all.
|
|
38
|
+
*/
|
|
39
|
+
ariaSort?: "ascending" | "descending" | "none";
|
|
40
|
+
/** Extra classes for this column's `<td>`. */
|
|
41
|
+
className?: string;
|
|
42
|
+
/** Extra classes for this column's `<th>`. */
|
|
43
|
+
headerClassName?: string;
|
|
44
|
+
};
|
|
45
|
+
interface DataTableProps<Row> {
|
|
46
|
+
columns: TableColumn<Row>[];
|
|
47
|
+
rows: Row[];
|
|
48
|
+
/** Stable React key per row. */
|
|
49
|
+
rowKey: (row: Row, index: number) => string;
|
|
50
|
+
/**
|
|
51
|
+
* `uppercase` — the tinted small-caps header (campaigns, showcase, filters).
|
|
52
|
+
* `plain` — the quieter left-aligned header (ads, targets, creatives).
|
|
53
|
+
*/
|
|
54
|
+
variant?: "uppercase" | "plain";
|
|
55
|
+
/**
|
|
56
|
+
* `comfortable` — the roomy default, for tables of a handful of columns.
|
|
57
|
+
* `compact` — what every table of eight columns or more had already chosen by
|
|
58
|
+
* hand, because the roomy padding pushes them into a horizontal scroll.
|
|
59
|
+
*/
|
|
60
|
+
density?: "comfortable" | "compact";
|
|
61
|
+
/** Pins the header for a table inside its own scroll container. */
|
|
62
|
+
stickyHeader?: boolean;
|
|
63
|
+
rowClassName?: (row: Row, index: number) => string | undefined;
|
|
64
|
+
/** Rendered in place of `<tbody>` rows when there are none. */
|
|
65
|
+
emptyMessage?: React.ReactNode;
|
|
66
|
+
/**
|
|
67
|
+
* Rows for a `<tfoot>` — a totals line, typically. The caller supplies the
|
|
68
|
+
* `<tr>` itself because a summary row rarely lines up with the columns above
|
|
69
|
+
* it; designer-counts spans its first two.
|
|
70
|
+
*/
|
|
71
|
+
footer?: React.ReactNode;
|
|
72
|
+
/** Names the table for screen readers when no visible caption fits. */
|
|
73
|
+
ariaLabel?: string;
|
|
74
|
+
/** Classes for the scroll wrapper. */
|
|
75
|
+
className?: string;
|
|
76
|
+
/** Classes for the `<table>`. */
|
|
77
|
+
tableClassName?: string;
|
|
78
|
+
}
|
|
79
|
+
declare function DataTable<Row>({ columns, rows, rowKey, variant, density, stickyHeader, rowClassName, emptyMessage, footer, ariaLabel, className, tableClassName, }: DataTableProps<Row>): React.JSX.Element;
|
|
80
|
+
|
|
81
|
+
export { DataTable, type DataTableProps, type TableColumn };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/date-range-picker/dateRange.ts
|
|
21
|
+
var dateRange_exports = {};
|
|
22
|
+
__export(dateRange_exports, {
|
|
23
|
+
addDays: () => addDays,
|
|
24
|
+
addMonths: () => addMonths,
|
|
25
|
+
createdRangeMs: () => createdRangeMs,
|
|
26
|
+
endAt2359Ms: () => endAt2359Ms,
|
|
27
|
+
endOfDayMs: () => endOfDayMs,
|
|
28
|
+
formatDisplay: () => formatDisplay,
|
|
29
|
+
fromIsoDate: () => fromIsoDate,
|
|
30
|
+
isSameDay: () => isSameDay,
|
|
31
|
+
monthGrid: () => monthGrid,
|
|
32
|
+
monthLabel: () => monthLabel,
|
|
33
|
+
startOfDayMs: () => startOfDayMs,
|
|
34
|
+
startOfMonth: () => startOfMonth,
|
|
35
|
+
toIsoDate: () => toIsoDate
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(dateRange_exports);
|
|
38
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
39
|
+
function toIsoDate(date) {
|
|
40
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
41
|
+
}
|
|
42
|
+
function fromIsoDate(value) {
|
|
43
|
+
if (!value) return null;
|
|
44
|
+
const trimmed = value.trim();
|
|
45
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed);
|
|
46
|
+
if (!match) return null;
|
|
47
|
+
const date = new Date(
|
|
48
|
+
Number(match[1]),
|
|
49
|
+
Number(match[2]) - 1,
|
|
50
|
+
Number(match[3])
|
|
51
|
+
);
|
|
52
|
+
return toIsoDate(date) === trimmed ? date : null;
|
|
53
|
+
}
|
|
54
|
+
function startOfMonth(date) {
|
|
55
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
56
|
+
}
|
|
57
|
+
function addMonths(date, count) {
|
|
58
|
+
return new Date(date.getFullYear(), date.getMonth() + count, 1);
|
|
59
|
+
}
|
|
60
|
+
function addDays(date, count) {
|
|
61
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + count);
|
|
62
|
+
}
|
|
63
|
+
function isSameDay(a, b) {
|
|
64
|
+
if (!a || !b) return false;
|
|
65
|
+
return toIsoDate(a) === toIsoDate(b);
|
|
66
|
+
}
|
|
67
|
+
function monthGrid(month) {
|
|
68
|
+
const first = startOfMonth(month);
|
|
69
|
+
const start = addDays(first, -first.getDay());
|
|
70
|
+
return Array.from({ length: 42 }, (_, index) => addDays(start, index));
|
|
71
|
+
}
|
|
72
|
+
function monthLabel(month, locale = "en-IN") {
|
|
73
|
+
return month.toLocaleDateString(locale, { month: "long", year: "numeric" });
|
|
74
|
+
}
|
|
75
|
+
function formatDisplay(value, locale = "en-IN") {
|
|
76
|
+
const date = fromIsoDate(value);
|
|
77
|
+
if (!date) return "";
|
|
78
|
+
return date.toLocaleDateString(locale, {
|
|
79
|
+
day: "numeric",
|
|
80
|
+
month: "short",
|
|
81
|
+
year: "numeric"
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
function startOfDayMs(value) {
|
|
85
|
+
const date = fromIsoDate(value);
|
|
86
|
+
return date ? date.getTime() : 0;
|
|
87
|
+
}
|
|
88
|
+
function endOfDayMs(value) {
|
|
89
|
+
const date = fromIsoDate(value);
|
|
90
|
+
if (!date) return 0;
|
|
91
|
+
return new Date(
|
|
92
|
+
date.getFullYear(),
|
|
93
|
+
date.getMonth(),
|
|
94
|
+
date.getDate(),
|
|
95
|
+
23,
|
|
96
|
+
59,
|
|
97
|
+
59,
|
|
98
|
+
999
|
|
99
|
+
).getTime();
|
|
100
|
+
}
|
|
101
|
+
function endAt2359Ms(value) {
|
|
102
|
+
const date = fromIsoDate(value);
|
|
103
|
+
if (!date) return 0;
|
|
104
|
+
return new Date(
|
|
105
|
+
date.getFullYear(),
|
|
106
|
+
date.getMonth(),
|
|
107
|
+
date.getDate(),
|
|
108
|
+
23,
|
|
109
|
+
59,
|
|
110
|
+
59,
|
|
111
|
+
0
|
|
112
|
+
).getTime();
|
|
113
|
+
}
|
|
114
|
+
function createdRangeMs(from, to) {
|
|
115
|
+
const startDate = from.trim() || to.trim();
|
|
116
|
+
const endDate = to.trim() || from.trim();
|
|
117
|
+
return {
|
|
118
|
+
start_time: startOfDayMs(startDate),
|
|
119
|
+
end_time: endAt2359Ms(endDate)
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
123
|
+
0 && (module.exports = {
|
|
124
|
+
addDays,
|
|
125
|
+
addMonths,
|
|
126
|
+
createdRangeMs,
|
|
127
|
+
endAt2359Ms,
|
|
128
|
+
endOfDayMs,
|
|
129
|
+
formatDisplay,
|
|
130
|
+
fromIsoDate,
|
|
131
|
+
isSameDay,
|
|
132
|
+
monthGrid,
|
|
133
|
+
monthLabel,
|
|
134
|
+
startOfDayMs,
|
|
135
|
+
startOfMonth,
|
|
136
|
+
toIsoDate
|
|
137
|
+
});
|
|
138
|
+
//# sourceMappingURL=dateRange.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/date-range-picker/dateRange.ts"],"sourcesContent":["/**\n * Date helpers for the range picker, all in local time.\n *\n * Deliberately not `toISOString()`: that converts to UTC first, so on any\n * negative-offset day it returns yesterday's date and the picker highlights the\n * wrong cell. Every value here is built and read as the local calendar day the\n * user is actually looking at.\n */\n\n/** `YYYY-MM-DD`, the value shape the filters store. */\nexport type IsoDate = string;\n\nconst pad = (n: number) => String(n).padStart(2, \"0\");\n\nexport function toIsoDate(date: Date): IsoDate {\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;\n}\n\n/** Parses `YYYY-MM-DD` into a local midnight Date; null for anything else. */\nexport function fromIsoDate(value: string | null | undefined): Date | null {\n if (!value) return null;\n const trimmed = value.trim();\n const match = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(trimmed);\n if (!match) return null;\n const date = new Date(\n Number(match[1]),\n Number(match[2]) - 1,\n Number(match[3]),\n );\n // Rejects 2026-02-31, which would otherwise roll silently into March.\n return toIsoDate(date) === trimmed ? date : null;\n}\n\nexport function startOfMonth(date: Date): Date {\n return new Date(date.getFullYear(), date.getMonth(), 1);\n}\n\nexport function addMonths(date: Date, count: number): Date {\n return new Date(date.getFullYear(), date.getMonth() + count, 1);\n}\n\nexport function addDays(date: Date, count: number): Date {\n return new Date(date.getFullYear(), date.getMonth(), date.getDate() + count);\n}\n\nexport function isSameDay(a: Date | null, b: Date | null): boolean {\n if (!a || !b) return false;\n return toIsoDate(a) === toIsoDate(b);\n}\n\n/**\n * The six-week grid for a month, Sunday-first, padded with the neighbouring\n * months so every row has seven cells.\n *\n * Always six rows, never five: a grid that changes height as you page through\n * months makes everything below it jump.\n */\nexport function monthGrid(month: Date): Date[] {\n const first = startOfMonth(month);\n const start = addDays(first, -first.getDay());\n return Array.from({ length: 42 }, (_, index) => addDays(start, index));\n}\n\nexport function monthLabel(month: Date, locale = \"en-IN\"): string {\n return month.toLocaleDateString(locale, { month: \"long\", year: \"numeric\" });\n}\n\n/** Human form for the trigger — \"22 Aug 2026\". */\nexport function formatDisplay(value: string, locale = \"en-IN\"): string {\n const date = fromIsoDate(value);\n if (!date) return \"\";\n return date.toLocaleDateString(locale, {\n day: \"numeric\",\n month: \"short\",\n year: \"numeric\",\n });\n}\n\nexport function startOfDayMs(value: string): number {\n const date = fromIsoDate(value);\n return date ? date.getTime() : 0;\n}\n\n/**\n * The end of a day as milliseconds.\n *\n * A range picked as whole days has to include everything created on the last\n * day, so \"to\" means 23:59:59.999 rather than that morning's midnight — which\n * would drop a whole day of cards without saying so.\n */\nexport function endOfDayMs(value: string): number {\n const date = fromIsoDate(value);\n if (!date) return 0;\n return new Date(\n date.getFullYear(),\n date.getMonth(),\n date.getDate(),\n 23,\n 59,\n 59,\n 999,\n ).getTime();\n}\n\n/**\n * 11:59 PM on that local day, as 23:59:59.\n *\n * The next midnight is already the following date, and the feed includes that\n * whole day — so the 28th through the 28th came back with the 29th. Stopping\n * at 11:59 PM keeps the end on the day that was picked.\n */\nexport function endAt2359Ms(value: string): number {\n const date = fromIsoDate(value);\n if (!date) return 0;\n return new Date(\n date.getFullYear(),\n date.getMonth(),\n date.getDate(),\n 23,\n 59,\n 59,\n 0,\n ).getTime();\n}\n\n/**\n * Created-date window for the feed.\n *\n * A blank end means the start day, so one selected date is that whole day.\n * `end_time` is 11:59 PM on the end date.\n */\nexport function createdRangeMs(\n from: string,\n to: string,\n): { start_time: number; end_time: number } {\n const startDate = from.trim() || to.trim();\n const endDate = to.trim() || from.trim();\n return {\n start_time: startOfDayMs(startDate),\n end_time: endAt2359Ms(endDate),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAYA,IAAM,MAAM,CAAC,MAAc,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AAE7C,SAAS,UAAU,MAAqB;AAC7C,SAAO,GAAG,KAAK,YAAY,CAAC,IAAI,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,IAAI,IAAI,KAAK,QAAQ,CAAC,CAAC;AACjF;AAGO,SAAS,YAAY,OAA+C;AACzE,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,UAAU,MAAM,KAAK;AAC3B,QAAM,QAAQ,4BAA4B,KAAK,OAAO;AACtD,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,OAAO,IAAI;AAAA,IACf,OAAO,MAAM,CAAC,CAAC;AAAA,IACf,OAAO,MAAM,CAAC,CAAC,IAAI;AAAA,IACnB,OAAO,MAAM,CAAC,CAAC;AAAA,EACjB;AAEA,SAAO,UAAU,IAAI,MAAM,UAAU,OAAO;AAC9C;AAEO,SAAS,aAAa,MAAkB;AAC7C,SAAO,IAAI,KAAK,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,CAAC;AACxD;AAEO,SAAS,UAAU,MAAY,OAAqB;AACzD,SAAO,IAAI,KAAK,KAAK,YAAY,GAAG,KAAK,SAAS,IAAI,OAAO,CAAC;AAChE;AAEO,SAAS,QAAQ,MAAY,OAAqB;AACvD,SAAO,IAAI,KAAK,KAAK,YAAY,GAAG,KAAK,SAAS,GAAG,KAAK,QAAQ,IAAI,KAAK;AAC7E;AAEO,SAAS,UAAU,GAAgB,GAAyB;AACjE,MAAI,CAAC,KAAK,CAAC,EAAG,QAAO;AACrB,SAAO,UAAU,CAAC,MAAM,UAAU,CAAC;AACrC;AASO,SAAS,UAAU,OAAqB;AAC7C,QAAM,QAAQ,aAAa,KAAK;AAChC,QAAM,QAAQ,QAAQ,OAAO,CAAC,MAAM,OAAO,CAAC;AAC5C,SAAO,MAAM,KAAK,EAAE,QAAQ,GAAG,GAAG,CAAC,GAAG,UAAU,QAAQ,OAAO,KAAK,CAAC;AACvE;AAEO,SAAS,WAAW,OAAa,SAAS,SAAiB;AAChE,SAAO,MAAM,mBAAmB,QAAQ,EAAE,OAAO,QAAQ,MAAM,UAAU,CAAC;AAC5E;AAGO,SAAS,cAAc,OAAe,SAAS,SAAiB;AACrE,QAAM,OAAO,YAAY,KAAK;AAC9B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,KAAK,mBAAmB,QAAQ;AAAA,IACrC,KAAK;AAAA,IACL,OAAO;AAAA,IACP,MAAM;AAAA,EACR,CAAC;AACH;AAEO,SAAS,aAAa,OAAuB;AAClD,QAAM,OAAO,YAAY,KAAK;AAC9B,SAAO,OAAO,KAAK,QAAQ,IAAI;AACjC;AASO,SAAS,WAAW,OAAuB;AAChD,QAAM,OAAO,YAAY,KAAK;AAC9B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,IAAI;AAAA,IACT,KAAK,YAAY;AAAA,IACjB,KAAK,SAAS;AAAA,IACd,KAAK,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,QAAQ;AACZ;AASO,SAAS,YAAY,OAAuB;AACjD,QAAM,OAAO,YAAY,KAAK;AAC9B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,IAAI;AAAA,IACT,KAAK,YAAY;AAAA,IACjB,KAAK,SAAS;AAAA,IACd,KAAK,QAAQ;AAAA,IACb;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,QAAQ;AACZ;AAQO,SAAS,eACd,MACA,IAC0C;AAC1C,QAAM,YAAY,KAAK,KAAK,KAAK,GAAG,KAAK;AACzC,QAAM,UAAU,GAAG,KAAK,KAAK,KAAK,KAAK;AACvC,SAAO;AAAA,IACL,YAAY,aAAa,SAAS;AAAA,IAClC,UAAU,YAAY,OAAO;AAAA,EAC/B;AACF;","names":[]}
|