@payglocal_ui/flux-ui 0.3.0 → 0.3.2
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/dist/index.cjs +456 -223
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +62 -3
- package/dist/index.d.ts +62 -3
- package/dist/index.js +483 -250
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/__tests__/copyable-cell-tooltip.test.tsx +81 -0
- package/src/__tests__/data-table-column-width.test.tsx +77 -0
- package/src/__tests__/date-picker-show-time.test.tsx +189 -0
- package/src/__tests__/picker-in-dialog.test.tsx +140 -0
- package/src/copyable-cell.tsx +65 -26
- package/src/data-table.tsx +65 -9
- package/src/date-picker.tsx +459 -126
- package/src/index.ts +1 -1
- package/src/time-picker.tsx +95 -66
package/dist/index.cjs
CHANGED
|
@@ -2859,7 +2859,7 @@ function useSpotlight(steps, initialStep = 0) {
|
|
|
2859
2859
|
else setCurrentStep((s) => s + 1);
|
|
2860
2860
|
},
|
|
2861
2861
|
goBack: () => setCurrentStep((s) => Math.max(0, s - 1)),
|
|
2862
|
-
goTo: (
|
|
2862
|
+
goTo: (step2) => setCurrentStep(Math.max(0, Math.min(step2, steps.length - 1)))
|
|
2863
2863
|
};
|
|
2864
2864
|
}
|
|
2865
2865
|
|
|
@@ -3904,20 +3904,20 @@ var Progress = React36.forwardRef(({ className, value, variant = "default", size
|
|
|
3904
3904
|
] }));
|
|
3905
3905
|
Progress.displayName = "Progress";
|
|
3906
3906
|
var ProgressTracker = React36.forwardRef(
|
|
3907
|
-
({ className, steps, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { ref, className: cn("flex items-start", className), ...props, children: steps.map((
|
|
3907
|
+
({ className, steps, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { ref, className: cn("flex items-start", className), ...props, children: steps.map((step2, i) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(React36.Fragment, { children: [
|
|
3908
3908
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "flex flex-col items-center gap-1.5 min-w-0", children: [
|
|
3909
3909
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: cn(
|
|
3910
3910
|
"flex h-8 w-8 shrink-0 items-center justify-center rounded-full border-2 text-sm font-semibold transition-colors",
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
), children:
|
|
3911
|
+
step2.status === "complete" && "bg-primary border-primary text-primary-foreground",
|
|
3912
|
+
step2.status === "current" && "bg-primary/10 border-primary text-primary",
|
|
3913
|
+
step2.status === "upcoming" && "bg-card border-border text-muted-foreground"
|
|
3914
|
+
), children: step2.status === "complete" ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(import_lucide_react23.Check, { className: "size-4", strokeWidth: 2.5 }) : i + 1 }),
|
|
3915
3915
|
/* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("div", { className: "text-center px-1", children: [
|
|
3916
|
-
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: cn("text-xs font-medium",
|
|
3917
|
-
|
|
3916
|
+
/* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: cn("text-xs font-medium", step2.status === "upcoming" ? "text-muted-foreground" : "text-foreground"), children: step2.label }),
|
|
3917
|
+
step2.description && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("p", { className: "text-[11px] text-muted-foreground mt-0.5", children: step2.description })
|
|
3918
3918
|
] })
|
|
3919
3919
|
] }),
|
|
3920
|
-
i < steps.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex-1 mt-4 mx-1", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: cn("h-0.5 w-full rounded-full transition-colors",
|
|
3920
|
+
i < steps.length - 1 && /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "flex-1 mt-4 mx-1", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: cn("h-0.5 w-full rounded-full transition-colors", step2.status === "complete" ? "bg-primary" : "bg-border") }) })
|
|
3921
3921
|
] }, i)) })
|
|
3922
3922
|
);
|
|
3923
3923
|
ProgressTracker.displayName = "ProgressTracker";
|
|
@@ -4070,6 +4070,32 @@ function SortIndicator({ order }) {
|
|
|
4070
4070
|
}
|
|
4071
4071
|
);
|
|
4072
4072
|
}
|
|
4073
|
+
function parseMinMaxWidth(width) {
|
|
4074
|
+
if (!width) return null;
|
|
4075
|
+
const match = /^minmax\(\s*([^,]+?)\s*,\s*([^)]+?)\s*\)$/.exec(width.trim());
|
|
4076
|
+
return match ? { min: match[1], max: match[2] } : null;
|
|
4077
|
+
}
|
|
4078
|
+
function isFlexUnit(value) {
|
|
4079
|
+
return /^[\d.]*fr$/.test(value.trim());
|
|
4080
|
+
}
|
|
4081
|
+
function colWidthStyle(col) {
|
|
4082
|
+
const parsed = parseMinMaxWidth(col.width);
|
|
4083
|
+
if (!parsed) {
|
|
4084
|
+
return {
|
|
4085
|
+
width: col.width ?? (col.minWidth != null ? `${col.minWidth}px` : void 0),
|
|
4086
|
+
minWidth: col.minWidth,
|
|
4087
|
+
maxWidth: col.maxWidth
|
|
4088
|
+
};
|
|
4089
|
+
}
|
|
4090
|
+
return {
|
|
4091
|
+
width: isFlexUnit(parsed.max) ? void 0 : parsed.max,
|
|
4092
|
+
// An explicit numeric `minWidth`/`maxWidth` alongside a `minmax()` string
|
|
4093
|
+
// is not a combination any caller uses today; the string wins because it
|
|
4094
|
+
// is the more specific of the two.
|
|
4095
|
+
minWidth: parsed.min,
|
|
4096
|
+
maxWidth: isFlexUnit(parsed.max) ? col.maxWidth : void 0
|
|
4097
|
+
};
|
|
4098
|
+
}
|
|
4073
4099
|
function DataTable({
|
|
4074
4100
|
columns,
|
|
4075
4101
|
data,
|
|
@@ -4216,17 +4242,7 @@ function DataTable({
|
|
|
4216
4242
|
children: [
|
|
4217
4243
|
tableLayout === "fixed" && !isEmpty && /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("colgroup", { children: [
|
|
4218
4244
|
hasExpand ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("col", { style: { width: 40 } }) : null,
|
|
4219
|
-
columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
4220
|
-
"col",
|
|
4221
|
-
{
|
|
4222
|
-
style: {
|
|
4223
|
-
width: col.width ?? (col.minWidth != null ? `${col.minWidth}px` : void 0),
|
|
4224
|
-
minWidth: col.minWidth,
|
|
4225
|
-
maxWidth: col.maxWidth
|
|
4226
|
-
}
|
|
4227
|
-
},
|
|
4228
|
-
col.key
|
|
4229
|
-
)),
|
|
4245
|
+
columns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("col", { style: colWidthStyle(col) }, col.key)),
|
|
4230
4246
|
hasAction ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("col", { style: { width: 0 } }) : null
|
|
4231
4247
|
] }),
|
|
4232
4248
|
/* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
@@ -4531,7 +4547,7 @@ var PAGE_BUTTON = "w-7 h-7 rounded-md flex items-center justify-center text-[12p
|
|
|
4531
4547
|
var PAGE_BUTTON_IDLE = "text-muted-foreground hover:text-foreground hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed";
|
|
4532
4548
|
var PAGE_BUTTON_ACTIVE = "bg-primary text-primary-foreground shadow-sm";
|
|
4533
4549
|
function DataTableFooter({
|
|
4534
|
-
pad:
|
|
4550
|
+
pad: pad3,
|
|
4535
4551
|
summary,
|
|
4536
4552
|
countLabels,
|
|
4537
4553
|
leading,
|
|
@@ -4572,7 +4588,7 @@ function DataTableFooter({
|
|
|
4572
4588
|
{
|
|
4573
4589
|
className: cn(
|
|
4574
4590
|
"flex items-center gap-4 flex-wrap border-t border-border",
|
|
4575
|
-
|
|
4591
|
+
pad3,
|
|
4576
4592
|
summary === "none" && !showRowsPerPage && !leading ? "justify-end" : "justify-between"
|
|
4577
4593
|
),
|
|
4578
4594
|
children: [
|
|
@@ -4920,7 +4936,7 @@ function CopyableCell({
|
|
|
4920
4936
|
valueClassName
|
|
4921
4937
|
);
|
|
4922
4938
|
const elided = display !== void 0 && display !== value;
|
|
4923
|
-
const copyHint = copied ? "Copied" :
|
|
4939
|
+
const copyHint = copied ? "Copied" : `Copy ${label}`;
|
|
4924
4940
|
if (variant === "cell") {
|
|
4925
4941
|
return /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(Tooltip, { children: [
|
|
4926
4942
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
|
|
@@ -4958,31 +4974,45 @@ function CopyableCell({
|
|
|
4958
4974
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipContent, { side: "top", className: "text-xs", children: copied ? "Copied" : "Copy" })
|
|
4959
4975
|
] }) });
|
|
4960
4976
|
}
|
|
4977
|
+
const valueNode = onClick ? (
|
|
4978
|
+
// A bare <button>, deliberately, where the rest of flux would reach for
|
|
4979
|
+
// `Button variant="link"`. That variant hard-codes `text-[15px]`, and
|
|
4980
|
+
// the obvious override — `text-[inherit]` — does not beat it: Tailwind
|
|
4981
|
+
// and tailwind-merge read `text-[<non-length>]` as a COLOUR, so the
|
|
4982
|
+
// size class survives and the cell renders 2px larger than every other
|
|
4983
|
+
// cell in the row. Preflight already gives a bare button `font: inherit`,
|
|
4984
|
+
// so this simply inherits the cell's size at whatever density the table
|
|
4985
|
+
// is using, which is what a cell should do.
|
|
4986
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
4987
|
+
"button",
|
|
4988
|
+
{
|
|
4989
|
+
type: "button",
|
|
4990
|
+
onClick,
|
|
4991
|
+
title: elided ? void 0 : value,
|
|
4992
|
+
"aria-label": elided ? value : void 0,
|
|
4993
|
+
className: cn(
|
|
4994
|
+
"cursor-pointer bg-transparent p-0 text-left underline-offset-4",
|
|
4995
|
+
"hover:underline focus-visible:underline focus-visible:outline-none",
|
|
4996
|
+
text
|
|
4997
|
+
),
|
|
4998
|
+
children: display ?? value
|
|
4999
|
+
}
|
|
5000
|
+
)
|
|
5001
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
5002
|
+
"span",
|
|
5003
|
+
{
|
|
5004
|
+
className: text,
|
|
5005
|
+
title: elided ? void 0 : value,
|
|
5006
|
+
"aria-hidden": elided || void 0,
|
|
5007
|
+
children: display ?? value
|
|
5008
|
+
}
|
|
5009
|
+
);
|
|
4961
5010
|
return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { className: cn("group/copy flex min-w-0 items-center gap-1", className), children: [
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
// size class survives and the cell renders 2px larger than every other
|
|
4968
|
-
// cell in the row. Preflight already gives a bare button `font: inherit`,
|
|
4969
|
-
// so this simply inherits the cell's size at whatever density the table
|
|
4970
|
-
// is using, which is what a cell should do.
|
|
4971
|
-
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
4972
|
-
"button",
|
|
4973
|
-
{
|
|
4974
|
-
type: "button",
|
|
4975
|
-
onClick,
|
|
4976
|
-
title: value,
|
|
4977
|
-
className: cn(
|
|
4978
|
-
"cursor-pointer bg-transparent p-0 text-left underline-offset-4",
|
|
4979
|
-
"hover:underline focus-visible:underline focus-visible:outline-none",
|
|
4980
|
-
text
|
|
4981
|
-
),
|
|
4982
|
-
children: display ?? value
|
|
4983
|
-
}
|
|
4984
|
-
)
|
|
4985
|
-
) : /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: text, title: value, children: display ?? value }),
|
|
5011
|
+
elided ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(Tooltip, { children: [
|
|
5012
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipTrigger, { asChild: true, children: valueNode }),
|
|
5013
|
+
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipContent, { side: "top", className: "text-xs", children: value })
|
|
5014
|
+
] }) }) : valueNode,
|
|
5015
|
+
elided && !onClick && /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("span", { className: "sr-only", children: value }),
|
|
4986
5016
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipProvider, { delayDuration: 200, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(Tooltip, { children: [
|
|
4987
5017
|
/* @__PURE__ */ (0, import_jsx_runtime53.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(
|
|
4988
5018
|
Button,
|
|
@@ -5922,6 +5952,7 @@ function CalendarDayButton({
|
|
|
5922
5952
|
// src/date-picker.tsx
|
|
5923
5953
|
var import_react14 = require("react");
|
|
5924
5954
|
var import_react_dom = require("react-dom");
|
|
5955
|
+
var import_react_remove_scroll = require("react-remove-scroll");
|
|
5925
5956
|
var import_lucide_react33 = require("lucide-react");
|
|
5926
5957
|
var import_framer_motion = require("framer-motion");
|
|
5927
5958
|
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
@@ -5941,30 +5972,117 @@ var MONTHS = [
|
|
|
5941
5972
|
];
|
|
5942
5973
|
var DAYS = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"];
|
|
5943
5974
|
var PRIMARY = "#0061E3";
|
|
5944
|
-
var
|
|
5975
|
+
var CALENDAR_W = 296;
|
|
5976
|
+
var TIME_COL_W = 58;
|
|
5977
|
+
var TIME_ITEM_H = 28;
|
|
5978
|
+
var TIME_COL_H = 232;
|
|
5945
5979
|
function daysInMonth(y, m) {
|
|
5946
5980
|
return new Date(y, m + 1, 0).getDate();
|
|
5947
5981
|
}
|
|
5948
5982
|
function firstDayOf(y, m) {
|
|
5949
5983
|
return new Date(y, m, 1).getDay();
|
|
5950
5984
|
}
|
|
5951
|
-
function
|
|
5985
|
+
function pad(n) {
|
|
5986
|
+
return String(n).padStart(2, "0");
|
|
5987
|
+
}
|
|
5988
|
+
function parseValue(s) {
|
|
5952
5989
|
if (!s) return null;
|
|
5953
|
-
const [
|
|
5990
|
+
const [datePart, timePart = ""] = s.trim().split(/[ T]/);
|
|
5991
|
+
const [y, m, d] = datePart.split("-").map(Number);
|
|
5954
5992
|
if (!y || !m || !d) return null;
|
|
5955
|
-
|
|
5993
|
+
const [hh = 0, mm = 0, ss = 0] = timePart ? timePart.split(":").map(Number) : [];
|
|
5994
|
+
return {
|
|
5995
|
+
y,
|
|
5996
|
+
m: m - 1,
|
|
5997
|
+
d,
|
|
5998
|
+
hh: Number.isFinite(hh) ? hh : 0,
|
|
5999
|
+
mm: Number.isFinite(mm) ? mm : 0,
|
|
6000
|
+
ss: Number.isFinite(ss) ? ss : 0
|
|
6001
|
+
};
|
|
6002
|
+
}
|
|
6003
|
+
function parseYMD(s) {
|
|
6004
|
+
const p = parseValue(s);
|
|
6005
|
+
return p ? { y: p.y, m: p.m, d: p.d } : null;
|
|
5956
6006
|
}
|
|
5957
6007
|
function toYMD(y, m, d) {
|
|
5958
|
-
return `${y}-${
|
|
6008
|
+
return `${y}-${pad(m + 1)}-${pad(d)}`;
|
|
5959
6009
|
}
|
|
5960
|
-
function
|
|
5961
|
-
const
|
|
6010
|
+
function formatValue(p, showTime, showSecond) {
|
|
6011
|
+
const date = toYMD(p.y, p.m, p.d);
|
|
6012
|
+
if (!showTime) return date;
|
|
6013
|
+
return showSecond ? `${date} ${pad(p.hh)}:${pad(p.mm)}:${pad(p.ss)}` : `${date} ${pad(p.hh)}:${pad(p.mm)}`;
|
|
6014
|
+
}
|
|
6015
|
+
function displayTime(p, showSecond) {
|
|
6016
|
+
const period = p.hh < 12 ? "AM" : "PM";
|
|
6017
|
+
const h12 = p.hh % 12 === 0 ? 12 : p.hh % 12;
|
|
6018
|
+
const base = showSecond ? `${pad(h12)}:${pad(p.mm)}:${pad(p.ss)}` : `${pad(h12)}:${pad(p.mm)}`;
|
|
6019
|
+
return `${base} ${period}`;
|
|
6020
|
+
}
|
|
6021
|
+
function displayValue(value, showTime, showSecond) {
|
|
6022
|
+
const p = parseValue(value);
|
|
5962
6023
|
if (!p) return "";
|
|
5963
|
-
|
|
6024
|
+
const date = `${pad(p.d)} ${MONTHS[p.m].slice(0, 3)} ${p.y}`;
|
|
6025
|
+
return showTime ? `${date}, ${displayTime(p, showSecond)}` : date;
|
|
6026
|
+
}
|
|
6027
|
+
function step(n) {
|
|
6028
|
+
return Math.max(1, Math.floor(n ?? 1));
|
|
6029
|
+
}
|
|
6030
|
+
function TimeColumn({
|
|
6031
|
+
label,
|
|
6032
|
+
items,
|
|
6033
|
+
selected,
|
|
6034
|
+
onSelect,
|
|
6035
|
+
render
|
|
6036
|
+
}) {
|
|
6037
|
+
const ref = (0, import_react14.useRef)(null);
|
|
6038
|
+
const index = items.indexOf(selected);
|
|
6039
|
+
(0, import_react14.useEffect)(() => {
|
|
6040
|
+
const el = ref.current;
|
|
6041
|
+
if (!el || index < 0) return;
|
|
6042
|
+
el.scrollTo({ top: index * TIME_ITEM_H, behavior: "smooth" });
|
|
6043
|
+
}, [index]);
|
|
6044
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex flex-col border-l border-border", style: { width: TIME_COL_W }, children: [
|
|
6045
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "py-1 text-center text-[11px] font-semibold uppercase tracking-wider text-muted-foreground/70", children: label }),
|
|
6046
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
6047
|
+
"div",
|
|
6048
|
+
{
|
|
6049
|
+
ref,
|
|
6050
|
+
className: "overflow-y-auto",
|
|
6051
|
+
style: { height: TIME_COL_H, scrollbarWidth: "none", msOverflowStyle: "none" },
|
|
6052
|
+
children: [
|
|
6053
|
+
items.map((item) => {
|
|
6054
|
+
const active = item === selected;
|
|
6055
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6056
|
+
"button",
|
|
6057
|
+
{
|
|
6058
|
+
type: "button",
|
|
6059
|
+
onClick: () => onSelect(item),
|
|
6060
|
+
className: cn(
|
|
6061
|
+
"flex w-full items-center justify-center rounded-md text-[13px] font-medium transition-colors",
|
|
6062
|
+
active ? "font-semibold text-white" : "text-foreground hover:bg-muted"
|
|
6063
|
+
),
|
|
6064
|
+
style: { height: TIME_ITEM_H, background: active ? PRIMARY : void 0 },
|
|
6065
|
+
children: render ? render(item) : String(item)
|
|
6066
|
+
},
|
|
6067
|
+
String(item)
|
|
6068
|
+
);
|
|
6069
|
+
}),
|
|
6070
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { style: { height: TIME_COL_H - TIME_ITEM_H } })
|
|
6071
|
+
]
|
|
6072
|
+
}
|
|
6073
|
+
)
|
|
6074
|
+
] });
|
|
5964
6075
|
}
|
|
5965
|
-
function DatePicker({ value, onChange, placeholder = "Select date", className, min, max, label }) {
|
|
6076
|
+
function DatePicker({ value, onChange, placeholder = "Select date", className, min, max, label, showTime = false, showNow = true }) {
|
|
5966
6077
|
const today = /* @__PURE__ */ new Date();
|
|
5967
|
-
const parsed =
|
|
6078
|
+
const parsed = parseValue(value);
|
|
6079
|
+
const timeOptions = (0, import_react14.useMemo)(
|
|
6080
|
+
() => typeof showTime === "object" ? showTime : {},
|
|
6081
|
+
[showTime]
|
|
6082
|
+
);
|
|
6083
|
+
const withTime = showTime !== false && showTime !== void 0;
|
|
6084
|
+
const use12Hours = timeOptions.use12Hours ?? true;
|
|
6085
|
+
const showSecond = timeOptions.showSecond ?? false;
|
|
5968
6086
|
const [open, setOpen] = (0, import_react14.useState)(false);
|
|
5969
6087
|
const [panelPos, setPanelPos] = (0, import_react14.useState)({ top: 0, left: 0 });
|
|
5970
6088
|
const [viewYear, setViewYear] = (0, import_react14.useState)(parsed?.y ?? today.getFullYear());
|
|
@@ -5983,34 +6101,39 @@ function DatePicker({ value, onChange, placeholder = "Select date", className, m
|
|
|
5983
6101
|
setViewMonth(parsed.m);
|
|
5984
6102
|
}
|
|
5985
6103
|
}, [value]);
|
|
6104
|
+
const columnCount = withTime ? (showSecond ? 3 : 2) + (use12Hours ? 1 : 0) : 0;
|
|
6105
|
+
const PANEL_W2 = CALENDAR_W + columnCount * TIME_COL_W;
|
|
6106
|
+
const PANEL_H2 = withTime ? 392 : 340;
|
|
5986
6107
|
function openPanel() {
|
|
5987
6108
|
if (!triggerRef.current) return;
|
|
5988
6109
|
const trigger = triggerRef.current;
|
|
5989
6110
|
const vw = window.innerWidth;
|
|
5990
6111
|
const vh = window.innerHeight;
|
|
5991
|
-
const PANEL_H2 = 340;
|
|
5992
6112
|
trigger.scrollIntoView({ block: "center", behavior: "auto" });
|
|
5993
6113
|
requestAnimationFrame(() => {
|
|
5994
6114
|
if (!triggerRef.current) return;
|
|
5995
6115
|
const rect = triggerRef.current.getBoundingClientRect();
|
|
5996
6116
|
let left = rect.left;
|
|
5997
|
-
if (left +
|
|
6117
|
+
if (left + PANEL_W2 > vw - 8) left = vw - PANEL_W2 - 8;
|
|
6118
|
+
if (left < 8) left = 8;
|
|
5998
6119
|
let top = rect.bottom + 6;
|
|
5999
6120
|
if (top + PANEL_H2 > vh - 8) top = rect.top - PANEL_H2 - 6;
|
|
6121
|
+
if (top < 8) top = 8;
|
|
6000
6122
|
setPanelPos({ top, left });
|
|
6001
6123
|
setOpen(true);
|
|
6002
6124
|
});
|
|
6003
6125
|
}
|
|
6126
|
+
function closePanel() {
|
|
6127
|
+
setOpen(false);
|
|
6128
|
+
setYearMenu(false);
|
|
6129
|
+
setMonthMenu(false);
|
|
6130
|
+
}
|
|
6004
6131
|
(0, import_react14.useEffect)(() => {
|
|
6005
6132
|
if (!open) return;
|
|
6006
6133
|
function handler(e) {
|
|
6007
6134
|
const inTrigger = triggerRef.current?.contains(e.target);
|
|
6008
6135
|
const inPanel = panelRef.current?.contains(e.target);
|
|
6009
|
-
if (!inTrigger && !inPanel)
|
|
6010
|
-
setOpen(false);
|
|
6011
|
-
setYearMenu(false);
|
|
6012
|
-
setMonthMenu(false);
|
|
6013
|
-
}
|
|
6136
|
+
if (!inTrigger && !inPanel) closePanel();
|
|
6014
6137
|
}
|
|
6015
6138
|
document.addEventListener("mousedown", handler);
|
|
6016
6139
|
return () => document.removeEventListener("mousedown", handler);
|
|
@@ -6053,18 +6176,251 @@ function DatePicker({ value, onChange, placeholder = "Select date", className, m
|
|
|
6053
6176
|
cells.push({ d, m, y, current: false });
|
|
6054
6177
|
}
|
|
6055
6178
|
const years = Array.from({ length: 15 }, (_, i) => today.getFullYear() - 2 + i);
|
|
6179
|
+
const fallback = parseValue(`2000-01-01 ${timeOptions.defaultValue ?? "00:00"}`);
|
|
6180
|
+
const current = parsed ?? {
|
|
6181
|
+
y: today.getFullYear(),
|
|
6182
|
+
m: today.getMonth(),
|
|
6183
|
+
d: today.getDate(),
|
|
6184
|
+
hh: fallback.hh,
|
|
6185
|
+
mm: fallback.mm,
|
|
6186
|
+
ss: fallback.ss
|
|
6187
|
+
};
|
|
6188
|
+
const emit = (0, import_react14.useCallback)(
|
|
6189
|
+
(next) => onChange(formatValue(next, withTime, showSecond)),
|
|
6190
|
+
[onChange, withTime, showSecond]
|
|
6191
|
+
);
|
|
6192
|
+
function patchTime(patch) {
|
|
6193
|
+
emit({ ...current, ...patch });
|
|
6194
|
+
}
|
|
6195
|
+
const hourStep = step(timeOptions.hourStep);
|
|
6196
|
+
const minuteStep = step(timeOptions.minuteStep);
|
|
6197
|
+
const secondStep = step(timeOptions.secondStep);
|
|
6198
|
+
const hourItems = use12Hours ? Array.from({ length: Math.ceil(12 / hourStep) }, (_, i) => i * hourStep % 12) : Array.from({ length: Math.ceil(24 / hourStep) }, (_, i) => i * hourStep);
|
|
6199
|
+
const minuteItems = Array.from({ length: Math.ceil(60 / minuteStep) }, (_, i) => i * minuteStep);
|
|
6200
|
+
const secondItems = Array.from({ length: Math.ceil(60 / secondStep) }, (_, i) => i * secondStep);
|
|
6201
|
+
const selectedHour = use12Hours ? current.hh % 12 : current.hh;
|
|
6202
|
+
const selectedMeridiem = current.hh < 12 ? "AM" : "PM";
|
|
6203
|
+
function selectHour(h) {
|
|
6204
|
+
if (!use12Hours) return patchTime({ hh: h });
|
|
6205
|
+
patchTime({ hh: selectedMeridiem === "AM" ? h : h + 12 });
|
|
6206
|
+
}
|
|
6207
|
+
function selectMeridiem(p) {
|
|
6208
|
+
const base = current.hh % 12;
|
|
6209
|
+
patchTime({ hh: p === "AM" ? base : base + 12 });
|
|
6210
|
+
}
|
|
6056
6211
|
function selectDay(cell) {
|
|
6057
6212
|
if (!cell.current) {
|
|
6058
6213
|
setViewYear(cell.y);
|
|
6059
6214
|
setViewMonth(cell.m);
|
|
6060
6215
|
}
|
|
6061
6216
|
if (cell.current && isDisabled(cell.y, cell.m, cell.d)) return;
|
|
6062
|
-
|
|
6063
|
-
setOpen(false);
|
|
6217
|
+
emit({ y: cell.y, m: cell.m, d: cell.d, hh: current.hh, mm: current.mm, ss: current.ss });
|
|
6218
|
+
if (!withTime) setOpen(false);
|
|
6219
|
+
}
|
|
6220
|
+
function selectNow() {
|
|
6221
|
+
const n = /* @__PURE__ */ new Date();
|
|
6222
|
+
if (isDisabled(n.getFullYear(), n.getMonth(), n.getDate())) return;
|
|
6223
|
+
emit({
|
|
6224
|
+
y: n.getFullYear(),
|
|
6225
|
+
m: n.getMonth(),
|
|
6226
|
+
d: n.getDate(),
|
|
6227
|
+
hh: n.getHours(),
|
|
6228
|
+
mm: n.getMinutes(),
|
|
6229
|
+
ss: n.getSeconds()
|
|
6230
|
+
});
|
|
6231
|
+
closePanel();
|
|
6064
6232
|
}
|
|
6065
6233
|
const isToday = (c) => c.d === today.getDate() && c.m === today.getMonth() && c.y === today.getFullYear();
|
|
6066
6234
|
const isSelected = (c) => !!parsed && c.d === parsed.d && c.m === parsed.m && c.y === parsed.y;
|
|
6067
|
-
const
|
|
6235
|
+
const calendar = /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { style: { width: CALENDAR_W }, className: "flex flex-col", children: [
|
|
6236
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center justify-between px-4 pt-4 pb-3", children: [
|
|
6237
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6238
|
+
"button",
|
|
6239
|
+
{
|
|
6240
|
+
type: "button",
|
|
6241
|
+
onClick: prevMonth,
|
|
6242
|
+
className: "w-8 h-8 rounded-full flex items-center justify-center text-muted-foreground hover:bg-muted transition-colors",
|
|
6243
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronLeft, { className: "w-4 h-4" })
|
|
6244
|
+
}
|
|
6245
|
+
),
|
|
6246
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
6247
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "relative", children: [
|
|
6248
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
6249
|
+
"button",
|
|
6250
|
+
{
|
|
6251
|
+
type: "button",
|
|
6252
|
+
onClick: () => {
|
|
6253
|
+
setMonthMenu((o) => !o);
|
|
6254
|
+
setYearMenu(false);
|
|
6255
|
+
},
|
|
6256
|
+
className: "flex items-center gap-1 px-2 py-1 rounded-lg text-[14px] font-semibold text-foreground hover:bg-muted transition-colors",
|
|
6257
|
+
children: [
|
|
6258
|
+
MONTHS[viewMonth].slice(0, 3),
|
|
6259
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronDown, { className: "w-3 h-3 text-muted-foreground" })
|
|
6260
|
+
]
|
|
6261
|
+
}
|
|
6262
|
+
),
|
|
6263
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_framer_motion.AnimatePresence, { children: monthMenu && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6264
|
+
import_framer_motion.motion.div,
|
|
6265
|
+
{
|
|
6266
|
+
initial: { opacity: 0, y: -4 },
|
|
6267
|
+
animate: { opacity: 1, y: 0 },
|
|
6268
|
+
exit: { opacity: 0, y: -4 },
|
|
6269
|
+
transition: { duration: 0.12 },
|
|
6270
|
+
className: "absolute top-full left-0 z-[10000] mt-1 max-h-[220px] min-w-[130px] overflow-y-auto rounded-xl border border-border bg-popover py-1 shadow-lg",
|
|
6271
|
+
children: MONTHS.map((mn, mi) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6272
|
+
"button",
|
|
6273
|
+
{
|
|
6274
|
+
type: "button",
|
|
6275
|
+
onClick: () => {
|
|
6276
|
+
setViewMonth(mi);
|
|
6277
|
+
setMonthMenu(false);
|
|
6278
|
+
},
|
|
6279
|
+
className: "w-full px-3 py-2 text-left text-[13px] text-foreground transition-colors hover:bg-muted",
|
|
6280
|
+
style: { fontWeight: mi === viewMonth ? 600 : 400, color: mi === viewMonth ? PRIMARY : void 0 },
|
|
6281
|
+
children: mn
|
|
6282
|
+
},
|
|
6283
|
+
mn
|
|
6284
|
+
))
|
|
6285
|
+
}
|
|
6286
|
+
) })
|
|
6287
|
+
] }),
|
|
6288
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "relative", children: [
|
|
6289
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
6290
|
+
"button",
|
|
6291
|
+
{
|
|
6292
|
+
type: "button",
|
|
6293
|
+
onClick: () => {
|
|
6294
|
+
setYearMenu((o) => !o);
|
|
6295
|
+
setMonthMenu(false);
|
|
6296
|
+
},
|
|
6297
|
+
className: "flex items-center gap-1 px-2 py-1 rounded-lg text-[14px] font-semibold text-foreground hover:bg-muted transition-colors",
|
|
6298
|
+
children: [
|
|
6299
|
+
viewYear,
|
|
6300
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronDown, { className: "w-3 h-3 text-muted-foreground" })
|
|
6301
|
+
]
|
|
6302
|
+
}
|
|
6303
|
+
),
|
|
6304
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_framer_motion.AnimatePresence, { children: yearMenu && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6305
|
+
import_framer_motion.motion.div,
|
|
6306
|
+
{
|
|
6307
|
+
initial: { opacity: 0, y: -4 },
|
|
6308
|
+
animate: { opacity: 1, y: 0 },
|
|
6309
|
+
exit: { opacity: 0, y: -4 },
|
|
6310
|
+
transition: { duration: 0.12 },
|
|
6311
|
+
className: "absolute top-full left-0 z-[10000] mt-1 max-h-[200px] min-w-[90px] overflow-y-auto rounded-xl border border-border bg-popover py-1 shadow-lg",
|
|
6312
|
+
children: years.map((yr) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6313
|
+
"button",
|
|
6314
|
+
{
|
|
6315
|
+
type: "button",
|
|
6316
|
+
onClick: () => {
|
|
6317
|
+
setViewYear(yr);
|
|
6318
|
+
setYearMenu(false);
|
|
6319
|
+
},
|
|
6320
|
+
className: "w-full px-3 py-2 text-left text-[13px] text-foreground transition-colors hover:bg-muted",
|
|
6321
|
+
style: { fontWeight: yr === viewYear ? 600 : 400, color: yr === viewYear ? PRIMARY : void 0 },
|
|
6322
|
+
children: yr
|
|
6323
|
+
},
|
|
6324
|
+
yr
|
|
6325
|
+
))
|
|
6326
|
+
}
|
|
6327
|
+
) })
|
|
6328
|
+
] })
|
|
6329
|
+
] }),
|
|
6330
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6331
|
+
"button",
|
|
6332
|
+
{
|
|
6333
|
+
type: "button",
|
|
6334
|
+
onClick: nextMonth,
|
|
6335
|
+
className: "w-8 h-8 rounded-full flex items-center justify-center text-muted-foreground hover:bg-muted transition-colors",
|
|
6336
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronRight, { className: "w-4 h-4" })
|
|
6337
|
+
}
|
|
6338
|
+
)
|
|
6339
|
+
] }),
|
|
6340
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6341
|
+
"div",
|
|
6342
|
+
{
|
|
6343
|
+
className: "px-3 pb-1",
|
|
6344
|
+
style: { display: "grid", gridTemplateColumns: "repeat(7, minmax(0, 1fr))" },
|
|
6345
|
+
children: DAYS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "py-1 text-center text-[11.5px] font-semibold text-muted-foreground", children: d }, d))
|
|
6346
|
+
}
|
|
6347
|
+
),
|
|
6348
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6349
|
+
"div",
|
|
6350
|
+
{
|
|
6351
|
+
className: "gap-y-0.5 px-3 pb-4",
|
|
6352
|
+
style: { display: "grid", gridTemplateColumns: "repeat(7, minmax(0, 1fr))" },
|
|
6353
|
+
children: cells.map((cell, i) => {
|
|
6354
|
+
const selected = isSelected(cell);
|
|
6355
|
+
const tod = isToday(cell);
|
|
6356
|
+
const disabled = cell.current && isDisabled(cell.y, cell.m, cell.d);
|
|
6357
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6358
|
+
"button",
|
|
6359
|
+
{
|
|
6360
|
+
type: "button",
|
|
6361
|
+
onClick: () => selectDay(cell),
|
|
6362
|
+
disabled,
|
|
6363
|
+
className: cn(
|
|
6364
|
+
"h-9 w-9 mx-auto rounded-full text-[13px] font-medium flex items-center justify-center transition-all",
|
|
6365
|
+
selected && "text-white font-semibold",
|
|
6366
|
+
!selected && tod && "font-semibold",
|
|
6367
|
+
!selected && !tod && cell.current && !disabled && "text-gray-800 hover:bg-gray-100",
|
|
6368
|
+
!selected && !cell.current && "text-gray-300 hover:bg-gray-50",
|
|
6369
|
+
disabled && "opacity-30 cursor-not-allowed"
|
|
6370
|
+
),
|
|
6371
|
+
style: selected ? { background: PRIMARY } : tod ? { background: `${PRIMARY}18`, color: PRIMARY } : {},
|
|
6372
|
+
children: cell.d
|
|
6373
|
+
},
|
|
6374
|
+
i
|
|
6375
|
+
);
|
|
6376
|
+
})
|
|
6377
|
+
}
|
|
6378
|
+
)
|
|
6379
|
+
] });
|
|
6380
|
+
const timeColumns = withTime && /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex pt-3", children: [
|
|
6381
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6382
|
+
TimeColumn,
|
|
6383
|
+
{
|
|
6384
|
+
label: "Hr",
|
|
6385
|
+
items: hourItems,
|
|
6386
|
+
selected: selectedHour,
|
|
6387
|
+
onSelect: selectHour,
|
|
6388
|
+
render: (h) => pad(use12Hours && h === 0 ? 12 : h)
|
|
6389
|
+
}
|
|
6390
|
+
),
|
|
6391
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TimeColumn, { label: "Min", items: minuteItems, selected: current.mm, onSelect: (m) => patchTime({ mm: m }), render: pad }),
|
|
6392
|
+
showSecond && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TimeColumn, { label: "Sec", items: secondItems, selected: current.ss, onSelect: (s) => patchTime({ ss: s }), render: pad }),
|
|
6393
|
+
use12Hours && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TimeColumn, { label: "AM/PM", items: ["AM", "PM"], selected: selectedMeridiem, onSelect: selectMeridiem })
|
|
6394
|
+
] });
|
|
6395
|
+
const body = /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(import_jsx_runtime62.Fragment, { children: [
|
|
6396
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex", children: [
|
|
6397
|
+
calendar,
|
|
6398
|
+
timeColumns
|
|
6399
|
+
] }),
|
|
6400
|
+
withTime && /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center justify-between border-t border-border px-4 py-2.5", children: [
|
|
6401
|
+
showNow ? /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6402
|
+
"button",
|
|
6403
|
+
{
|
|
6404
|
+
type: "button",
|
|
6405
|
+
onClick: selectNow,
|
|
6406
|
+
className: "rounded-md px-1 text-[13px] font-medium transition-colors hover:underline",
|
|
6407
|
+
style: { color: PRIMARY },
|
|
6408
|
+
children: "Now"
|
|
6409
|
+
}
|
|
6410
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", {}),
|
|
6411
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6412
|
+
"button",
|
|
6413
|
+
{
|
|
6414
|
+
type: "button",
|
|
6415
|
+
onClick: closePanel,
|
|
6416
|
+
className: "rounded-lg px-3 py-1.5 text-[13px] font-semibold text-white transition-opacity hover:opacity-90",
|
|
6417
|
+
style: { background: PRIMARY },
|
|
6418
|
+
children: "OK"
|
|
6419
|
+
}
|
|
6420
|
+
)
|
|
6421
|
+
] })
|
|
6422
|
+
] });
|
|
6423
|
+
const panel = /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_framer_motion.AnimatePresence, { children: open && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6068
6424
|
import_framer_motion.motion.div,
|
|
6069
6425
|
{
|
|
6070
6426
|
ref: panelRef,
|
|
@@ -6077,149 +6433,21 @@ function DatePicker({ value, onChange, placeholder = "Select date", className, m
|
|
|
6077
6433
|
position: "fixed",
|
|
6078
6434
|
top: panelPos.top,
|
|
6079
6435
|
left: panelPos.left,
|
|
6080
|
-
width:
|
|
6436
|
+
width: PANEL_W2,
|
|
6081
6437
|
zIndex: 2e4,
|
|
6438
|
+
// A modal Radix Dialog sets `pointer-events: none` on <body> while
|
|
6439
|
+
// it is open, and this panel is portaled to <body> — so without
|
|
6440
|
+
// this every click on a day landed on nothing and the calendar
|
|
6441
|
+
// looked frozen inside a Dialog or Drawer. Hit-testing is
|
|
6442
|
+
// per-element, so re-enabling it here is enough; the page behind
|
|
6443
|
+
// the dialog stays inert. The click still reaches the dialog's
|
|
6444
|
+
// DismissableLayer through React's portal event propagation, so it
|
|
6445
|
+
// is treated as inside and does not dismiss the dialog.
|
|
6446
|
+
pointerEvents: "auto",
|
|
6082
6447
|
backgroundColor: "var(--popover)",
|
|
6083
6448
|
boxShadow: "0 16px 40px rgba(0,0,0,0.12), 0 4px 12px rgba(0,0,0,0.07)"
|
|
6084
6449
|
},
|
|
6085
|
-
children:
|
|
6086
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center justify-between px-4 pt-4 pb-3", children: [
|
|
6087
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6088
|
-
"button",
|
|
6089
|
-
{
|
|
6090
|
-
onClick: prevMonth,
|
|
6091
|
-
className: "w-8 h-8 rounded-full flex items-center justify-center text-gray-500 hover:bg-gray-100 transition-colors",
|
|
6092
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronLeft, { className: "w-4 h-4" })
|
|
6093
|
-
}
|
|
6094
|
-
),
|
|
6095
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "flex items-center gap-1", children: [
|
|
6096
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "relative", children: [
|
|
6097
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
6098
|
-
"button",
|
|
6099
|
-
{
|
|
6100
|
-
onClick: () => {
|
|
6101
|
-
setMonthMenu((o) => !o);
|
|
6102
|
-
setYearMenu(false);
|
|
6103
|
-
},
|
|
6104
|
-
className: "flex items-center gap-1 px-2 py-1 rounded-lg text-[14px] font-semibold text-gray-900 hover:bg-gray-100 transition-colors",
|
|
6105
|
-
children: [
|
|
6106
|
-
MONTHS[viewMonth].slice(0, 3),
|
|
6107
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronDown, { className: "w-3 h-3 text-gray-400" })
|
|
6108
|
-
]
|
|
6109
|
-
}
|
|
6110
|
-
),
|
|
6111
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_framer_motion.AnimatePresence, { children: monthMenu && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6112
|
-
import_framer_motion.motion.div,
|
|
6113
|
-
{
|
|
6114
|
-
initial: { opacity: 0, y: -4 },
|
|
6115
|
-
animate: { opacity: 1, y: 0 },
|
|
6116
|
-
exit: { opacity: 0, y: -4 },
|
|
6117
|
-
transition: { duration: 0.12 },
|
|
6118
|
-
className: "absolute top-full left-0 z-[10000] mt-1 max-h-[220px] min-w-[130px] overflow-y-auto rounded-xl border border-border bg-popover py-1 shadow-lg",
|
|
6119
|
-
children: MONTHS.map((mn, mi) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6120
|
-
"button",
|
|
6121
|
-
{
|
|
6122
|
-
onClick: () => {
|
|
6123
|
-
setViewMonth(mi);
|
|
6124
|
-
setMonthMenu(false);
|
|
6125
|
-
},
|
|
6126
|
-
className: "w-full px-3 py-2 text-left text-[13px] text-foreground transition-colors hover:bg-muted",
|
|
6127
|
-
style: { fontWeight: mi === viewMonth ? 600 : 400, color: mi === viewMonth ? PRIMARY : void 0 },
|
|
6128
|
-
children: mn
|
|
6129
|
-
},
|
|
6130
|
-
mn
|
|
6131
|
-
))
|
|
6132
|
-
}
|
|
6133
|
-
) })
|
|
6134
|
-
] }),
|
|
6135
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: "relative", children: [
|
|
6136
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(
|
|
6137
|
-
"button",
|
|
6138
|
-
{
|
|
6139
|
-
onClick: () => {
|
|
6140
|
-
setYearMenu((o) => !o);
|
|
6141
|
-
setMonthMenu(false);
|
|
6142
|
-
},
|
|
6143
|
-
className: "flex items-center gap-1 px-2 py-1 rounded-lg text-[14px] font-semibold text-gray-900 hover:bg-gray-100 transition-colors",
|
|
6144
|
-
children: [
|
|
6145
|
-
viewYear,
|
|
6146
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronDown, { className: "w-3 h-3 text-gray-400" })
|
|
6147
|
-
]
|
|
6148
|
-
}
|
|
6149
|
-
),
|
|
6150
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_framer_motion.AnimatePresence, { children: yearMenu && /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6151
|
-
import_framer_motion.motion.div,
|
|
6152
|
-
{
|
|
6153
|
-
initial: { opacity: 0, y: -4 },
|
|
6154
|
-
animate: { opacity: 1, y: 0 },
|
|
6155
|
-
exit: { opacity: 0, y: -4 },
|
|
6156
|
-
transition: { duration: 0.12 },
|
|
6157
|
-
className: "absolute top-full left-0 z-[10000] mt-1 max-h-[200px] min-w-[90px] overflow-y-auto rounded-xl border border-border bg-popover py-1 shadow-lg",
|
|
6158
|
-
children: years.map((yr) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6159
|
-
"button",
|
|
6160
|
-
{
|
|
6161
|
-
onClick: () => {
|
|
6162
|
-
setViewYear(yr);
|
|
6163
|
-
setYearMenu(false);
|
|
6164
|
-
},
|
|
6165
|
-
className: "w-full px-3 py-2 text-left text-[13px] text-foreground transition-colors hover:bg-muted",
|
|
6166
|
-
style: { fontWeight: yr === viewYear ? 600 : 400, color: yr === viewYear ? PRIMARY : void 0 },
|
|
6167
|
-
children: yr
|
|
6168
|
-
},
|
|
6169
|
-
yr
|
|
6170
|
-
))
|
|
6171
|
-
}
|
|
6172
|
-
) })
|
|
6173
|
-
] })
|
|
6174
|
-
] }),
|
|
6175
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6176
|
-
"button",
|
|
6177
|
-
{
|
|
6178
|
-
onClick: nextMonth,
|
|
6179
|
-
className: "w-8 h-8 rounded-full flex items-center justify-center text-gray-500 hover:bg-gray-100 transition-colors",
|
|
6180
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronRight, { className: "w-4 h-4" })
|
|
6181
|
-
}
|
|
6182
|
-
)
|
|
6183
|
-
] }),
|
|
6184
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6185
|
-
"div",
|
|
6186
|
-
{
|
|
6187
|
-
className: "px-3 pb-1",
|
|
6188
|
-
style: { display: "grid", gridTemplateColumns: "repeat(7, minmax(0, 1fr))" },
|
|
6189
|
-
children: DAYS.map((d) => /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("div", { className: "py-1 text-center text-[11.5px] font-semibold text-muted-foreground", children: d }, d))
|
|
6190
|
-
}
|
|
6191
|
-
),
|
|
6192
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6193
|
-
"div",
|
|
6194
|
-
{
|
|
6195
|
-
className: "gap-y-0.5 px-3 pb-4",
|
|
6196
|
-
style: { display: "grid", gridTemplateColumns: "repeat(7, minmax(0, 1fr))" },
|
|
6197
|
-
children: cells.map((cell, i) => {
|
|
6198
|
-
const selected = isSelected(cell);
|
|
6199
|
-
const tod = isToday(cell);
|
|
6200
|
-
const disabled = cell.current && isDisabled(cell.y, cell.m, cell.d);
|
|
6201
|
-
return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
6202
|
-
"button",
|
|
6203
|
-
{
|
|
6204
|
-
onClick: () => selectDay(cell),
|
|
6205
|
-
disabled,
|
|
6206
|
-
className: cn(
|
|
6207
|
-
"h-9 w-9 mx-auto rounded-full text-[13px] font-medium flex items-center justify-center transition-all",
|
|
6208
|
-
selected && "text-white font-semibold",
|
|
6209
|
-
!selected && tod && "font-semibold",
|
|
6210
|
-
!selected && !tod && cell.current && !disabled && "text-gray-800 hover:bg-gray-100",
|
|
6211
|
-
!selected && !cell.current && "text-gray-300 hover:bg-gray-50",
|
|
6212
|
-
disabled && "opacity-30 cursor-not-allowed"
|
|
6213
|
-
),
|
|
6214
|
-
style: selected ? { background: PRIMARY } : tod ? { background: `${PRIMARY}18`, color: PRIMARY } : {},
|
|
6215
|
-
children: cell.d
|
|
6216
|
-
},
|
|
6217
|
-
i
|
|
6218
|
-
);
|
|
6219
|
-
})
|
|
6220
|
-
}
|
|
6221
|
-
)
|
|
6222
|
-
]
|
|
6450
|
+
children: withTime ? /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_react_remove_scroll.RemoveScroll, { allowPinchZoom: true, children: body }) : body
|
|
6223
6451
|
}
|
|
6224
6452
|
) });
|
|
6225
6453
|
return /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)("div", { className: cn("relative", className), children: [
|
|
@@ -6229,14 +6457,14 @@ function DatePicker({ value, onChange, placeholder = "Select date", className, m
|
|
|
6229
6457
|
{
|
|
6230
6458
|
ref: triggerRef,
|
|
6231
6459
|
type: "button",
|
|
6232
|
-
onClick: () => open ?
|
|
6460
|
+
onClick: () => open ? closePanel() : openPanel(),
|
|
6233
6461
|
className: cn(
|
|
6234
6462
|
"flex h-12 min-h-12 w-full items-center gap-3 rounded-xl border border-border bg-card px-5 text-left text-[15px] shadow-sm transition-colors",
|
|
6235
6463
|
open ? "border-ring ring-2 ring-ring/20" : "hover:border-muted-foreground/45"
|
|
6236
6464
|
),
|
|
6237
6465
|
children: [
|
|
6238
6466
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.CalendarDays, { className: "size-[1.125rem] shrink-0 text-muted-foreground" }),
|
|
6239
|
-
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: cn("flex-1", value ? "text-foreground" : "text-muted-foreground"), children: value ?
|
|
6467
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)("span", { className: cn("flex-1", value ? "text-foreground" : "text-muted-foreground"), children: value ? displayValue(value, withTime, showSecond) : placeholder }),
|
|
6240
6468
|
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_lucide_react33.ChevronDown, { className: cn("size-[1.125rem] shrink-0 text-muted-foreground transition-transform", open && "rotate-180") })
|
|
6241
6469
|
]
|
|
6242
6470
|
}
|
|
@@ -7789,9 +8017,10 @@ IconButton.displayName = "IconButton";
|
|
|
7789
8017
|
// src/time-picker.tsx
|
|
7790
8018
|
var React48 = __toESM(require("react"), 1);
|
|
7791
8019
|
var import_react_dom2 = require("react-dom");
|
|
8020
|
+
var import_react_remove_scroll2 = require("react-remove-scroll");
|
|
7792
8021
|
var import_lucide_react40 = require("lucide-react");
|
|
7793
8022
|
var import_jsx_runtime72 = require("react/jsx-runtime");
|
|
7794
|
-
function
|
|
8023
|
+
function pad2(n) {
|
|
7795
8024
|
return String(n).padStart(2, "0");
|
|
7796
8025
|
}
|
|
7797
8026
|
function parseHHMM(v) {
|
|
@@ -7804,15 +8033,15 @@ function parseHHMM(v) {
|
|
|
7804
8033
|
return { h, m };
|
|
7805
8034
|
}
|
|
7806
8035
|
function toHHMM(h, m) {
|
|
7807
|
-
return `${
|
|
8036
|
+
return `${pad2(h)}:${pad2(m)}`;
|
|
7808
8037
|
}
|
|
7809
|
-
function
|
|
8038
|
+
function displayTime2(value, use24Hour) {
|
|
7810
8039
|
const p = parseHHMM(value);
|
|
7811
8040
|
if (!p) return "";
|
|
7812
|
-
if (use24Hour) return `${
|
|
8041
|
+
if (use24Hour) return `${pad2(p.h)}:${pad2(p.m)}`;
|
|
7813
8042
|
const period = p.h < 12 ? "AM" : "PM";
|
|
7814
8043
|
const displayH = p.h % 12 === 0 ? 12 : p.h % 12;
|
|
7815
|
-
return `${
|
|
8044
|
+
return `${pad2(displayH)}:${pad2(p.m)} ${period}`;
|
|
7816
8045
|
}
|
|
7817
8046
|
var ITEM_H = 36;
|
|
7818
8047
|
var VISIBLE = 5;
|
|
@@ -7916,7 +8145,7 @@ function ScrollColumn({
|
|
|
7916
8145
|
)
|
|
7917
8146
|
] });
|
|
7918
8147
|
}
|
|
7919
|
-
var
|
|
8148
|
+
var PANEL_W = 224;
|
|
7920
8149
|
var PANEL_H = 220;
|
|
7921
8150
|
var TimePicker = React48.forwardRef(
|
|
7922
8151
|
({
|
|
@@ -7970,7 +8199,7 @@ var TimePicker = React48.forwardRef(
|
|
|
7970
8199
|
const vw = window.innerWidth;
|
|
7971
8200
|
const vh = window.innerHeight;
|
|
7972
8201
|
let left = rect.left;
|
|
7973
|
-
if (left +
|
|
8202
|
+
if (left + PANEL_W > vw - 8) left = vw - PANEL_W - 8;
|
|
7974
8203
|
let top = rect.bottom + 6;
|
|
7975
8204
|
if (top + PANEL_H > vh - 8) top = rect.top - PANEL_H - 6;
|
|
7976
8205
|
setPanelPos({ top, left });
|
|
@@ -8013,7 +8242,7 @@ var TimePicker = React48.forwardRef(
|
|
|
8013
8242
|
e.stopPropagation();
|
|
8014
8243
|
onValueChange("");
|
|
8015
8244
|
}
|
|
8016
|
-
const panel = open ? /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
|
|
8245
|
+
const panel = open ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(import_react_remove_scroll2.RemoveScroll, { allowPinchZoom: true, children: /* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
|
|
8017
8246
|
"div",
|
|
8018
8247
|
{
|
|
8019
8248
|
ref: panelRef,
|
|
@@ -8025,13 +8254,17 @@ var TimePicker = React48.forwardRef(
|
|
|
8025
8254
|
position: "fixed",
|
|
8026
8255
|
top: panelPos.top,
|
|
8027
8256
|
left: panelPos.left,
|
|
8028
|
-
width:
|
|
8029
|
-
zIndex: 2e4
|
|
8257
|
+
width: PANEL_W,
|
|
8258
|
+
zIndex: 2e4,
|
|
8259
|
+
// See DatePicker: a modal Radix Dialog puts `pointer-events: none`
|
|
8260
|
+
// on <body>, which this portaled panel would otherwise inherit —
|
|
8261
|
+
// the columns rendered but no row could be clicked.
|
|
8262
|
+
pointerEvents: "auto"
|
|
8030
8263
|
},
|
|
8031
8264
|
children: [
|
|
8032
8265
|
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)("div", { className: "flex items-center gap-1.5 border-b border-border px-4 py-2.5", children: [
|
|
8033
8266
|
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)(import_lucide_react40.Clock, { className: "size-3.5 text-muted-foreground" }),
|
|
8034
|
-
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "text-[13px] font-medium text-muted-foreground", children: value ?
|
|
8267
|
+
/* @__PURE__ */ (0, import_jsx_runtime72.jsx)("span", { className: "text-[13px] font-medium text-muted-foreground", children: value ? displayTime2(value, use24Hour) : "\u2014" })
|
|
8035
8268
|
] }),
|
|
8036
8269
|
/* @__PURE__ */ (0, import_jsx_runtime72.jsxs)(
|
|
8037
8270
|
"div",
|
|
@@ -8052,7 +8285,7 @@ var TimePicker = React48.forwardRef(
|
|
|
8052
8285
|
items: hours,
|
|
8053
8286
|
selected: hour,
|
|
8054
8287
|
onSelect: handleHourChange,
|
|
8055
|
-
renderItem: (h) =>
|
|
8288
|
+
renderItem: (h) => pad2(h),
|
|
8056
8289
|
getKey: (h) => h
|
|
8057
8290
|
}
|
|
8058
8291
|
),
|
|
@@ -8063,7 +8296,7 @@ var TimePicker = React48.forwardRef(
|
|
|
8063
8296
|
items: minutes,
|
|
8064
8297
|
selected: minute,
|
|
8065
8298
|
onSelect: handleMinuteChange,
|
|
8066
|
-
renderItem: (m) =>
|
|
8299
|
+
renderItem: (m) => pad2(m),
|
|
8067
8300
|
getKey: (m) => m
|
|
8068
8301
|
}
|
|
8069
8302
|
),
|
|
@@ -8083,7 +8316,7 @@ var TimePicker = React48.forwardRef(
|
|
|
8083
8316
|
] })
|
|
8084
8317
|
]
|
|
8085
8318
|
}
|
|
8086
|
-
) : null;
|
|
8319
|
+
) }) : null;
|
|
8087
8320
|
function mergeRef(el) {
|
|
8088
8321
|
triggerRef.current = el;
|
|
8089
8322
|
if (typeof ref === "function") ref(el);
|
|
@@ -8115,7 +8348,7 @@ var TimePicker = React48.forwardRef(
|
|
|
8115
8348
|
"flex-1 truncate",
|
|
8116
8349
|
value ? "text-foreground" : "text-muted-foreground"
|
|
8117
8350
|
),
|
|
8118
|
-
children: value ?
|
|
8351
|
+
children: value ? displayTime2(value, use24Hour) : placeholder
|
|
8119
8352
|
}
|
|
8120
8353
|
),
|
|
8121
8354
|
value && !disabled ? /* @__PURE__ */ (0, import_jsx_runtime72.jsx)(
|