@inshorts/glint-ui 0.5.4 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/alert.cjs +96 -0
- package/dist/alert.cjs.map +1 -0
- package/dist/alert.d.cts +29 -0
- package/dist/alert.d.ts +29 -0
- package/dist/alert.js +10 -0
- package/dist/alert.js.map +1 -0
- package/dist/autocomplete.cjs +578 -0
- package/dist/autocomplete.cjs.map +1 -0
- package/dist/autocomplete.d.cts +56 -0
- package/dist/autocomplete.d.ts +56 -0
- package/dist/autocomplete.js +11 -0
- package/dist/autocomplete.js.map +1 -0
- package/dist/badge.cjs +89 -0
- package/dist/badge.cjs.map +1 -0
- package/dist/badge.d.cts +25 -0
- package/dist/badge.d.ts +25 -0
- package/dist/badge.js +10 -0
- package/dist/badge.js.map +1 -0
- package/dist/breadcrumb.cjs +88 -0
- package/dist/breadcrumb.cjs.map +1 -0
- package/dist/breadcrumb.d.cts +14 -0
- package/dist/breadcrumb.d.ts +14 -0
- package/dist/breadcrumb.js +8 -0
- package/dist/breadcrumb.js.map +1 -0
- package/dist/button.cjs +143 -0
- package/dist/button.cjs.map +1 -0
- package/dist/button.d.cts +34 -0
- package/dist/button.d.ts +34 -0
- package/dist/button.js +9 -0
- package/dist/button.js.map +1 -0
- package/dist/card.cjs +111 -0
- package/dist/card.cjs.map +1 -0
- package/dist/card.d.cts +15 -0
- package/dist/card.d.ts +15 -0
- package/dist/card.js +18 -0
- package/dist/card.js.map +1 -0
- package/dist/checkbox.cjs +66 -0
- package/dist/checkbox.cjs.map +1 -0
- package/{src/checkbox.tsx → dist/checkbox.d.cts} +5 -22
- package/dist/checkbox.d.ts +25 -0
- package/dist/checkbox.js +10 -0
- package/dist/checkbox.js.map +1 -0
- package/dist/chunk-5MEOZHJA.js +513 -0
- package/dist/chunk-5MEOZHJA.js.map +1 -0
- package/dist/chunk-67ACNS42.js +29 -0
- package/dist/chunk-67ACNS42.js.map +1 -0
- package/dist/chunk-A6GRLKOO.js +85 -0
- package/dist/chunk-A6GRLKOO.js.map +1 -0
- package/dist/chunk-DS3QYIKL.js +90 -0
- package/dist/chunk-DS3QYIKL.js.map +1 -0
- package/dist/chunk-EWSBFU54.js +53 -0
- package/dist/chunk-EWSBFU54.js.map +1 -0
- package/dist/chunk-G4ZQUSAJ.js +38 -0
- package/dist/chunk-G4ZQUSAJ.js.map +1 -0
- package/dist/chunk-GMCUXEFI.js +67 -0
- package/dist/chunk-GMCUXEFI.js.map +1 -0
- package/dist/chunk-HBBOR43A.js +85 -0
- package/dist/chunk-HBBOR43A.js.map +1 -0
- package/dist/chunk-HCA5ODCD.js +11 -0
- package/dist/chunk-HCA5ODCD.js.map +1 -0
- package/dist/chunk-HYRJYUPI.js +26 -0
- package/dist/chunk-HYRJYUPI.js.map +1 -0
- package/dist/chunk-IRCTGJQB.js +26 -0
- package/dist/chunk-IRCTGJQB.js.map +1 -0
- package/dist/chunk-ISPICB4W.js +70 -0
- package/dist/chunk-ISPICB4W.js.map +1 -0
- package/dist/chunk-JDE5XYPT.js +30 -0
- package/dist/chunk-JDE5XYPT.js.map +1 -0
- package/dist/chunk-JSJEEKR3.js +59 -0
- package/dist/chunk-JSJEEKR3.js.map +1 -0
- package/dist/chunk-KR3BCFP7.js +85 -0
- package/dist/chunk-KR3BCFP7.js.map +1 -0
- package/dist/chunk-MLRSOTFI.js +81 -0
- package/dist/chunk-MLRSOTFI.js.map +1 -0
- package/dist/chunk-MQT5RAQV.js +202 -0
- package/dist/chunk-MQT5RAQV.js.map +1 -0
- package/dist/chunk-MUPW2TFJ.js +102 -0
- package/dist/chunk-MUPW2TFJ.js.map +1 -0
- package/dist/chunk-OUYT6SPU.js +76 -0
- package/dist/chunk-OUYT6SPU.js.map +1 -0
- package/dist/chunk-PM2VE7DJ.js +100 -0
- package/dist/chunk-PM2VE7DJ.js.map +1 -0
- package/dist/chunk-PPYR3O3L.js +44 -0
- package/dist/chunk-PPYR3O3L.js.map +1 -0
- package/dist/chunk-PUTC52SI.js +98 -0
- package/dist/chunk-PUTC52SI.js.map +1 -0
- package/dist/chunk-PWAKTEXF.js +18 -0
- package/dist/chunk-PWAKTEXF.js.map +1 -0
- package/dist/chunk-QTFWORA7.js +26 -0
- package/dist/chunk-QTFWORA7.js.map +1 -0
- package/dist/chunk-RUPL2H6V.js +49 -0
- package/dist/chunk-RUPL2H6V.js.map +1 -0
- package/dist/chunk-S7PVZAPL.js +28 -0
- package/dist/chunk-S7PVZAPL.js.map +1 -0
- package/dist/chunk-SQDV2AKJ.js +49 -0
- package/dist/chunk-SQDV2AKJ.js.map +1 -0
- package/dist/chunk-T2KXVH3O.js +297 -0
- package/dist/chunk-T2KXVH3O.js.map +1 -0
- package/dist/chunk-T4WCCHJQ.js +29 -0
- package/dist/chunk-T4WCCHJQ.js.map +1 -0
- package/dist/chunk-UC3ZIQPE.js +93 -0
- package/dist/chunk-UC3ZIQPE.js.map +1 -0
- package/dist/chunk-UE7JY7VR.js +28 -0
- package/dist/chunk-UE7JY7VR.js.map +1 -0
- package/dist/chunk-Y5WCT6XN.js +93 -0
- package/dist/chunk-Y5WCT6XN.js.map +1 -0
- package/dist/chunk-YDICVETX.js +151 -0
- package/dist/chunk-YDICVETX.js.map +1 -0
- package/dist/chunk-ZFSQVMLJ.js +126 -0
- package/dist/chunk-ZFSQVMLJ.js.map +1 -0
- package/dist/chunk-ZHATD73Y.js +46 -0
- package/dist/chunk-ZHATD73Y.js.map +1 -0
- package/dist/chunk-ZLAA4DGG.js +111 -0
- package/dist/chunk-ZLAA4DGG.js.map +1 -0
- package/dist/chunk-ZP252OJZ.js +56 -0
- package/dist/chunk-ZP252OJZ.js.map +1 -0
- package/dist/clipboard.cjs +125 -0
- package/dist/clipboard.cjs.map +1 -0
- package/dist/clipboard.d.cts +52 -0
- package/dist/clipboard.d.ts +52 -0
- package/dist/clipboard.js +23 -0
- package/dist/clipboard.js.map +1 -0
- package/dist/collapsible.cjs +94 -0
- package/dist/collapsible.cjs.map +1 -0
- package/dist/collapsible.d.cts +21 -0
- package/dist/collapsible.d.ts +21 -0
- package/dist/collapsible.js +9 -0
- package/dist/collapsible.js.map +1 -0
- package/dist/confirm-dialog.cjs +369 -0
- package/dist/confirm-dialog.cjs.map +1 -0
- package/dist/confirm-dialog.d.cts +16 -0
- package/dist/confirm-dialog.d.ts +16 -0
- package/dist/confirm-dialog.js +13 -0
- package/dist/confirm-dialog.js.map +1 -0
- package/dist/copy-button.cjs +102 -0
- package/dist/copy-button.cjs.map +1 -0
- package/dist/copy-button.d.cts +18 -0
- package/dist/copy-button.d.ts +18 -0
- package/dist/copy-button.js +10 -0
- package/dist/copy-button.js.map +1 -0
- package/dist/data-table.cjs +140 -0
- package/dist/data-table.cjs.map +1 -0
- package/dist/data-table.d.cts +81 -0
- package/dist/data-table.d.ts +81 -0
- package/dist/data-table.js +8 -0
- package/dist/data-table.js.map +1 -0
- package/dist/date-range-picker/dateRange.cjs +138 -0
- package/dist/date-range-picker/dateRange.cjs.map +1 -0
- package/dist/date-range-picker/dateRange.d.cts +57 -0
- package/dist/date-range-picker/dateRange.d.ts +57 -0
- package/dist/date-range-picker/dateRange.js +31 -0
- package/dist/date-range-picker/dateRange.js.map +1 -0
- package/dist/date-range-picker/index.cjs +375 -0
- package/dist/date-range-picker/index.cjs.map +1 -0
- package/dist/date-range-picker/index.d.cts +18 -0
- package/dist/date-range-picker/index.d.ts +18 -0
- package/dist/date-range-picker/index.js +10 -0
- package/dist/date-range-picker/index.js.map +1 -0
- package/dist/dialogLayer.cjs +121 -0
- package/dist/dialogLayer.cjs.map +1 -0
- package/dist/dialogLayer.d.cts +11 -0
- package/dist/dialogLayer.d.ts +11 -0
- package/dist/dialogLayer.js +8 -0
- package/dist/dialogLayer.js.map +1 -0
- package/dist/feature-access-gate.cjs +160 -0
- package/dist/feature-access-gate.cjs.map +1 -0
- package/dist/feature-access-gate.d.cts +14 -0
- package/dist/feature-access-gate.d.ts +14 -0
- package/dist/feature-access-gate.js +11 -0
- package/dist/feature-access-gate.js.map +1 -0
- package/dist/field.cjs +58 -0
- package/dist/field.cjs.map +1 -0
- package/dist/field.d.cts +23 -0
- package/dist/field.d.ts +23 -0
- package/dist/field.js +8 -0
- package/dist/field.js.map +1 -0
- package/dist/image-uploader.cjs +293 -0
- package/dist/image-uploader.cjs.map +1 -0
- package/dist/image-uploader.d.cts +34 -0
- package/dist/image-uploader.d.ts +34 -0
- package/dist/image-uploader.js +12 -0
- package/dist/image-uploader.js.map +1 -0
- package/dist/index.cjs +3008 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +41 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +232 -0
- package/dist/index.js.map +1 -0
- package/dist/input.cjs +58 -0
- package/dist/input.cjs.map +1 -0
- package/dist/input.d.cts +7 -0
- package/dist/input.d.ts +7 -0
- package/dist/input.js +10 -0
- package/dist/input.js.map +1 -0
- package/dist/label.cjs +67 -0
- package/dist/label.cjs.map +1 -0
- package/dist/label.d.cts +7 -0
- package/dist/label.d.ts +7 -0
- package/dist/label.js +9 -0
- package/dist/label.js.map +1 -0
- package/dist/modal.cjs +212 -0
- package/dist/modal.cjs.map +1 -0
- package/dist/modal.d.cts +39 -0
- package/dist/modal.d.ts +39 -0
- package/dist/modal.js +12 -0
- package/dist/modal.js.map +1 -0
- package/dist/page-header.cjs +78 -0
- package/dist/page-header.cjs.map +1 -0
- package/dist/page-header.d.cts +35 -0
- package/dist/page-header.d.ts +35 -0
- package/dist/page-header.js +8 -0
- package/dist/page-header.js.map +1 -0
- package/dist/pagination.cjs +237 -0
- package/dist/pagination.cjs.map +1 -0
- package/dist/pagination.d.cts +15 -0
- package/dist/pagination.d.ts +15 -0
- package/dist/pagination.js +11 -0
- package/dist/pagination.js.map +1 -0
- package/dist/panel-brand-mark.cjs +59 -0
- package/dist/panel-brand-mark.cjs.map +1 -0
- package/dist/panel-brand-mark.d.cts +13 -0
- package/dist/panel-brand-mark.d.ts +13 -0
- package/dist/panel-brand-mark.js +8 -0
- package/dist/panel-brand-mark.js.map +1 -0
- package/dist/panel-sign-in.cjs +256 -0
- package/dist/panel-sign-in.cjs.map +1 -0
- package/dist/panel-sign-in.d.cts +31 -0
- package/dist/panel-sign-in.d.ts +31 -0
- package/dist/panel-sign-in.js +14 -0
- package/dist/panel-sign-in.js.map +1 -0
- package/dist/segmented-control.cjs +122 -0
- package/dist/segmented-control.cjs.map +1 -0
- package/dist/segmented-control.d.cts +58 -0
- package/dist/segmented-control.d.ts +58 -0
- package/dist/segmented-control.js +9 -0
- package/dist/segmented-control.js.map +1 -0
- package/dist/select.cjs +648 -0
- package/dist/select.cjs.map +1 -0
- package/dist/select.d.cts +30 -0
- package/dist/select.d.ts +30 -0
- package/dist/select.js +12 -0
- package/dist/select.js.map +1 -0
- package/dist/separator.cjs +70 -0
- package/dist/separator.cjs.map +1 -0
- package/dist/separator.d.cts +13 -0
- package/dist/separator.d.ts +13 -0
- package/dist/separator.js +9 -0
- package/dist/separator.js.map +1 -0
- package/dist/side-drawer.cjs +321 -0
- package/dist/side-drawer.cjs.map +1 -0
- package/dist/side-drawer.d.cts +21 -0
- package/dist/side-drawer.d.ts +21 -0
- package/dist/side-drawer.js +13 -0
- package/dist/side-drawer.js.map +1 -0
- package/dist/spinner.cjs +57 -0
- package/dist/spinner.cjs.map +1 -0
- package/{src/spinner.tsx → dist/spinner.d.cts} +11 -22
- package/dist/spinner.d.ts +27 -0
- package/dist/spinner.js +8 -0
- package/dist/spinner.js.map +1 -0
- package/dist/spreadsheet-grid.cjs +238 -0
- package/dist/spreadsheet-grid.cjs.map +1 -0
- package/dist/spreadsheet-grid.d.cts +48 -0
- package/dist/spreadsheet-grid.d.ts +48 -0
- package/dist/spreadsheet-grid.js +8 -0
- package/dist/spreadsheet-grid.js.map +1 -0
- package/dist/state-panel.cjs +86 -0
- package/dist/state-panel.cjs.map +1 -0
- package/dist/state-panel.d.cts +23 -0
- package/dist/state-panel.d.ts +23 -0
- package/dist/state-panel.js +9 -0
- package/dist/state-panel.js.map +1 -0
- package/dist/switch.cjs +87 -0
- package/dist/switch.cjs.map +1 -0
- package/dist/switch.d.cts +13 -0
- package/dist/switch.d.ts +13 -0
- package/dist/switch.js +9 -0
- package/dist/switch.js.map +1 -0
- package/dist/table.cjs +139 -0
- package/dist/table.cjs.map +1 -0
- package/dist/table.d.cts +16 -0
- package/dist/table.d.ts +16 -0
- package/dist/table.js +22 -0
- package/dist/table.js.map +1 -0
- package/dist/tabs.cjs +168 -0
- package/dist/tabs.cjs.map +1 -0
- package/dist/tabs.d.cts +59 -0
- package/dist/tabs.d.ts +59 -0
- package/dist/tabs.js +11 -0
- package/dist/tabs.js.map +1 -0
- package/dist/textarea.cjs +66 -0
- package/dist/textarea.cjs.map +1 -0
- package/dist/textarea.d.cts +18 -0
- package/dist/textarea.d.ts +18 -0
- package/dist/textarea.js +10 -0
- package/dist/textarea.js.map +1 -0
- package/dist/utils.cjs +35 -0
- package/dist/utils.cjs.map +1 -0
- package/dist/utils.d.cts +5 -0
- package/dist/utils.d.ts +5 -0
- package/dist/utils.js +7 -0
- package/dist/utils.js.map +1 -0
- package/package.json +391 -14
- package/src/alert.tsx +0 -74
- package/src/autocomplete.tsx +0 -666
- package/src/badge.tsx +0 -60
- package/src/breadcrumb.tsx +0 -71
- package/src/button.tsx +0 -113
- package/src/card.tsx +0 -79
- package/src/clipboard.ts +0 -144
- package/src/collapsible.tsx +0 -63
- package/src/confirm-dialog.tsx +0 -84
- package/src/copy-button.tsx +0 -58
- package/src/data-table.tsx +0 -190
- package/src/date-range-picker/dateRange.ts +0 -142
- package/src/date-range-picker/index.tsx +0 -366
- package/src/dialogLayer.ts +0 -142
- package/src/feature-access-gate.tsx +0 -38
- package/src/field.tsx +0 -56
- package/src/image-uploader.tsx +0 -181
- package/src/index.ts +0 -37
- package/src/input.tsx +0 -16
- package/src/label.tsx +0 -23
- package/src/modal.tsx +0 -117
- package/src/page-header.tsx +0 -75
- package/src/pagination.tsx +0 -116
- package/src/panel-brand-mark.tsx +0 -32
- package/src/panel-sign-in.tsx +0 -134
- package/src/segmented-control.tsx +0 -155
- package/src/select.tsx +0 -105
- package/src/separator.tsx +0 -32
- package/src/side-drawer.tsx +0 -87
- package/src/spreadsheet-grid.tsx +0 -264
- package/src/state-panel.tsx +0 -46
- package/src/switch.tsx +0 -47
- package/src/table.tsx +0 -110
- package/src/tabs.tsx +0 -201
- package/src/textarea.tsx +0 -32
- package/src/utils.ts +0 -6
|
@@ -0,0 +1,375 @@
|
|
|
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/date-range-picker/index.tsx
|
|
33
|
+
var date_range_picker_exports = {};
|
|
34
|
+
__export(date_range_picker_exports, {
|
|
35
|
+
DateRangePicker: () => DateRangePicker
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(date_range_picker_exports);
|
|
38
|
+
var import_lucide_react = require("lucide-react");
|
|
39
|
+
var React = __toESM(require("react"), 1);
|
|
40
|
+
|
|
41
|
+
// src/utils.ts
|
|
42
|
+
var import_clsx = require("clsx");
|
|
43
|
+
var import_tailwind_merge = require("tailwind-merge");
|
|
44
|
+
function cn(...inputs) {
|
|
45
|
+
return (0, import_tailwind_merge.twMerge)((0, import_clsx.clsx)(inputs));
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/date-range-picker/dateRange.ts
|
|
49
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
50
|
+
function toIsoDate(date) {
|
|
51
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
52
|
+
}
|
|
53
|
+
function fromIsoDate(value) {
|
|
54
|
+
if (!value) return null;
|
|
55
|
+
const trimmed = value.trim();
|
|
56
|
+
const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(trimmed);
|
|
57
|
+
if (!match) return null;
|
|
58
|
+
const date = new Date(
|
|
59
|
+
Number(match[1]),
|
|
60
|
+
Number(match[2]) - 1,
|
|
61
|
+
Number(match[3])
|
|
62
|
+
);
|
|
63
|
+
return toIsoDate(date) === trimmed ? date : null;
|
|
64
|
+
}
|
|
65
|
+
function startOfMonth(date) {
|
|
66
|
+
return new Date(date.getFullYear(), date.getMonth(), 1);
|
|
67
|
+
}
|
|
68
|
+
function addMonths(date, count) {
|
|
69
|
+
return new Date(date.getFullYear(), date.getMonth() + count, 1);
|
|
70
|
+
}
|
|
71
|
+
function addDays(date, count) {
|
|
72
|
+
return new Date(date.getFullYear(), date.getMonth(), date.getDate() + count);
|
|
73
|
+
}
|
|
74
|
+
function isSameDay(a, b) {
|
|
75
|
+
if (!a || !b) return false;
|
|
76
|
+
return toIsoDate(a) === toIsoDate(b);
|
|
77
|
+
}
|
|
78
|
+
function monthGrid(month) {
|
|
79
|
+
const first = startOfMonth(month);
|
|
80
|
+
const start = addDays(first, -first.getDay());
|
|
81
|
+
return Array.from({ length: 42 }, (_, index) => addDays(start, index));
|
|
82
|
+
}
|
|
83
|
+
function monthLabel(month, locale = "en-IN") {
|
|
84
|
+
return month.toLocaleDateString(locale, { month: "long", year: "numeric" });
|
|
85
|
+
}
|
|
86
|
+
function formatDisplay(value, locale = "en-IN") {
|
|
87
|
+
const date = fromIsoDate(value);
|
|
88
|
+
if (!date) return "";
|
|
89
|
+
return date.toLocaleDateString(locale, {
|
|
90
|
+
day: "numeric",
|
|
91
|
+
month: "short",
|
|
92
|
+
year: "numeric"
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// src/date-range-picker/index.tsx
|
|
97
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
98
|
+
var PRESETS = [
|
|
99
|
+
{
|
|
100
|
+
label: "Today",
|
|
101
|
+
range: () => {
|
|
102
|
+
const today = toIsoDate(/* @__PURE__ */ new Date());
|
|
103
|
+
return { from: today, to: today };
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
label: "Yesterday",
|
|
108
|
+
range: () => {
|
|
109
|
+
const day = toIsoDate(addDays(/* @__PURE__ */ new Date(), -1));
|
|
110
|
+
return { from: day, to: day };
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
label: "Last 7 days",
|
|
115
|
+
range: () => ({
|
|
116
|
+
from: toIsoDate(addDays(/* @__PURE__ */ new Date(), -6)),
|
|
117
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
118
|
+
})
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
label: "Last 30 days",
|
|
122
|
+
range: () => ({
|
|
123
|
+
from: toIsoDate(addDays(/* @__PURE__ */ new Date(), -29)),
|
|
124
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
125
|
+
})
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
label: "This month",
|
|
129
|
+
range: () => ({
|
|
130
|
+
from: toIsoDate(startOfMonth(/* @__PURE__ */ new Date())),
|
|
131
|
+
to: toIsoDate(/* @__PURE__ */ new Date())
|
|
132
|
+
})
|
|
133
|
+
}
|
|
134
|
+
];
|
|
135
|
+
var WEEKDAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
136
|
+
function DateRangePicker({
|
|
137
|
+
value,
|
|
138
|
+
onChange,
|
|
139
|
+
disabled,
|
|
140
|
+
placeholder = "Any date",
|
|
141
|
+
className,
|
|
142
|
+
ariaLabel = "Date range"
|
|
143
|
+
}) {
|
|
144
|
+
const [open, setOpen] = React.useState(false);
|
|
145
|
+
const [hovered, setHovered] = React.useState(null);
|
|
146
|
+
const [pendingFrom, setPendingFrom] = React.useState(null);
|
|
147
|
+
const rootRef = React.useRef(null);
|
|
148
|
+
const from = fromIsoDate(value.from);
|
|
149
|
+
const to = fromIsoDate(value.to);
|
|
150
|
+
const [viewMonth, setViewMonth] = React.useState(
|
|
151
|
+
() => startOfMonth(from ?? /* @__PURE__ */ new Date())
|
|
152
|
+
);
|
|
153
|
+
React.useEffect(() => {
|
|
154
|
+
if (!open) return void 0;
|
|
155
|
+
const onPointerDown = (event) => {
|
|
156
|
+
if (!rootRef.current?.contains(event.target)) setOpen(false);
|
|
157
|
+
};
|
|
158
|
+
const onKeyDown = (event) => {
|
|
159
|
+
if (event.key === "Escape") setOpen(false);
|
|
160
|
+
};
|
|
161
|
+
document.addEventListener("mousedown", onPointerDown);
|
|
162
|
+
document.addEventListener("keydown", onKeyDown);
|
|
163
|
+
return () => {
|
|
164
|
+
document.removeEventListener("mousedown", onPointerDown);
|
|
165
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
166
|
+
};
|
|
167
|
+
}, [open]);
|
|
168
|
+
function openPicker() {
|
|
169
|
+
setViewMonth(startOfMonth(fromIsoDate(value.from) ?? /* @__PURE__ */ new Date()));
|
|
170
|
+
setPendingFrom(null);
|
|
171
|
+
setHovered(null);
|
|
172
|
+
setOpen(true);
|
|
173
|
+
}
|
|
174
|
+
const anchor = pendingFrom ?? (to ? null : from);
|
|
175
|
+
const previewEnd = pendingFrom ? hovered : null;
|
|
176
|
+
function rangeBounds() {
|
|
177
|
+
if (pendingFrom) {
|
|
178
|
+
if (!previewEnd) return [pendingFrom, pendingFrom];
|
|
179
|
+
return previewEnd.getTime() < pendingFrom.getTime() ? [previewEnd, pendingFrom] : [pendingFrom, previewEnd];
|
|
180
|
+
}
|
|
181
|
+
return [from, to];
|
|
182
|
+
}
|
|
183
|
+
const [rangeStart, rangeEnd] = rangeBounds();
|
|
184
|
+
function selectDay(day) {
|
|
185
|
+
if (!anchor) {
|
|
186
|
+
setPendingFrom(day);
|
|
187
|
+
onChange({ from: toIsoDate(day), to: "" });
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
const [start, end] = day.getTime() < anchor.getTime() ? [day, anchor] : [anchor, day];
|
|
191
|
+
onChange({ from: toIsoDate(start), to: toIsoDate(end) });
|
|
192
|
+
setPendingFrom(null);
|
|
193
|
+
setHovered(null);
|
|
194
|
+
setOpen(false);
|
|
195
|
+
}
|
|
196
|
+
function onGridKeyDown(event) {
|
|
197
|
+
const offsets = {
|
|
198
|
+
ArrowLeft: -1,
|
|
199
|
+
ArrowRight: 1,
|
|
200
|
+
ArrowUp: -7,
|
|
201
|
+
ArrowDown: 7
|
|
202
|
+
};
|
|
203
|
+
const offset = offsets[event.key];
|
|
204
|
+
if (offset === void 0) return;
|
|
205
|
+
const focused = document.activeElement;
|
|
206
|
+
const iso = focused?.dataset?.day;
|
|
207
|
+
const current = fromIsoDate(iso);
|
|
208
|
+
if (!current) return;
|
|
209
|
+
event.preventDefault();
|
|
210
|
+
const next = addDays(current, offset);
|
|
211
|
+
const nextIso = toIsoDate(next);
|
|
212
|
+
if (!rootRef.current?.querySelector(`[data-day="${nextIso}"]`)) {
|
|
213
|
+
setViewMonth(startOfMonth(offset < 0 ? next : addMonths(next, -1)));
|
|
214
|
+
}
|
|
215
|
+
window.requestAnimationFrame(() => {
|
|
216
|
+
rootRef.current?.querySelector(`[data-day="${nextIso}"]`)?.focus();
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
const label = value.from || value.to ? `${formatDisplay(value.from) || "Any"} \u2192 ${formatDisplay(value.to) || "Any"}` : placeholder;
|
|
220
|
+
const today = /* @__PURE__ */ new Date();
|
|
221
|
+
function renderMonth(month) {
|
|
222
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "w-[15.75rem] shrink-0", children: [
|
|
223
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-foreground mb-2 text-center text-sm font-medium whitespace-nowrap", children: monthLabel(month) }),
|
|
224
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "text-muted-foreground grid grid-cols-7 text-center text-[11px]", children: WEEKDAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid size-9 place-items-center", children: day }, day)) }),
|
|
225
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-7", children: monthGrid(month).map((day) => {
|
|
226
|
+
const iso = toIsoDate(day);
|
|
227
|
+
const outside = day.getMonth() !== month.getMonth();
|
|
228
|
+
const isStart = isSameDay(day, rangeStart);
|
|
229
|
+
const isEnd = isSameDay(day, rangeEnd);
|
|
230
|
+
const inRange = rangeStart != null && rangeEnd != null && day.getTime() > rangeStart.getTime() && day.getTime() < rangeEnd.getTime();
|
|
231
|
+
const isToday = isSameDay(day, today);
|
|
232
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
233
|
+
"button",
|
|
234
|
+
{
|
|
235
|
+
type: "button",
|
|
236
|
+
"data-day": iso,
|
|
237
|
+
onClick: () => selectDay(day),
|
|
238
|
+
onMouseEnter: () => setHovered(day),
|
|
239
|
+
"aria-label": day.toDateString(),
|
|
240
|
+
"aria-pressed": isStart || isEnd,
|
|
241
|
+
className: cn(
|
|
242
|
+
"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",
|
|
243
|
+
outside ? "text-muted-foreground/50" : "text-foreground",
|
|
244
|
+
inRange && "bg-primary/10 rounded-none",
|
|
245
|
+
(isStart || isEnd) && "bg-primary text-primary-foreground font-medium",
|
|
246
|
+
// Square off the inner edge so a range reads as one bar
|
|
247
|
+
// rather than two pills with a gap.
|
|
248
|
+
isStart && rangeEnd && !isEnd && "rounded-r-none",
|
|
249
|
+
isEnd && rangeStart && !isStart && "rounded-l-none",
|
|
250
|
+
!isStart && !isEnd && "hover:bg-muted",
|
|
251
|
+
isToday && !isStart && !isEnd && "ring-border font-semibold ring-1"
|
|
252
|
+
),
|
|
253
|
+
children: day.getDate()
|
|
254
|
+
},
|
|
255
|
+
iso
|
|
256
|
+
);
|
|
257
|
+
}) })
|
|
258
|
+
] }, monthLabel(month));
|
|
259
|
+
}
|
|
260
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { ref: rootRef, className: cn("relative", className), children: [
|
|
261
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
262
|
+
"div",
|
|
263
|
+
{
|
|
264
|
+
className: cn(
|
|
265
|
+
"border-border bg-background flex items-center rounded-md border",
|
|
266
|
+
"focus-within:ring-ring/50 focus-within:border-ring focus-within:ring-2",
|
|
267
|
+
disabled && "opacity-50"
|
|
268
|
+
),
|
|
269
|
+
children: [
|
|
270
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
271
|
+
"button",
|
|
272
|
+
{
|
|
273
|
+
type: "button",
|
|
274
|
+
disabled,
|
|
275
|
+
"aria-haspopup": "dialog",
|
|
276
|
+
"aria-expanded": open,
|
|
277
|
+
"aria-label": ariaLabel,
|
|
278
|
+
onClick: () => open ? setOpen(false) : openPicker(),
|
|
279
|
+
className: "flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5 text-left text-sm",
|
|
280
|
+
children: [
|
|
281
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
282
|
+
import_lucide_react.CalendarDays,
|
|
283
|
+
{
|
|
284
|
+
className: "text-muted-foreground size-4 shrink-0",
|
|
285
|
+
"aria-hidden": true
|
|
286
|
+
}
|
|
287
|
+
),
|
|
288
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
289
|
+
"span",
|
|
290
|
+
{
|
|
291
|
+
className: cn(
|
|
292
|
+
"truncate",
|
|
293
|
+
!value.from && !value.to && "text-muted-foreground"
|
|
294
|
+
),
|
|
295
|
+
children: label
|
|
296
|
+
}
|
|
297
|
+
)
|
|
298
|
+
]
|
|
299
|
+
}
|
|
300
|
+
),
|
|
301
|
+
(value.from || value.to) && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
302
|
+
"button",
|
|
303
|
+
{
|
|
304
|
+
type: "button",
|
|
305
|
+
"aria-label": "Clear date range",
|
|
306
|
+
onClick: () => {
|
|
307
|
+
onChange({ from: "", to: "" });
|
|
308
|
+
setPendingFrom(null);
|
|
309
|
+
},
|
|
310
|
+
className: "text-muted-foreground hover:text-foreground shrink-0 px-2",
|
|
311
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.X, { className: "size-3.5", "aria-hidden": true })
|
|
312
|
+
}
|
|
313
|
+
) : null
|
|
314
|
+
]
|
|
315
|
+
}
|
|
316
|
+
),
|
|
317
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
318
|
+
"div",
|
|
319
|
+
{
|
|
320
|
+
role: "dialog",
|
|
321
|
+
"aria-label": ariaLabel,
|
|
322
|
+
className: "border-border bg-background absolute top-full right-0 z-50 mt-1 flex w-max rounded-lg border p-3 shadow-lg",
|
|
323
|
+
children: [
|
|
324
|
+
/* @__PURE__ */ (0, import_jsx_runtime.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_runtime.jsx)(
|
|
325
|
+
"button",
|
|
326
|
+
{
|
|
327
|
+
type: "button",
|
|
328
|
+
className: "hover:bg-muted text-foreground rounded-md px-2 py-1.5 text-left text-xs",
|
|
329
|
+
onClick: () => {
|
|
330
|
+
onChange(preset.range());
|
|
331
|
+
setPendingFrom(null);
|
|
332
|
+
setOpen(false);
|
|
333
|
+
},
|
|
334
|
+
children: preset.label
|
|
335
|
+
},
|
|
336
|
+
preset.label
|
|
337
|
+
)) }),
|
|
338
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { onKeyDown: onGridKeyDown, children: [
|
|
339
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-2 flex items-center justify-between", children: [
|
|
340
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
341
|
+
"button",
|
|
342
|
+
{
|
|
343
|
+
type: "button",
|
|
344
|
+
"aria-label": "Previous month",
|
|
345
|
+
className: "hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5",
|
|
346
|
+
onClick: () => setViewMonth(addMonths(viewMonth, -1)),
|
|
347
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronLeft, { className: "size-4", "aria-hidden": true })
|
|
348
|
+
}
|
|
349
|
+
),
|
|
350
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
351
|
+
"button",
|
|
352
|
+
{
|
|
353
|
+
type: "button",
|
|
354
|
+
"aria-label": "Next month",
|
|
355
|
+
className: "hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5",
|
|
356
|
+
onClick: () => setViewMonth(addMonths(viewMonth, 1)),
|
|
357
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.ChevronRight, { className: "size-4", "aria-hidden": true })
|
|
358
|
+
}
|
|
359
|
+
)
|
|
360
|
+
] }),
|
|
361
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "flex gap-5", onMouseLeave: () => setHovered(null), children: [
|
|
362
|
+
renderMonth(viewMonth),
|
|
363
|
+
renderMonth(addMonths(viewMonth, 1))
|
|
364
|
+
] })
|
|
365
|
+
] })
|
|
366
|
+
]
|
|
367
|
+
}
|
|
368
|
+
) : null
|
|
369
|
+
] });
|
|
370
|
+
}
|
|
371
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
372
|
+
0 && (module.exports = {
|
|
373
|
+
DateRangePicker
|
|
374
|
+
});
|
|
375
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/date-range-picker/index.tsx","../../src/utils.ts","../../src/date-range-picker/dateRange.ts"],"sourcesContent":["\"use client\";\n\nimport { CalendarDays, ChevronLeft, ChevronRight, X } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { cn } from \"../utils\";\nimport {\n addDays,\n addMonths,\n formatDisplay,\n fromIsoDate,\n isSameDay,\n monthGrid,\n monthLabel,\n startOfMonth,\n toIsoDate,\n} from \"./dateRange\";\n\nexport type DateRangeValue = { from: string; to: string };\n\n/**\n * A two-month range calendar.\n *\n * Two separate date fields cost two columns and read as two unrelated\n * questions when they are one: which window. They also let the pair be set\n * backwards, which returns nothing and looks like a broken filter.\n *\n * Two months rather than one because almost every range anyone picks here\n * crosses a month boundary — \"last week of July into the first of August\" is a\n * single gesture with two months visible and a paging exercise with one.\n *\n * Presets are the useful half. The common ranges are the same handful every\n * time, and picking \"Last 7 days\" out of a list beats counting backwards on a\n * grid.\n */\nconst PRESETS: { label: string; range: () => DateRangeValue }[] = [\n {\n label: \"Today\",\n range: () => {\n const today = toIsoDate(new Date());\n return { from: today, to: today };\n },\n },\n {\n label: \"Yesterday\",\n range: () => {\n const day = toIsoDate(addDays(new Date(), -1));\n return { from: day, to: day };\n },\n },\n {\n label: \"Last 7 days\",\n range: () => ({\n from: toIsoDate(addDays(new Date(), -6)),\n to: toIsoDate(new Date()),\n }),\n },\n {\n label: \"Last 30 days\",\n range: () => ({\n from: toIsoDate(addDays(new Date(), -29)),\n to: toIsoDate(new Date()),\n }),\n },\n {\n label: \"This month\",\n range: () => ({\n from: toIsoDate(startOfMonth(new Date())),\n to: toIsoDate(new Date()),\n }),\n },\n];\n\nconst WEEKDAYS = [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"];\n\nexport interface DateRangePickerProps {\n value: DateRangeValue;\n onChange: (next: DateRangeValue) => void;\n disabled?: boolean;\n placeholder?: string;\n className?: string;\n /** Names the trigger for screen readers when there is no visible label. */\n ariaLabel?: string;\n}\n\nexport function DateRangePicker({\n value,\n onChange,\n disabled,\n placeholder = \"Any date\",\n className,\n ariaLabel = \"Date range\",\n}: DateRangePickerProps) {\n const [open, setOpen] = React.useState(false);\n const [hovered, setHovered] = React.useState<Date | null>(null);\n /** Set while choosing the second end, so the range can preview under the cursor. */\n const [pendingFrom, setPendingFrom] = React.useState<Date | null>(null);\n const rootRef = React.useRef<HTMLDivElement>(null);\n\n const from = fromIsoDate(value.from);\n const to = fromIsoDate(value.to);\n\n const [viewMonth, setViewMonth] = React.useState<Date>(() =>\n startOfMonth(from ?? new Date()),\n );\n\n React.useEffect(() => {\n if (!open) return undefined;\n const onPointerDown = (event: MouseEvent) => {\n if (!rootRef.current?.contains(event.target as Node)) setOpen(false);\n };\n const onKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\") setOpen(false);\n };\n document.addEventListener(\"mousedown\", onPointerDown);\n document.addEventListener(\"keydown\", onKeyDown);\n return () => {\n document.removeEventListener(\"mousedown\", onPointerDown);\n document.removeEventListener(\"keydown\", onKeyDown);\n };\n }, [open]);\n\n /**\n * Reopening lands on the current selection rather than wherever the view was\n * left. Done here rather than in an effect: it is a response to an event, and\n * setting state from an effect is what `react-hooks/set-state-in-effect`\n * rejects — correctly, since it costs an extra render every open.\n */\n function openPicker() {\n setViewMonth(startOfMonth(fromIsoDate(value.from) ?? new Date()));\n setPendingFrom(null);\n setHovered(null);\n setOpen(true);\n }\n\n const anchor = pendingFrom ?? (to ? null : from);\n const previewEnd = pendingFrom ? hovered : null;\n\n function rangeBounds(): [Date | null, Date | null] {\n if (pendingFrom) {\n if (!previewEnd) return [pendingFrom, pendingFrom];\n return previewEnd.getTime() < pendingFrom.getTime()\n ? [previewEnd, pendingFrom]\n : [pendingFrom, previewEnd];\n }\n return [from, to];\n }\n\n const [rangeStart, rangeEnd] = rangeBounds();\n\n function selectDay(day: Date) {\n if (!anchor) {\n // Starting a new range. Keeping only `from` means the next click closes\n // it, whichever side of the anchor it lands on.\n setPendingFrom(day);\n onChange({ from: toIsoDate(day), to: \"\" });\n return;\n }\n const [start, end] =\n day.getTime() < anchor.getTime() ? [day, anchor] : [anchor, day];\n onChange({ from: toIsoDate(start), to: toIsoDate(end) });\n setPendingFrom(null);\n setHovered(null);\n setOpen(false);\n }\n\n /** Arrow keys move by day/week across both months, as a calendar should. */\n function onGridKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {\n const offsets: Record<string, number> = {\n ArrowLeft: -1,\n ArrowRight: 1,\n ArrowUp: -7,\n ArrowDown: 7,\n };\n const offset = offsets[event.key];\n if (offset === undefined) return;\n const focused = document.activeElement as HTMLElement | null;\n const iso = focused?.dataset?.day;\n const current = fromIsoDate(iso);\n if (!current) return;\n event.preventDefault();\n const next = addDays(current, offset);\n const nextIso = toIsoDate(next);\n // Page the view when the move lands outside what is rendered.\n if (!rootRef.current?.querySelector(`[data-day=\"${nextIso}\"]`)) {\n setViewMonth(startOfMonth(offset < 0 ? next : addMonths(next, -1)));\n }\n window.requestAnimationFrame(() => {\n rootRef.current\n ?.querySelector<HTMLElement>(`[data-day=\"${nextIso}\"]`)\n ?.focus();\n });\n }\n\n const label =\n value.from || value.to\n ? `${formatDisplay(value.from) || \"Any\"} → ${formatDisplay(value.to) || \"Any\"}`\n : placeholder;\n\n const today = new Date();\n\n function renderMonth(month: Date) {\n return (\n <div key={monthLabel(month)} className=\"w-[15.75rem] shrink-0\">\n <div className=\"text-foreground mb-2 text-center text-sm font-medium whitespace-nowrap\">\n {monthLabel(month)}\n </div>\n <div className=\"text-muted-foreground grid grid-cols-7 text-center text-[11px]\">\n {WEEKDAYS.map((day) => (\n <div key={day} className=\"grid size-9 place-items-center\">\n {day}\n </div>\n ))}\n </div>\n <div className=\"grid grid-cols-7\">\n {monthGrid(month).map((day) => {\n const iso = toIsoDate(day);\n const outside = day.getMonth() !== month.getMonth();\n const isStart = isSameDay(day, rangeStart);\n const isEnd = isSameDay(day, rangeEnd);\n const inRange =\n rangeStart != null &&\n rangeEnd != null &&\n day.getTime() > rangeStart.getTime() &&\n day.getTime() < rangeEnd.getTime();\n const isToday = isSameDay(day, today);\n\n return (\n <button\n key={iso}\n type=\"button\"\n data-day={iso}\n // Outside days stay clickable — clicking one is how you reach\n // the neighbouring month without paging.\n onClick={() => selectDay(day)}\n onMouseEnter={() => setHovered(day)}\n aria-label={day.toDateString()}\n aria-pressed={isStart || isEnd}\n className={cn(\n \"focus-visible:ring-ring relative grid size-9 place-items-center rounded-md text-sm transition-colors focus-visible:ring-2 focus-visible:outline-none\",\n outside ? \"text-muted-foreground/50\" : \"text-foreground\",\n inRange && \"bg-primary/10 rounded-none\",\n (isStart || isEnd) &&\n \"bg-primary text-primary-foreground font-medium\",\n // Square off the inner edge so a range reads as one bar\n // rather than two pills with a gap.\n isStart && rangeEnd && !isEnd && \"rounded-r-none\",\n isEnd && rangeStart && !isStart && \"rounded-l-none\",\n !isStart && !isEnd && \"hover:bg-muted\",\n isToday &&\n !isStart &&\n !isEnd &&\n \"ring-border font-semibold ring-1\",\n )}\n >\n {day.getDate()}\n </button>\n );\n })}\n </div>\n </div>\n );\n }\n\n return (\n <div ref={rootRef} className={cn(\"relative\", className)}>\n <div\n className={cn(\n \"border-border bg-background flex items-center rounded-md border\",\n \"focus-within:ring-ring/50 focus-within:border-ring focus-within:ring-2\",\n disabled && \"opacity-50\",\n )}\n >\n <button\n type=\"button\"\n disabled={disabled}\n aria-haspopup=\"dialog\"\n aria-expanded={open}\n aria-label={ariaLabel}\n onClick={() => (open ? setOpen(false) : openPicker())}\n className=\"flex min-w-0 flex-1 items-center gap-2 px-2 py-1.5 text-left text-sm\"\n >\n <CalendarDays\n className=\"text-muted-foreground size-4 shrink-0\"\n aria-hidden\n />\n <span\n className={cn(\n \"truncate\",\n !value.from && !value.to && \"text-muted-foreground\",\n )}\n >\n {label}\n </span>\n </button>\n {(value.from || value.to) && !disabled ? (\n <button\n type=\"button\"\n aria-label=\"Clear date range\"\n onClick={() => {\n onChange({ from: \"\", to: \"\" });\n setPendingFrom(null);\n }}\n className=\"text-muted-foreground hover:text-foreground shrink-0 px-2\"\n >\n <X className=\"size-3.5\" aria-hidden />\n </button>\n ) : null}\n </div>\n\n {open ? (\n <div\n role=\"dialog\"\n aria-label={ariaLabel}\n // `w-max` so the calendar sets its own width instead of inheriting\n // the filter column, which squeezed the months until the numbers ran\n // together. Anchored right because this sits in the last column and\n // would otherwise open off the edge of the viewport.\n className=\"border-border bg-background absolute top-full right-0 z-50 mt-1 flex w-max rounded-lg border p-3 shadow-lg\"\n >\n <div className=\"border-border mr-3 flex w-32 shrink-0 flex-col gap-0.5 border-r pr-3\">\n {PRESETS.map((preset) => (\n <button\n key={preset.label}\n type=\"button\"\n className=\"hover:bg-muted text-foreground rounded-md px-2 py-1.5 text-left text-xs\"\n onClick={() => {\n onChange(preset.range());\n setPendingFrom(null);\n setOpen(false);\n }}\n >\n {preset.label}\n </button>\n ))}\n </div>\n\n <div onKeyDown={onGridKeyDown}>\n <div className=\"mb-2 flex items-center justify-between\">\n <button\n type=\"button\"\n aria-label=\"Previous month\"\n className=\"hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5\"\n onClick={() => setViewMonth(addMonths(viewMonth, -1))}\n >\n <ChevronLeft className=\"size-4\" aria-hidden />\n </button>\n <button\n type=\"button\"\n aria-label=\"Next month\"\n className=\"hover:bg-muted text-muted-foreground hover:text-foreground rounded-md p-1.5\"\n onClick={() => setViewMonth(addMonths(viewMonth, 1))}\n >\n <ChevronRight className=\"size-4\" aria-hidden />\n </button>\n </div>\n <div className=\"flex gap-5\" onMouseLeave={() => setHovered(null)}>\n {renderMonth(viewMonth)}\n {renderMonth(addMonths(viewMonth, 1))}\n </div>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n","import { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}\n","/**\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":"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","names":[]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type DateRangeValue = {
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
};
|
|
7
|
+
interface DateRangePickerProps {
|
|
8
|
+
value: DateRangeValue;
|
|
9
|
+
onChange: (next: DateRangeValue) => void;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
/** Names the trigger for screen readers when there is no visible label. */
|
|
14
|
+
ariaLabel?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function DateRangePicker({ value, onChange, disabled, placeholder, className, ariaLabel, }: DateRangePickerProps): React.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { DateRangePicker, type DateRangePickerProps, type DateRangeValue };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
type DateRangeValue = {
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
};
|
|
7
|
+
interface DateRangePickerProps {
|
|
8
|
+
value: DateRangeValue;
|
|
9
|
+
onChange: (next: DateRangeValue) => void;
|
|
10
|
+
disabled?: boolean;
|
|
11
|
+
placeholder?: string;
|
|
12
|
+
className?: string;
|
|
13
|
+
/** Names the trigger for screen readers when there is no visible label. */
|
|
14
|
+
ariaLabel?: string;
|
|
15
|
+
}
|
|
16
|
+
declare function DateRangePicker({ value, onChange, disabled, placeholder, className, ariaLabel, }: DateRangePickerProps): React.JSX.Element;
|
|
17
|
+
|
|
18
|
+
export { DateRangePicker, type DateRangePickerProps, type DateRangeValue };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,121 @@
|
|
|
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/dialogLayer.ts
|
|
33
|
+
var dialogLayer_exports = {};
|
|
34
|
+
__export(dialogLayer_exports, {
|
|
35
|
+
useDialogLayer: () => useDialogLayer
|
|
36
|
+
});
|
|
37
|
+
module.exports = __toCommonJS(dialogLayer_exports);
|
|
38
|
+
var React = __toESM(require("react"), 1);
|
|
39
|
+
var layers = [];
|
|
40
|
+
var FOCUSABLE = [
|
|
41
|
+
"a[href]",
|
|
42
|
+
"button:not([disabled])",
|
|
43
|
+
"input:not([disabled])",
|
|
44
|
+
"select:not([disabled])",
|
|
45
|
+
"textarea:not([disabled])",
|
|
46
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
47
|
+
].join(",");
|
|
48
|
+
function isVisible(element) {
|
|
49
|
+
if (element.closest("[hidden]")) return false;
|
|
50
|
+
if (element.getAttribute("aria-hidden") === "true") return false;
|
|
51
|
+
return typeof element.checkVisibility === "function" ? element.checkVisibility() : true;
|
|
52
|
+
}
|
|
53
|
+
function focusableWithin(container) {
|
|
54
|
+
return Array.from(container.querySelectorAll(FOCUSABLE)).filter(
|
|
55
|
+
isVisible
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
function useDialogLayer({
|
|
59
|
+
active,
|
|
60
|
+
containerRef,
|
|
61
|
+
onEscape
|
|
62
|
+
}) {
|
|
63
|
+
const escapeRef = React.useRef(onEscape);
|
|
64
|
+
React.useEffect(() => {
|
|
65
|
+
escapeRef.current = onEscape;
|
|
66
|
+
});
|
|
67
|
+
React.useEffect(() => {
|
|
68
|
+
if (!active) return;
|
|
69
|
+
const layer = /* @__PURE__ */ Symbol("dialog-layer");
|
|
70
|
+
layers.push(layer);
|
|
71
|
+
const isTopLayer = () => layers[layers.length - 1] === layer;
|
|
72
|
+
const previouslyFocused = document.activeElement instanceof HTMLElement ? document.activeElement : null;
|
|
73
|
+
const container = containerRef.current;
|
|
74
|
+
if (container && !container.contains(document.activeElement)) {
|
|
75
|
+
const [first] = focusableWithin(container);
|
|
76
|
+
(container.hasAttribute("tabindex") ? container : first)?.focus();
|
|
77
|
+
}
|
|
78
|
+
function handleKeyDown(event) {
|
|
79
|
+
if (!isTopLayer()) return;
|
|
80
|
+
if (event.key === "Escape") {
|
|
81
|
+
escapeRef.current?.();
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
if (event.key !== "Tab") return;
|
|
85
|
+
const panel = containerRef.current;
|
|
86
|
+
if (!panel) return;
|
|
87
|
+
const items = focusableWithin(panel);
|
|
88
|
+
if (items.length === 0) {
|
|
89
|
+
event.preventDefault();
|
|
90
|
+
panel.focus();
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const first = items[0];
|
|
94
|
+
const last = items[items.length - 1];
|
|
95
|
+
const active2 = document.activeElement;
|
|
96
|
+
const outside = !panel.contains(active2);
|
|
97
|
+
if (event.shiftKey && (active2 === first || outside)) {
|
|
98
|
+
event.preventDefault();
|
|
99
|
+
last.focus();
|
|
100
|
+
} else if (!event.shiftKey && (active2 === last || outside)) {
|
|
101
|
+
event.preventDefault();
|
|
102
|
+
first.focus();
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
106
|
+
const previousOverflow = document.body.style.overflow;
|
|
107
|
+
document.body.style.overflow = "hidden";
|
|
108
|
+
return () => {
|
|
109
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
110
|
+
document.body.style.overflow = previousOverflow;
|
|
111
|
+
const index = layers.indexOf(layer);
|
|
112
|
+
if (index !== -1) layers.splice(index, 1);
|
|
113
|
+
if (previouslyFocused?.isConnected) previouslyFocused.focus();
|
|
114
|
+
};
|
|
115
|
+
}, [active, containerRef]);
|
|
116
|
+
}
|
|
117
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
118
|
+
0 && (module.exports = {
|
|
119
|
+
useDialogLayer
|
|
120
|
+
});
|
|
121
|
+
//# sourceMappingURL=dialogLayer.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dialogLayer.ts"],"sourcesContent":["\"use client\";\n\nimport * as React from \"react\";\n\n/**\n * The keyboard and focus behaviour every dialog needs, in one place.\n *\n * `Modal` and `SideDrawer` each had a copy of the scroll lock and an Escape\n * handler, and neither did anything about focus: opening a dialog left focus\n * on the button behind it, Tab walked the page underneath — through the\n * full-screen backdrop button, among other things — and closing left focus\n * wherever it had wandered. That is the whole keyboard story for thirty\n * dialogs, so it is fixed once here rather than thirty times.\n */\n\n/**\n * Open dialogs, innermost last.\n *\n * Nesting is real here — \"Create audience group\" opens on top of \"Send\n * notification\" — and without an ordering both would answer the same Escape\n * and fight over the same Tab. Only the top layer acts.\n */\nconst layers: symbol[] = [];\n\nconst FOCUSABLE = [\n \"a[href]\",\n \"button:not([disabled])\",\n \"input:not([disabled])\",\n \"select:not([disabled])\",\n \"textarea:not([disabled])\",\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(\",\");\n\n/**\n * Deliberately not `offsetParent` or `getClientRects`: the first is null for\n * anything `position: fixed`, which a dialog panel usually is, and the second\n * is empty for *everything* under a test renderer that does no layout — which\n * would collapse the trap to \"no focusable elements\" in every test.\n */\nfunction isVisible(element: HTMLElement): boolean {\n if (element.closest(\"[hidden]\")) return false;\n if (element.getAttribute(\"aria-hidden\") === \"true\") return false;\n return typeof element.checkVisibility === \"function\"\n ? element.checkVisibility()\n : true;\n}\n\nfunction focusableWithin(container: HTMLElement): HTMLElement[] {\n return Array.from(container.querySelectorAll<HTMLElement>(FOCUSABLE)).filter(\n isVisible,\n );\n}\n\nexport function useDialogLayer({\n active,\n containerRef,\n onEscape,\n}: {\n active: boolean;\n /** The panel. Focus is moved into it and kept inside it. */\n containerRef: React.RefObject<HTMLElement | null>;\n /** Called on Escape, only while this is the top layer. Omit to ignore it. */\n onEscape?: () => void;\n}): void {\n // Read through a ref so a caller passing a fresh closure every render does\n // not tear the listener down and rebuild it on every keystroke.\n const escapeRef = React.useRef(onEscape);\n React.useEffect(() => {\n escapeRef.current = onEscape;\n });\n\n React.useEffect(() => {\n if (!active) return;\n\n const layer = Symbol(\"dialog-layer\");\n layers.push(layer);\n const isTopLayer = () => layers[layers.length - 1] === layer;\n\n const previouslyFocused =\n document.activeElement instanceof HTMLElement\n ? document.activeElement\n : null;\n\n const container = containerRef.current;\n // Something inside may have claimed focus already — an `autoFocus` input —\n // and that choice is better than any this could make.\n if (container && !container.contains(document.activeElement)) {\n const [first] = focusableWithin(container);\n // The panel itself, not its first control: the first control is a Delete\n // button often enough that focusing it would put a destructive action\n // one Enter away from an accidental keypress.\n (container.hasAttribute(\"tabindex\") ? container : first)?.focus();\n }\n\n function handleKeyDown(event: KeyboardEvent) {\n if (!isTopLayer()) return;\n\n if (event.key === \"Escape\") {\n escapeRef.current?.();\n return;\n }\n\n if (event.key !== \"Tab\") return;\n const panel = containerRef.current;\n if (!panel) return;\n\n const items = focusableWithin(panel);\n if (items.length === 0) {\n event.preventDefault();\n panel.focus();\n return;\n }\n\n const first = items[0]!;\n const last = items[items.length - 1]!;\n const active = document.activeElement;\n const outside = !panel.contains(active);\n\n if (event.shiftKey && (active === first || outside)) {\n event.preventDefault();\n last.focus();\n } else if (!event.shiftKey && (active === last || outside)) {\n event.preventDefault();\n first.focus();\n }\n }\n\n document.addEventListener(\"keydown\", handleKeyDown);\n const previousOverflow = document.body.style.overflow;\n document.body.style.overflow = \"hidden\";\n\n return () => {\n document.removeEventListener(\"keydown\", handleKeyDown);\n document.body.style.overflow = previousOverflow;\n const index = layers.indexOf(layer);\n if (index !== -1) layers.splice(index, 1);\n // Back where it came from, so closing a dialog opened by keyboard does\n // not drop the caret at the top of the document.\n if (previouslyFocused?.isConnected) previouslyFocused.focus();\n };\n }, [active, containerRef]);\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,YAAuB;AAoBvB,IAAM,SAAmB,CAAC;AAE1B,IAAM,YAAY;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,EAAE,KAAK,GAAG;AAQV,SAAS,UAAU,SAA+B;AAChD,MAAI,QAAQ,QAAQ,UAAU,EAAG,QAAO;AACxC,MAAI,QAAQ,aAAa,aAAa,MAAM,OAAQ,QAAO;AAC3D,SAAO,OAAO,QAAQ,oBAAoB,aACtC,QAAQ,gBAAgB,IACxB;AACN;AAEA,SAAS,gBAAgB,WAAuC;AAC9D,SAAO,MAAM,KAAK,UAAU,iBAA8B,SAAS,CAAC,EAAE;AAAA,IACpE;AAAA,EACF;AACF;AAEO,SAAS,eAAe;AAAA,EAC7B;AAAA,EACA;AAAA,EACA;AACF,GAMS;AAGP,QAAM,YAAkB,aAAO,QAAQ;AACvC,EAAM,gBAAU,MAAM;AACpB,cAAU,UAAU;AAAA,EACtB,CAAC;AAED,EAAM,gBAAU,MAAM;AACpB,QAAI,CAAC,OAAQ;AAEb,UAAM,QAAQ,uBAAO,cAAc;AACnC,WAAO,KAAK,KAAK;AACjB,UAAM,aAAa,MAAM,OAAO,OAAO,SAAS,CAAC,MAAM;AAEvD,UAAM,oBACJ,SAAS,yBAAyB,cAC9B,SAAS,gBACT;AAEN,UAAM,YAAY,aAAa;AAG/B,QAAI,aAAa,CAAC,UAAU,SAAS,SAAS,aAAa,GAAG;AAC5D,YAAM,CAAC,KAAK,IAAI,gBAAgB,SAAS;AAIzC,OAAC,UAAU,aAAa,UAAU,IAAI,YAAY,QAAQ,MAAM;AAAA,IAClE;AAEA,aAAS,cAAc,OAAsB;AAC3C,UAAI,CAAC,WAAW,EAAG;AAEnB,UAAI,MAAM,QAAQ,UAAU;AAC1B,kBAAU,UAAU;AACpB;AAAA,MACF;AAEA,UAAI,MAAM,QAAQ,MAAO;AACzB,YAAM,QAAQ,aAAa;AAC3B,UAAI,CAAC,MAAO;AAEZ,YAAM,QAAQ,gBAAgB,KAAK;AACnC,UAAI,MAAM,WAAW,GAAG;AACtB,cAAM,eAAe;AACrB,cAAM,MAAM;AACZ;AAAA,MACF;AAEA,YAAM,QAAQ,MAAM,CAAC;AACrB,YAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,YAAMA,UAAS,SAAS;AACxB,YAAM,UAAU,CAAC,MAAM,SAASA,OAAM;AAEtC,UAAI,MAAM,aAAaA,YAAW,SAAS,UAAU;AACnD,cAAM,eAAe;AACrB,aAAK,MAAM;AAAA,MACb,WAAW,CAAC,MAAM,aAAaA,YAAW,QAAQ,UAAU;AAC1D,cAAM,eAAe;AACrB,cAAM,MAAM;AAAA,MACd;AAAA,IACF;AAEA,aAAS,iBAAiB,WAAW,aAAa;AAClD,UAAM,mBAAmB,SAAS,KAAK,MAAM;AAC7C,aAAS,KAAK,MAAM,WAAW;AAE/B,WAAO,MAAM;AACX,eAAS,oBAAoB,WAAW,aAAa;AACrD,eAAS,KAAK,MAAM,WAAW;AAC/B,YAAM,QAAQ,OAAO,QAAQ,KAAK;AAClC,UAAI,UAAU,GAAI,QAAO,OAAO,OAAO,CAAC;AAGxC,UAAI,mBAAmB,YAAa,mBAAkB,MAAM;AAAA,IAC9D;AAAA,EACF,GAAG,CAAC,QAAQ,YAAY,CAAC;AAC3B;","names":["active"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
declare function useDialogLayer({ active, containerRef, onEscape, }: {
|
|
4
|
+
active: boolean;
|
|
5
|
+
/** The panel. Focus is moved into it and kept inside it. */
|
|
6
|
+
containerRef: React.RefObject<HTMLElement | null>;
|
|
7
|
+
/** Called on Escape, only while this is the top layer. Omit to ignore it. */
|
|
8
|
+
onEscape?: () => void;
|
|
9
|
+
}): void;
|
|
10
|
+
|
|
11
|
+
export { useDialogLayer };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
declare function useDialogLayer({ active, containerRef, onEscape, }: {
|
|
4
|
+
active: boolean;
|
|
5
|
+
/** The panel. Focus is moved into it and kept inside it. */
|
|
6
|
+
containerRef: React.RefObject<HTMLElement | null>;
|
|
7
|
+
/** Called on Escape, only while this is the top layer. Omit to ignore it. */
|
|
8
|
+
onEscape?: () => void;
|
|
9
|
+
}): void;
|
|
10
|
+
|
|
11
|
+
export { useDialogLayer };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|