twico-ui 1.11.1 → 1.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/dist/index.cjs +1673 -210
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +488 -74
- package/dist/index.d.ts +488 -74
- package/dist/index.mjs +1669 -211
- package/dist/index.mjs.map +1 -1
- package/llms.txt +309 -3
- package/package.json +6 -6
package/dist/index.cjs
CHANGED
|
@@ -384,6 +384,12 @@ var ACCORDION_CSS = `
|
|
|
384
384
|
transition: grid-template-rows var(--duration-base) var(--ease-standard), visibility 0s; }
|
|
385
385
|
.twc-accordion__panel-inner { overflow: hidden; }
|
|
386
386
|
.twc-accordion__content { padding: 0 var(--space-4) var(--space-4); font-size: var(--text-sm); color: var(--color-text-muted); line-height: var(--leading-normal); }
|
|
387
|
+
/* WCAG 2.3.3: panels expand/collapse (and the chevron rotates) instantly under reduced motion
|
|
388
|
+
\u2014 visibility still toggles, so open/closed state is unchanged. */
|
|
389
|
+
@media (prefers-reduced-motion: reduce) {
|
|
390
|
+
.twc-accordion__panel, .twc-accordion__panel[data-open="true"] { transition: none; }
|
|
391
|
+
.twc-accordion__chevron { transition: none; }
|
|
392
|
+
}
|
|
387
393
|
`;
|
|
388
394
|
function Accordion({
|
|
389
395
|
items,
|
|
@@ -1143,6 +1149,9 @@ var CSS2 = `
|
|
|
1143
1149
|
transform: scale(0); pointer-events: none;
|
|
1144
1150
|
animation: twico-ripple var(--duration-slow) var(--ease-out) forwards;
|
|
1145
1151
|
}
|
|
1152
|
+
/* WCAG 2.3.3: suppress the click ripple entirely under reduced motion (display:none, not
|
|
1153
|
+
animation:none, so no static scale(0) dot lingers for the 600ms cleanup window). */
|
|
1154
|
+
@media (prefers-reduced-motion: reduce) { .twc-ripple { display: none; } }
|
|
1146
1155
|
`;
|
|
1147
1156
|
function safeHref4(url) {
|
|
1148
1157
|
if (url == null) return void 0;
|
|
@@ -1502,6 +1511,13 @@ var CAROUSEL_CSS = `
|
|
|
1502
1511
|
.twc-carousel__pause svg { width: 15px; height: 15px; display: block; }
|
|
1503
1512
|
.twc-carousel__live { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
|
|
1504
1513
|
overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
|
|
1514
|
+
/* WCAG 2.3.3: no slide/dot/arrow motion when the user asks for reduced motion \u2014 the index
|
|
1515
|
+
still changes, it just jumps rather than tweening. */
|
|
1516
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1517
|
+
.twc-carousel__track { transition: none; }
|
|
1518
|
+
.twc-carousel__dot { transition: none; }
|
|
1519
|
+
.twc-carousel__arrow { transition: none; }
|
|
1520
|
+
}
|
|
1505
1521
|
`;
|
|
1506
1522
|
function Carousel({
|
|
1507
1523
|
children,
|
|
@@ -1603,7 +1619,7 @@ function Carousel({
|
|
|
1603
1619
|
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-carousel__arrow", "data-dir": "prev", "aria-label": "Previous", disabled: atStart, onClick: () => go(index - 1), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
1604
1620
|
/* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-carousel__arrow", "data-dir": "next", "aria-label": "Next", disabled: atEnd, onClick: () => go(index + 1), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) }) })
|
|
1605
1621
|
] }) : null,
|
|
1606
|
-
showDots && count > 1 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-carousel__dots", children: slides.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-carousel__dot", "data-active": i === index || void 0, "aria-label": `Go to slide ${i + 1}`, onClick: () => go(i) }, i)) }) : null
|
|
1622
|
+
showDots && count > 1 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-carousel__dots", children: slides.map((_, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { className: "twc-carousel__dot", "data-active": i === index || void 0, "aria-current": i === index ? "true" : void 0, "aria-label": `Go to slide ${i + 1}`, onClick: () => go(i) }, i)) }) : null
|
|
1607
1623
|
]
|
|
1608
1624
|
}
|
|
1609
1625
|
);
|
|
@@ -1631,9 +1647,9 @@ function niceCeil(v) {
|
|
|
1631
1647
|
const step = n <= 1 ? 1 : n <= 2 ? 2 : n <= 5 ? 5 : 10;
|
|
1632
1648
|
return step * pow;
|
|
1633
1649
|
}
|
|
1634
|
-
function niceNum(
|
|
1635
|
-
const exp = Math.floor(Math.log10(
|
|
1636
|
-
const frac = (
|
|
1650
|
+
function niceNum(range2, round) {
|
|
1651
|
+
const exp = Math.floor(Math.log10(range2 || 1));
|
|
1652
|
+
const frac = (range2 || 1) / Math.pow(10, exp);
|
|
1637
1653
|
let nf;
|
|
1638
1654
|
if (round) nf = frac < 1.5 ? 1 : frac < 3 ? 2 : frac < 7 ? 5 : 10;
|
|
1639
1655
|
else nf = frac <= 1 ? 1 : frac <= 2 ? 2 : frac <= 5 ? 5 : 10;
|
|
@@ -1644,8 +1660,8 @@ function niceScale(min, max, maxTicks = 5) {
|
|
|
1644
1660
|
if (min === max) {
|
|
1645
1661
|
max = min + 1;
|
|
1646
1662
|
}
|
|
1647
|
-
const
|
|
1648
|
-
const step = niceNum(
|
|
1663
|
+
const range2 = niceNum(max - min, false);
|
|
1664
|
+
const step = niceNum(range2 / Math.max(1, maxTicks - 1), true);
|
|
1649
1665
|
const niceMin = Math.floor(min / step) * step;
|
|
1650
1666
|
const niceMax = Math.ceil(max / step) * step;
|
|
1651
1667
|
const ticks = [];
|
|
@@ -2423,7 +2439,7 @@ function PieChart({
|
|
|
2423
2439
|
styles,
|
|
2424
2440
|
/* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: `0 0 ${H} ${H}`, role: "img", "aria-label": svgAriaLabel, "aria-describedby": tableId, children: total <= 0 ? /* @__PURE__ */ jsxRuntime.jsx("text", { className: "twc-chart__empty", x: cx, y: cy, textAnchor: "middle", dominantBaseline: "middle", children: "No data" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2425
2441
|
slices.map(({ d, i, v, s0, s1, span, pct, color }) => {
|
|
2426
|
-
const
|
|
2442
|
+
const pad2 = span > padAngle ? padAngle / 2 : 0;
|
|
2427
2443
|
const items = [{ color, label: fmt(v), value: `${pct}%` }];
|
|
2428
2444
|
let explode;
|
|
2429
2445
|
if (selected === i) {
|
|
@@ -2442,7 +2458,7 @@ function PieChart({
|
|
|
2442
2458
|
"data-mark": "",
|
|
2443
2459
|
"data-active": emph === i ? "true" : void 0,
|
|
2444
2460
|
"data-selected": selected === i ? "true" : void 0,
|
|
2445
|
-
d: arcPath(cx, cy, rOuter, rInner, s0 +
|
|
2461
|
+
d: arcPath(cx, cy, rOuter, rInner, s0 + pad2, s1 - pad2),
|
|
2446
2462
|
onMouseMove: (e) => {
|
|
2447
2463
|
setActive(i);
|
|
2448
2464
|
show({ title: d.label, items }, e);
|
|
@@ -2544,9 +2560,9 @@ function Gauge({
|
|
|
2544
2560
|
const cx = size / 2, cy = size / 2;
|
|
2545
2561
|
const span = endAngle - startAngle;
|
|
2546
2562
|
const frac = (v) => {
|
|
2547
|
-
const
|
|
2548
|
-
if (!
|
|
2549
|
-
return Math.max(0, Math.min(1, ((Number(v) || 0) - min) /
|
|
2563
|
+
const range2 = max - min;
|
|
2564
|
+
if (!range2) return 0;
|
|
2565
|
+
return Math.max(0, Math.min(1, ((Number(v) || 0) - min) / range2));
|
|
2550
2566
|
};
|
|
2551
2567
|
const isMulti = Array.isArray(series) && series.length > 0;
|
|
2552
2568
|
const items = isMulti ? series : [{ value: Number(value) || 0, label, color }];
|
|
@@ -2721,9 +2737,9 @@ function Sparkline({
|
|
|
2721
2737
|
const n = values.length;
|
|
2722
2738
|
const W = width, H = height;
|
|
2723
2739
|
const dotR = showDots ? Math.max(2, strokeWidth + 1) : 0;
|
|
2724
|
-
const
|
|
2725
|
-
const innerW = Math.max(1, W -
|
|
2726
|
-
const innerH = Math.max(1, H -
|
|
2740
|
+
const pad2 = Math.max(strokeWidth / 2, dotR) + 1;
|
|
2741
|
+
const innerW = Math.max(1, W - pad2 * 2);
|
|
2742
|
+
const innerH = Math.max(1, H - pad2 * 2);
|
|
2727
2743
|
const dMin = min != null ? min : n ? Math.min(...values) : 0;
|
|
2728
2744
|
const dMax = max != null ? max : n ? Math.max(...values) : 1;
|
|
2729
2745
|
let lo = dMin, hi = dMax;
|
|
@@ -2732,9 +2748,9 @@ function Sparkline({
|
|
|
2732
2748
|
hi = hi + 1;
|
|
2733
2749
|
}
|
|
2734
2750
|
const span = hi - lo;
|
|
2735
|
-
const x = (i) => n <= 1 ?
|
|
2736
|
-
const y = (v) =>
|
|
2737
|
-
const baselineY =
|
|
2751
|
+
const x = (i) => n <= 1 ? pad2 + innerW / 2 : pad2 + innerW / (n - 1) * i;
|
|
2752
|
+
const y = (v) => pad2 + innerH - (v - lo) / span * innerH;
|
|
2753
|
+
const baselineY = pad2 + innerH;
|
|
2738
2754
|
const points = values.map((v, i) => [x(i), y(v)]);
|
|
2739
2755
|
const crv = isBar ? "straight" : curve;
|
|
2740
2756
|
const pathOpts = { smooth: crv === "smooth", step: crv === "stepped" ? "after" : null };
|
|
@@ -2766,7 +2782,7 @@ function Sparkline({
|
|
|
2766
2782
|
"data-mark": true,
|
|
2767
2783
|
"data-selected": selected === i || void 0,
|
|
2768
2784
|
style: { fill: color },
|
|
2769
|
-
x:
|
|
2785
|
+
x: pad2 + band * i + (band - slot) / 2,
|
|
2770
2786
|
y: baselineY - h,
|
|
2771
2787
|
width: Math.max(1, slot),
|
|
2772
2788
|
height: Math.max(1, h),
|
|
@@ -3933,8 +3949,8 @@ function FunnelChart({
|
|
|
3933
3949
|
const n = rows.length;
|
|
3934
3950
|
const fmt = valueFormat || fmtNumber;
|
|
3935
3951
|
const W = 600, H = height;
|
|
3936
|
-
const
|
|
3937
|
-
const innerW = W -
|
|
3952
|
+
const pad2 = 8;
|
|
3953
|
+
const innerW = W - pad2 * 2, innerH = H - pad2 * 2;
|
|
3938
3954
|
const values = rows.map((d) => Number(d.value) || 0);
|
|
3939
3955
|
const maxValue = Math.max(0, ...values);
|
|
3940
3956
|
const denom = maxValue > 0 ? maxValue : 1;
|
|
@@ -3954,16 +3970,16 @@ function FunnelChart({
|
|
|
3954
3970
|
let points, tx, ty;
|
|
3955
3971
|
if (horizontal) {
|
|
3956
3972
|
const bandW = innerW / Math.max(1, n);
|
|
3957
|
-
const x0 =
|
|
3958
|
-
const x1 =
|
|
3973
|
+
const x0 = pad2 + bandW * i + gap / 2;
|
|
3974
|
+
const x1 = pad2 + bandW * (i + 1) - gap / 2;
|
|
3959
3975
|
const cy = H / 2;
|
|
3960
3976
|
points = [[x0, cy - lead], [x1, cy - trail], [x1, cy + trail], [x0, cy + lead]];
|
|
3961
3977
|
tx = (x0 + x1) / 2;
|
|
3962
3978
|
ty = cy;
|
|
3963
3979
|
} else {
|
|
3964
3980
|
const bandH = innerH / Math.max(1, n);
|
|
3965
|
-
const y0 =
|
|
3966
|
-
const y1 =
|
|
3981
|
+
const y0 = pad2 + bandH * i + gap / 2;
|
|
3982
|
+
const y1 = pad2 + bandH * (i + 1) - gap / 2;
|
|
3967
3983
|
const cx = W / 2;
|
|
3968
3984
|
points = [[cx - lead, y0], [cx + lead, y0], [cx + trail, y1], [cx - trail, y1]];
|
|
3969
3985
|
tx = cx;
|
|
@@ -5126,6 +5142,7 @@ function Checkbox({
|
|
|
5126
5142
|
.twc-check[data-invalid="true"] .twc-check__box { border-color: var(--color-danger); }
|
|
5127
5143
|
.twc-check__text { display: flex; flex-direction: column; gap: 2px; }
|
|
5128
5144
|
.twc-check__label { font-size: var(--text-sm); font-weight: var(--font-medium); color: var(--color-text); line-height: 1.3; }
|
|
5145
|
+
.twc-field__req { color: var(--color-danger); }
|
|
5129
5146
|
.twc-check__desc { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
5130
5147
|
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
5131
5148
|
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
@@ -5166,7 +5183,10 @@ function Checkbox({
|
|
|
5166
5183
|
),
|
|
5167
5184
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-check__box", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { className: "twc-check__svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "3.5", strokeLinecap: "round", strokeLinejoin: "round", children: mixed ? /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M5 12h14" }) : /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M20 6 9 17l-5-5" }) }) }),
|
|
5168
5185
|
label || description ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-check__text", children: [
|
|
5169
|
-
label ? /* @__PURE__ */ jsxRuntime.
|
|
5186
|
+
label ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-check__label", children: [
|
|
5187
|
+
label,
|
|
5188
|
+
required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-field__req", children: "*" }) : null
|
|
5189
|
+
] }) : null,
|
|
5170
5190
|
description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-check__desc", children: description }) : null
|
|
5171
5191
|
] }) : null
|
|
5172
5192
|
] });
|
|
@@ -5186,9 +5206,11 @@ var FIELD_CSS = `
|
|
|
5186
5206
|
var COLORPICKER_CSS = `
|
|
5187
5207
|
.twc-cp { position: relative; font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-1-5); }
|
|
5188
5208
|
.twc-cp__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); }
|
|
5189
|
-
.twc-cp__trigger { display: flex; align-items: center; gap: var(--space-2-5);
|
|
5209
|
+
.twc-cp__trigger { display: flex; align-items: center; gap: var(--space-2-5); --_h: var(--control-h-md); height: var(--_h); padding: 0 var(--space-2) 0 var(--space-2);
|
|
5190
5210
|
background: var(--color-surface); border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md); cursor: pointer;
|
|
5191
5211
|
transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); }
|
|
5212
|
+
.twc-cp__trigger[data-size="sm"] { --_h: var(--control-h-sm); }
|
|
5213
|
+
.twc-cp__trigger[data-size="lg"] { --_h: var(--control-h-lg); }
|
|
5192
5214
|
.twc-cp__trigger:hover:not([data-open="true"]):not([data-disabled="true"]) { border-color: var(--color-border-strong); }
|
|
5193
5215
|
.twc-cp__trigger[data-open="true"] { border-color: var(--color-primary); box-shadow: var(--ring); }
|
|
5194
5216
|
.twc-cp__trigger[data-invalid="true"] { border-color: var(--color-danger); }
|
|
@@ -5282,6 +5304,7 @@ function ColorPicker({
|
|
|
5282
5304
|
defaultValue = "#6366F1",
|
|
5283
5305
|
presets = DEFAULT_PRESETS,
|
|
5284
5306
|
disabled = false,
|
|
5307
|
+
size = "md",
|
|
5285
5308
|
alpha = false,
|
|
5286
5309
|
tone = "primary",
|
|
5287
5310
|
onChange,
|
|
@@ -5433,6 +5456,7 @@ function ColorPicker({
|
|
|
5433
5456
|
"data-open": open || void 0,
|
|
5434
5457
|
"data-disabled": disabled || void 0,
|
|
5435
5458
|
"data-invalid": invalid || void 0,
|
|
5459
|
+
"data-size": size,
|
|
5436
5460
|
role: "button",
|
|
5437
5461
|
tabIndex: disabled ? -1 : 0,
|
|
5438
5462
|
"aria-haspopup": "dialog",
|
|
@@ -7353,6 +7377,8 @@ function MultiSelect({
|
|
|
7353
7377
|
name,
|
|
7354
7378
|
max,
|
|
7355
7379
|
maxTagCount,
|
|
7380
|
+
filter,
|
|
7381
|
+
onInputChange,
|
|
7356
7382
|
virtualized = false,
|
|
7357
7383
|
overscan = 8,
|
|
7358
7384
|
id,
|
|
@@ -7380,10 +7406,11 @@ function MultiSelect({
|
|
|
7380
7406
|
const popRef = React51__namespace.default.useRef(null);
|
|
7381
7407
|
const listRef = React51__namespace.default.useRef(null);
|
|
7382
7408
|
const activeRef = React51__namespace.default.useRef(null);
|
|
7383
|
-
const fGroups = React51__namespace.default.useMemo(
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7409
|
+
const fGroups = React51__namespace.default.useMemo(() => {
|
|
7410
|
+
const q = query.trim();
|
|
7411
|
+
const fn = filter === false ? null : typeof filter === "function" ? filter : matches2;
|
|
7412
|
+
return groups.map((g) => ({ group: g.group, options: fn ? g.options.filter((o) => fn(o, q)) : g.options })).filter((g) => g.options.length);
|
|
7413
|
+
}, [groups, query, filter]);
|
|
7387
7414
|
const visible = React51__namespace.default.useMemo(() => fGroups.flatMap((g) => g.options), [fGroups]);
|
|
7388
7415
|
const rowH = React51__namespace.default.useMemo(() => visible.some((o) => o.description) ? 48 : 36, [visible]);
|
|
7389
7416
|
const GROUP_H = 30;
|
|
@@ -7663,6 +7690,7 @@ function MultiSelect({
|
|
|
7663
7690
|
onChange: (e) => {
|
|
7664
7691
|
setQuery(e.target.value);
|
|
7665
7692
|
setOpen(true);
|
|
7693
|
+
onInputChange?.(e.target.value);
|
|
7666
7694
|
},
|
|
7667
7695
|
onKeyDown: (e) => {
|
|
7668
7696
|
onKeyDown?.(e);
|
|
@@ -8505,6 +8533,7 @@ var NUM_OPS = [
|
|
|
8505
8533
|
];
|
|
8506
8534
|
var opsFor = (type) => type === "number" ? NUM_OPS : STR_OPS;
|
|
8507
8535
|
var isMultiOp = (op) => op === "isAnyOf";
|
|
8536
|
+
var getColVal = (col, row) => col && col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col && col.field];
|
|
8508
8537
|
function testFilter(raw, op, target, type) {
|
|
8509
8538
|
if (op === "isEmpty") return raw == null || raw === "";
|
|
8510
8539
|
if (op === "isNotEmpty") return !(raw == null || raw === "");
|
|
@@ -8550,14 +8579,15 @@ function runDatatableQuery(rows, query, options = {}) {
|
|
|
8550
8579
|
const cols = options.columns || [];
|
|
8551
8580
|
const typeOf = (field) => cols.find((c) => c.field === field)?.type === "number" ? "number" : "string";
|
|
8552
8581
|
const searchFields = options.searchFields || (cols.length ? cols.filter((c) => c.field && c.type !== "actions").map((c) => c.field) : rows && rows[0] ? Object.keys(rows[0]) : []);
|
|
8582
|
+
const gv = (field, r2) => getColVal(cols.find((c) => c.field === field) || { field }, r2);
|
|
8553
8583
|
let out = Array.isArray(rows) ? rows : [];
|
|
8554
8584
|
const quick = String(q.quickFilter || "").trim().toLowerCase();
|
|
8555
|
-
if (quick) out = out.filter((r2) => searchFields.some((f) => String(
|
|
8556
|
-
for (const f of q.filters || []) out = out.filter((r2) => testFilter(
|
|
8585
|
+
if (quick) out = out.filter((r2) => searchFields.some((f) => String(gv(f, r2) ?? "").toLowerCase().includes(quick)));
|
|
8586
|
+
for (const f of q.filters || []) out = out.filter((r2) => testFilter(gv(f.field, r2), f.op, f.value, typeOf(f.field)));
|
|
8557
8587
|
if (q.sort && q.sort.field) {
|
|
8558
8588
|
const { field, dir } = q.sort, numeric = typeOf(field) === "number";
|
|
8559
8589
|
out = [...out].sort((a, b) => {
|
|
8560
|
-
const av =
|
|
8590
|
+
const av = gv(field, a), bv = gv(field, b);
|
|
8561
8591
|
if (av == null) return 1;
|
|
8562
8592
|
if (bv == null) return -1;
|
|
8563
8593
|
const r2 = numeric ? av - bv : String(av).localeCompare(String(bv));
|
|
@@ -8815,6 +8845,7 @@ function Datatable({
|
|
|
8815
8845
|
"aria-label": ariaLabelAttr,
|
|
8816
8846
|
rowGrouping = [],
|
|
8817
8847
|
rowNumbers = false,
|
|
8848
|
+
searchFields = null,
|
|
8818
8849
|
rowPinning = false,
|
|
8819
8850
|
rowReorder = false,
|
|
8820
8851
|
rowResize = false,
|
|
@@ -8993,7 +9024,19 @@ function Datatable({
|
|
|
8993
9024
|
rowGroupingKeyRef.current = rowGroupingKey;
|
|
8994
9025
|
setGroupBy(rowGrouping || []);
|
|
8995
9026
|
}, [rowGroupingKey]);
|
|
8996
|
-
const
|
|
9027
|
+
const AUTO_CHROME = 74;
|
|
9028
|
+
const autoWidth = (c) => {
|
|
9029
|
+
const label = typeof c.headerName === "string" ? c.headerName : String(c.field ?? "");
|
|
9030
|
+
return AUTO_CHROME + Math.ceil(label.length * 8);
|
|
9031
|
+
};
|
|
9032
|
+
const clampWidth = (w, c) => {
|
|
9033
|
+
let x = w;
|
|
9034
|
+
if (typeof c.maxWidth === "number") x = Math.min(x, c.maxWidth);
|
|
9035
|
+
if (typeof c.minWidth === "number") x = Math.max(x, c.minWidth);
|
|
9036
|
+
return Math.max(40, x);
|
|
9037
|
+
};
|
|
9038
|
+
const intrinsicWidth = (c) => c.width === "auto" ? autoWidth(c) : typeof c.width === "number" ? c.width : 160;
|
|
9039
|
+
const widthOf = (c) => clampWidth(widths[c.field] ?? intrinsicWidth(c), c);
|
|
8997
9040
|
const [colMenu, setColMenu] = React51__namespace.default.useState(null);
|
|
8998
9041
|
const [menuPos, openMenu, closeMenu] = useFloating();
|
|
8999
9042
|
const [panel, setPanel] = React51__namespace.default.useState(null);
|
|
@@ -9156,17 +9199,18 @@ function Datatable({
|
|
|
9156
9199
|
let out = rows;
|
|
9157
9200
|
if (quick.trim()) {
|
|
9158
9201
|
const q = quick.trim().toLowerCase();
|
|
9159
|
-
|
|
9202
|
+
const searchCols = searchFields && searchFields.length ? searchFields.map((f) => colByField[f] || { field: f }) : visibleCols;
|
|
9203
|
+
out = out.filter((r2) => searchCols.some((c) => String(getColVal(c, r2) ?? "").toLowerCase().includes(q)));
|
|
9160
9204
|
}
|
|
9161
9205
|
for (const f of filters) {
|
|
9162
9206
|
const col = colByField[f.field];
|
|
9163
9207
|
if (!col) continue;
|
|
9164
|
-
out = out.filter((r2) => testFilter(r2
|
|
9208
|
+
out = out.filter((r2) => testFilter(getColVal(col, r2), f.op, f.value, col.type));
|
|
9165
9209
|
}
|
|
9166
9210
|
if (sort) {
|
|
9167
9211
|
const col = colByField[sort.field];
|
|
9168
9212
|
out = [...out].sort((a, b) => {
|
|
9169
|
-
const av = a
|
|
9213
|
+
const av = getColVal(col, a), bv = getColVal(col, b);
|
|
9170
9214
|
if (av == null) return 1;
|
|
9171
9215
|
if (bv == null) return -1;
|
|
9172
9216
|
const r2 = col?.type === "number" ? av - bv : String(av).localeCompare(String(bv));
|
|
@@ -9178,7 +9222,7 @@ function Datatable({
|
|
|
9178
9222
|
out = [...out].sort((a, b) => (idx.get(keyOf(a)) ?? 1e9) - (idx.get(keyOf(b)) ?? 1e9));
|
|
9179
9223
|
}
|
|
9180
9224
|
return out;
|
|
9181
|
-
}, [rows, quick, filters, sort, visibleCols, colByField, serverMode, rowOrder]);
|
|
9225
|
+
}, [rows, quick, filters, sort, visibleCols, colByField, serverMode, rowOrder, searchFields]);
|
|
9182
9226
|
const paginated = pageSize > 0;
|
|
9183
9227
|
const serverTotal = rowCount == null ? processed.length : rowCount;
|
|
9184
9228
|
const totalRows = serverMode ? serverTotal : processed.length;
|
|
@@ -9203,7 +9247,7 @@ function Datatable({
|
|
|
9203
9247
|
function computeAgg(col, data) {
|
|
9204
9248
|
const agg = col.aggregation;
|
|
9205
9249
|
if (!agg) return null;
|
|
9206
|
-
const raw = data.map((r2) => r2
|
|
9250
|
+
const raw = data.map((r2) => getColVal(col, r2)).filter((v) => v != null && v !== "");
|
|
9207
9251
|
if (typeof agg === "function") return agg(raw, data);
|
|
9208
9252
|
if (agg === "count") return raw.length;
|
|
9209
9253
|
const nums = raw.map(Number).filter((n) => !Number.isNaN(n));
|
|
@@ -9221,7 +9265,8 @@ function Datatable({
|
|
|
9221
9265
|
const field = activeGroupBy[depth];
|
|
9222
9266
|
const map = /* @__PURE__ */ new Map();
|
|
9223
9267
|
for (const r2 of rowsIn) {
|
|
9224
|
-
const
|
|
9268
|
+
const gvv = getColVal(colByField[field], r2);
|
|
9269
|
+
const v = gvv == null || gvv === "" ? "\u2014" : gvv;
|
|
9225
9270
|
if (!map.has(v)) map.set(v, []);
|
|
9226
9271
|
map.get(v).push(r2);
|
|
9227
9272
|
}
|
|
@@ -9518,13 +9563,17 @@ function Datatable({
|
|
|
9518
9563
|
function optionsForField(field) {
|
|
9519
9564
|
const col = colByField[field];
|
|
9520
9565
|
if (col?.valueOptions) return col.valueOptions.map((o) => typeof o === "string" ? { value: o, label: o } : o);
|
|
9521
|
-
const
|
|
9566
|
+
const seen2 = /* @__PURE__ */ new Map();
|
|
9522
9567
|
for (const r2 of rows) {
|
|
9523
|
-
const
|
|
9524
|
-
if (
|
|
9525
|
-
|
|
9568
|
+
const raw = getColVal(col, r2);
|
|
9569
|
+
if (raw == null || raw === "") continue;
|
|
9570
|
+
const key = String(raw);
|
|
9571
|
+
if (seen2.has(key)) continue;
|
|
9572
|
+
const label = col?.valueFormatter ? col.valueFormatter(raw, r2) : key;
|
|
9573
|
+
seen2.set(key, { value: key, label: typeof label === "string" || typeof label === "number" ? String(label) : key });
|
|
9574
|
+
if (seen2.size > 80) break;
|
|
9526
9575
|
}
|
|
9527
|
-
return [...
|
|
9576
|
+
return [...seen2.values()].sort((a, b) => String(a.label).localeCompare(String(b.label)));
|
|
9528
9577
|
}
|
|
9529
9578
|
const [resizing, setResizing] = React51__namespace.default.useState(false);
|
|
9530
9579
|
function startResize(e, field) {
|
|
@@ -9554,7 +9603,7 @@ function Datatable({
|
|
|
9554
9603
|
meas.setAttribute("aria-hidden", "true");
|
|
9555
9604
|
meas.style.cssText = "position:fixed;left:-9999px;top:-9999px;visibility:hidden;pointer-events:none;white-space:nowrap;display:inline-block;box-sizing:content-box;padding:0;";
|
|
9556
9605
|
document.body.appendChild(meas);
|
|
9557
|
-
let content = 0,
|
|
9606
|
+
let content = 0, pad2 = 0;
|
|
9558
9607
|
try {
|
|
9559
9608
|
for (const cell of cells) {
|
|
9560
9609
|
const src = cell.tagName === "TH" ? cell.querySelector(".twc-dt__th-inner") || cell : cell;
|
|
@@ -9566,13 +9615,13 @@ function Datatable({
|
|
|
9566
9615
|
meas.style.letterSpacing = cs.letterSpacing;
|
|
9567
9616
|
meas.innerHTML = src.innerHTML;
|
|
9568
9617
|
content = Math.max(content, meas.scrollWidth);
|
|
9569
|
-
|
|
9618
|
+
pad2 = Math.max(pad2, (parseFloat(cs.paddingLeft) || 0) + (parseFloat(cs.paddingRight) || 0));
|
|
9570
9619
|
}
|
|
9571
9620
|
} finally {
|
|
9572
9621
|
meas.innerHTML = "";
|
|
9573
9622
|
document.body.removeChild(meas);
|
|
9574
9623
|
}
|
|
9575
|
-
const w = Math.min(640, Math.max(72, Math.ceil(content) + Math.ceil(
|
|
9624
|
+
const w = Math.min(640, Math.max(72, Math.ceil(content) + Math.ceil(pad2) + 6));
|
|
9576
9625
|
setWidths((m) => ({ ...m, [field]: w }));
|
|
9577
9626
|
}
|
|
9578
9627
|
function onColDrop(targetField) {
|
|
@@ -9591,7 +9640,7 @@ function Datatable({
|
|
|
9591
9640
|
function exportData(format = "csv") {
|
|
9592
9641
|
const expCols = ordered.filter((c) => c.type !== "actions");
|
|
9593
9642
|
const source = serverMode ? paged : processed;
|
|
9594
|
-
const cellValue = (c, row) => c.exportValue ? c.exportValue(row[c.field], row) : row
|
|
9643
|
+
const cellValue = (c, row) => c.exportValue ? c.exportValue(row[c.field], row) : getColVal(c, row);
|
|
9595
9644
|
const fname = (ext) => `${exportFilename}.${ext}`;
|
|
9596
9645
|
const download = (text2, mime, ext) => {
|
|
9597
9646
|
const blob = new Blob([text2], { type: mime });
|
|
@@ -9640,7 +9689,7 @@ function Datatable({
|
|
|
9640
9689
|
}
|
|
9641
9690
|
}
|
|
9642
9691
|
const data = serverMode ? paged : processed;
|
|
9643
|
-
const raw = data.map((r2) => r2
|
|
9692
|
+
const raw = data.map((r2) => getColVal(col, r2)).filter((v) => v != null && v !== "");
|
|
9644
9693
|
if (typeof agg === "function") return agg(raw, data);
|
|
9645
9694
|
if (agg === "count") return raw.length;
|
|
9646
9695
|
const nums = raw.map(Number).filter((n) => !Number.isNaN(n));
|
|
@@ -10059,7 +10108,7 @@ function Datatable({
|
|
|
10059
10108
|
showRowNum ? /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-dt__td twc-dt__rownum", role: "gridcell", "aria-hidden": "true", "data-pin": "left", "data-pin-edge": pins.left.length ? void 0 : "left", style: { insetInlineStart: numLeft, width: NUM_W }, children: typeof ri === "number" ? (paginated || serverMode ? pageVal * sizeVal : 0) + ri + 1 : "" }) : null,
|
|
10060
10109
|
ordered.map((c, ci) => {
|
|
10061
10110
|
const st = stickyOf(c.field);
|
|
10062
|
-
const val = row
|
|
10111
|
+
const val = getColVal(c, row);
|
|
10063
10112
|
const isActions = c.type === "actions";
|
|
10064
10113
|
const editable = isColEditable(c);
|
|
10065
10114
|
const isEditing = editing && editing.key === k && editing.field === c.field;
|
|
@@ -10116,9 +10165,9 @@ function Datatable({
|
|
|
10116
10165
|
}
|
|
10117
10166
|
function renderPivot() {
|
|
10118
10167
|
const rFields = pivotConfig.rows, cFields = pivotConfig.columns || [], values = pivotConfig.values;
|
|
10119
|
-
const rowKeyOf = (r2) => rFields.map((f) =>
|
|
10120
|
-
const colPathOf = (r2) => cFields.map((f) => String(
|
|
10121
|
-
const aggOf2 = (subset, v) => computeAgg({ field: v.field, aggregation: v.agg || "sum" }, subset || []);
|
|
10168
|
+
const rowKeyOf = (r2) => rFields.map((f) => getColVal(colByField[f], r2) ?? "\u2014").join(" \xB7 ");
|
|
10169
|
+
const colPathOf = (r2) => cFields.map((f) => String(getColVal(colByField[f], r2) ?? "\u2014"));
|
|
10170
|
+
const aggOf2 = (subset, v) => computeAgg({ ...colByField[v.field], field: v.field, aggregation: v.agg || "sum" }, subset || []);
|
|
10122
10171
|
const fmt = (val, v) => {
|
|
10123
10172
|
if (val == null) return "\u2014";
|
|
10124
10173
|
const col = colByField[v.field];
|
|
@@ -10575,7 +10624,7 @@ function Datatable({
|
|
|
10575
10624
|
e.preventDefault();
|
|
10576
10625
|
e.stopPropagation();
|
|
10577
10626
|
const delta = e.key === "ArrowRight" ? 10 : -10;
|
|
10578
|
-
setWidths((m) => ({ ...m, [c.field]: Math.max(72, (m[c.field] ?? c
|
|
10627
|
+
setWidths((m) => ({ ...m, [c.field]: Math.max(72, (m[c.field] ?? intrinsicWidth(c)) + delta) }));
|
|
10579
10628
|
},
|
|
10580
10629
|
title: "Drag to resize \xB7 double-click to fit content"
|
|
10581
10630
|
}
|
|
@@ -10818,10 +10867,10 @@ function Datatable({
|
|
|
10818
10867
|
" ",
|
|
10819
10868
|
groupBy.includes(c.field) ? "Stop grouping" : "Group by this column"
|
|
10820
10869
|
] }) : null,
|
|
10821
|
-
!disableColumnReorder && c.type !== "actions" && !pins.left.includes(c.field) && !pins.right.includes(c.field) ? (() => {
|
|
10870
|
+
!disableColumnReorder && c.reorderable !== false && c.type !== "actions" && !pins.left.includes(c.field) && !pins.right.includes(c.field) && movableMidFields.length > 1 ? (() => {
|
|
10822
10871
|
const midIdx = movableMidFields.indexOf(c.field);
|
|
10823
|
-
const atFirst = midIdx
|
|
10824
|
-
const atLast = midIdx ===
|
|
10872
|
+
const atFirst = midIdx === 0;
|
|
10873
|
+
const atLast = midIdx === movableMidFields.length - 1;
|
|
10825
10874
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
10826
10875
|
/* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", disabled: atFirst, "aria-disabled": atFirst || void 0, onClick: () => {
|
|
10827
10876
|
moveCol(c.field, -1);
|
|
@@ -10857,7 +10906,7 @@ function Datatable({
|
|
|
10857
10906
|
pins.right.includes(c.field) ? "Unpin" : "Pin to right"
|
|
10858
10907
|
] })
|
|
10859
10908
|
] }) : null,
|
|
10860
|
-
c.type !== "actions" ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", "data-active": wrapped.has(c.field) || void 0, onClick: () => {
|
|
10909
|
+
c.type !== "actions" && c.wrappable !== false ? /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", role: "menuitem", className: "twc-dt__mi", "data-active": wrapped.has(c.field) || void 0, onClick: () => {
|
|
10861
10910
|
toggleWrap(c.field);
|
|
10862
10911
|
close();
|
|
10863
10912
|
}, children: [
|
|
@@ -11274,6 +11323,474 @@ function Datatable({
|
|
|
11274
11323
|
] }) : null
|
|
11275
11324
|
] });
|
|
11276
11325
|
}
|
|
11326
|
+
function space(v) {
|
|
11327
|
+
if (v == null) return void 0;
|
|
11328
|
+
if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
|
|
11329
|
+
return v;
|
|
11330
|
+
}
|
|
11331
|
+
function len(v) {
|
|
11332
|
+
return typeof v === "number" ? `${v}px` : v;
|
|
11333
|
+
}
|
|
11334
|
+
var BP = { sm: 640, md: 768, lg: 1024, xl: 1280 };
|
|
11335
|
+
function safeHref5(url) {
|
|
11336
|
+
if (url == null) return void 0;
|
|
11337
|
+
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
11338
|
+
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
11339
|
+
}
|
|
11340
|
+
var Grid = React51__namespace.default.forwardRef(function Grid2({
|
|
11341
|
+
as: Tag2 = "div",
|
|
11342
|
+
columns,
|
|
11343
|
+
minChildWidth,
|
|
11344
|
+
gap = 4,
|
|
11345
|
+
rowGap,
|
|
11346
|
+
columnGap,
|
|
11347
|
+
align,
|
|
11348
|
+
justify,
|
|
11349
|
+
justifyItems,
|
|
11350
|
+
alignContent,
|
|
11351
|
+
justifyContent,
|
|
11352
|
+
sx,
|
|
11353
|
+
className = "",
|
|
11354
|
+
style,
|
|
11355
|
+
children,
|
|
11356
|
+
...rest
|
|
11357
|
+
}, ref) {
|
|
11358
|
+
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
11359
|
+
const responsive = columns != null && typeof columns === "object";
|
|
11360
|
+
const uid = React51__namespace.default.useId();
|
|
11361
|
+
const gridId = responsive ? `g${uid.replace(/[^a-zA-Z0-9]/g, "")}` : null;
|
|
11362
|
+
let css = "";
|
|
11363
|
+
if (responsive) {
|
|
11364
|
+
const base = columns.base ?? 1;
|
|
11365
|
+
const sel = `[data-twc-grid-id="${gridId}"]`;
|
|
11366
|
+
css = `${sel} { --twc-grid-cols: ${base}; }`;
|
|
11367
|
+
for (const bp of ["sm", "md", "lg", "xl"]) {
|
|
11368
|
+
if (columns[bp] != null) css += `
|
|
11369
|
+
@media (min-width: ${BP[bp]}px) { ${sel} { --twc-grid-cols: ${columns[bp]}; } }`;
|
|
11370
|
+
}
|
|
11371
|
+
}
|
|
11372
|
+
const __twcStyles = useScopedStyles(gridId ? `twc-grid-${gridId}` : "twc-grid", css);
|
|
11373
|
+
const templateColumns = minChildWidth ? `repeat(auto-fill, minmax(min(${len(minChildWidth)}, 100%), 1fr))` : responsive ? `repeat(var(--twc-grid-cols, ${columns.base ?? 1}), minmax(0, 1fr))` : `repeat(${columns || 1}, minmax(0, 1fr))`;
|
|
11374
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref5(rest.href);
|
|
11375
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
11376
|
+
Tag2,
|
|
11377
|
+
{
|
|
11378
|
+
ref,
|
|
11379
|
+
className: `twc-grid ${className}`.trim(),
|
|
11380
|
+
"data-twc-grid-id": gridId || void 0,
|
|
11381
|
+
"data-twc-sx": sxAttr,
|
|
11382
|
+
style: {
|
|
11383
|
+
display: "grid",
|
|
11384
|
+
gridTemplateColumns: templateColumns,
|
|
11385
|
+
rowGap: space(rowGap ?? gap),
|
|
11386
|
+
columnGap: space(columnGap ?? gap),
|
|
11387
|
+
alignItems: align,
|
|
11388
|
+
// #216: `justifyItems` is the explicit, correctly-named prop; `justify` remains a
|
|
11389
|
+
// backward-compatible alias for it (note: on Grid `justify` = justify-**items**, unlike
|
|
11390
|
+
// Stack.justify = justify-**content**). The explicit prop wins when both are set.
|
|
11391
|
+
justifyItems: justifyItems ?? justify,
|
|
11392
|
+
alignContent,
|
|
11393
|
+
justifyContent,
|
|
11394
|
+
...style,
|
|
11395
|
+
...flatStyle
|
|
11396
|
+
},
|
|
11397
|
+
...rest,
|
|
11398
|
+
children: [
|
|
11399
|
+
responsive ? __twcStyles : null,
|
|
11400
|
+
styleNode,
|
|
11401
|
+
children
|
|
11402
|
+
]
|
|
11403
|
+
}
|
|
11404
|
+
);
|
|
11405
|
+
});
|
|
11406
|
+
Grid.displayName = "Grid";
|
|
11407
|
+
var CARDGRID_CSS = `
|
|
11408
|
+
.twc-cardgrid { font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-3); }
|
|
11409
|
+
.twc-cardgrid__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); }
|
|
11410
|
+
.twc-cardgrid__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
|
|
11411
|
+
.twc-cardgrid__search { flex: 1 1 200px; min-width: 160px; }
|
|
11412
|
+
.twc-cardgrid__spacer { flex: 1 1 auto; }
|
|
11413
|
+
.twc-cardgrid__sort { display: inline-flex; align-items: center; gap: var(--space-1); flex: none; }
|
|
11414
|
+
.twc-cardgrid__dir { display: inline-grid; place-items: center; width: 32px; height: 32px; border: var(--border-thin) solid var(--color-border); background: var(--color-surface); color: var(--color-text-muted); cursor: pointer; border-radius: var(--radius-md); transition: background-color var(--duration-fast), color var(--duration-fast); }
|
|
11415
|
+
.twc-cardgrid__dir:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
11416
|
+
.twc-cardgrid__dir svg { width: 16px; height: 16px; transition: transform var(--duration-fast) var(--ease-standard); }
|
|
11417
|
+
.twc-cardgrid__dir[data-dir="desc"] svg { transform: scaleY(-1); }
|
|
11418
|
+
.twc-cardgrid__body { position: relative; min-height: 60px; }
|
|
11419
|
+
.twc-cardgrid__body[data-loading="true"] .twc-cardgrid__grid { opacity: 0.55; pointer-events: none; }
|
|
11420
|
+
.twc-cardgrid__overlay { position: absolute; inset: 0; display: grid; place-items: center; z-index: 1; }
|
|
11421
|
+
.twc-cardgrid__spinner { width: 26px; height: 26px; border: 3px solid var(--color-border); border-top-color: var(--color-primary); border-radius: var(--radius-full); animation: twc-cardgrid-spin 0.7s linear infinite; }
|
|
11422
|
+
@keyframes twc-cardgrid-spin { to { transform: rotate(360deg); } }
|
|
11423
|
+
@media (prefers-reduced-motion: reduce) { .twc-cardgrid__spinner { animation-duration: 1.6s; } }
|
|
11424
|
+
.twc-cardgrid__empty { padding: var(--space-8) var(--space-4); text-align: center; color: var(--color-text-muted); font-size: var(--text-sm); }
|
|
11425
|
+
.twc-cardgrid__footer { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: var(--space-2); }
|
|
11426
|
+
.twc-cardgrid__count { font-size: var(--text-sm); color: var(--color-text-muted); }
|
|
11427
|
+
.twc-cardgrid__perpage { display: inline-flex; align-items: center; gap: var(--space-2); font-size: var(--text-sm); color: var(--color-text-muted); }
|
|
11428
|
+
`;
|
|
11429
|
+
function CardGrid({
|
|
11430
|
+
rows = [],
|
|
11431
|
+
renderCard,
|
|
11432
|
+
rowKey = "id",
|
|
11433
|
+
minChildWidth = "18rem",
|
|
11434
|
+
gap = 4,
|
|
11435
|
+
columns,
|
|
11436
|
+
// pagination
|
|
11437
|
+
pageSize = 12,
|
|
11438
|
+
pageSizeOptions = [12, 24, 48, 96],
|
|
11439
|
+
page,
|
|
11440
|
+
defaultPage = 0,
|
|
11441
|
+
onPageChange,
|
|
11442
|
+
onPageSizeChange,
|
|
11443
|
+
showPageSize = true,
|
|
11444
|
+
// query / server contract (mirrors Datatable serverMode)
|
|
11445
|
+
serverMode = false,
|
|
11446
|
+
rowCount,
|
|
11447
|
+
loading = false,
|
|
11448
|
+
onServerChange,
|
|
11449
|
+
// filtering & sorting
|
|
11450
|
+
filters = [],
|
|
11451
|
+
quickFilter,
|
|
11452
|
+
defaultQuickFilter = "",
|
|
11453
|
+
onQuickFilterChange,
|
|
11454
|
+
searchable = false,
|
|
11455
|
+
searchFields,
|
|
11456
|
+
searchPlaceholder = "Search\u2026",
|
|
11457
|
+
sort,
|
|
11458
|
+
defaultSort = null,
|
|
11459
|
+
onSortChange,
|
|
11460
|
+
sortOptions,
|
|
11461
|
+
sortMinWidth,
|
|
11462
|
+
// slots / states
|
|
11463
|
+
toolbar,
|
|
11464
|
+
emptyState = "No results.",
|
|
11465
|
+
label,
|
|
11466
|
+
id,
|
|
11467
|
+
className = "",
|
|
11468
|
+
...rest
|
|
11469
|
+
}) {
|
|
11470
|
+
const styles = useScopedStyles("twc-cardgrid-styles", CARDGRID_CSS);
|
|
11471
|
+
const autoId = React51__namespace.default.useId();
|
|
11472
|
+
const fieldId = id || autoId;
|
|
11473
|
+
const [internalPage, setInternalPage] = React51__namespace.default.useState(defaultPage);
|
|
11474
|
+
const pageVal = page !== void 0 ? page : internalPage;
|
|
11475
|
+
const commitPage = (p) => {
|
|
11476
|
+
onPageChange?.(p);
|
|
11477
|
+
if (page === void 0) setInternalPage(p);
|
|
11478
|
+
};
|
|
11479
|
+
const [internalSize, setInternalSize] = React51__namespace.default.useState(pageSize > 0 ? pageSize : 12);
|
|
11480
|
+
const sizeControlled = onPageSizeChange !== void 0;
|
|
11481
|
+
const sizeVal = sizeControlled ? pageSize > 0 ? pageSize : 12 : internalSize;
|
|
11482
|
+
const commitSize = (n) => {
|
|
11483
|
+
onPageSizeChange?.(n);
|
|
11484
|
+
if (!sizeControlled) setInternalSize(n);
|
|
11485
|
+
commitPage(0);
|
|
11486
|
+
};
|
|
11487
|
+
React51__namespace.default.useEffect(() => {
|
|
11488
|
+
if (!sizeControlled) setInternalSize(pageSize > 0 ? pageSize : 12);
|
|
11489
|
+
}, [pageSize]);
|
|
11490
|
+
const [internalQuick, setInternalQuick] = React51__namespace.default.useState(defaultQuickFilter);
|
|
11491
|
+
const quickVal = quickFilter !== void 0 ? quickFilter : internalQuick;
|
|
11492
|
+
const commitQuick = (q) => {
|
|
11493
|
+
onQuickFilterChange?.(q);
|
|
11494
|
+
if (quickFilter === void 0) setInternalQuick(q);
|
|
11495
|
+
commitPage(0);
|
|
11496
|
+
};
|
|
11497
|
+
const [internalSort, setInternalSort] = React51__namespace.default.useState(defaultSort);
|
|
11498
|
+
const sortVal = sort !== void 0 ? sort : internalSort;
|
|
11499
|
+
const commitSort = (s) => {
|
|
11500
|
+
onSortChange?.(s);
|
|
11501
|
+
if (sort === void 0) setInternalSort(s);
|
|
11502
|
+
commitPage(0);
|
|
11503
|
+
};
|
|
11504
|
+
const filtersKey = JSON.stringify(filters);
|
|
11505
|
+
const mounted = React51__namespace.default.useRef(false);
|
|
11506
|
+
React51__namespace.default.useEffect(() => {
|
|
11507
|
+
if (!mounted.current) {
|
|
11508
|
+
mounted.current = true;
|
|
11509
|
+
return;
|
|
11510
|
+
}
|
|
11511
|
+
commitPage(0);
|
|
11512
|
+
}, [filtersKey]);
|
|
11513
|
+
const paginated = sizeVal > 0;
|
|
11514
|
+
const query = { page: pageVal, pageSize: paginated ? sizeVal : 0, sort: sortVal, filters, quickFilter: String(quickVal || "").trim() };
|
|
11515
|
+
const queryCols = sortOptions ? sortOptions.map((o) => ({ field: o.field, type: o.type })) : columns;
|
|
11516
|
+
const client = serverMode ? null : runDatatableQuery(rows, query, { columns: queryCols, searchFields });
|
|
11517
|
+
const pageRows = serverMode ? rows : client.rows;
|
|
11518
|
+
const total = serverMode ? rowCount == null ? rows.length : rowCount : client.total;
|
|
11519
|
+
const totalPages = Math.max(1, paginated ? Math.ceil(total / sizeVal) : 1);
|
|
11520
|
+
const onServerChangeRef = React51__namespace.default.useRef(onServerChange);
|
|
11521
|
+
onServerChangeRef.current = onServerChange;
|
|
11522
|
+
const queryKey = JSON.stringify(query);
|
|
11523
|
+
React51__namespace.default.useEffect(() => {
|
|
11524
|
+
if (!serverMode) return void 0;
|
|
11525
|
+
const t = setTimeout(() => onServerChangeRef.current?.(JSON.parse(queryKey)), 250);
|
|
11526
|
+
return () => clearTimeout(t);
|
|
11527
|
+
}, [serverMode, queryKey]);
|
|
11528
|
+
const keyOf = typeof rowKey === "function" ? rowKey : (r2) => r2 && r2[rowKey];
|
|
11529
|
+
const from = total === 0 ? 0 : pageVal * sizeVal + 1;
|
|
11530
|
+
const to = paginated ? Math.min((pageVal + 1) * sizeVal, total) : total;
|
|
11531
|
+
const rppOptions = Array.from(new Set([...pageSizeOptions || [], pageSize].filter((n) => n > 0))).sort((a, b) => a - b).map((n) => ({ value: String(n), label: String(n) }));
|
|
11532
|
+
const sortSelectOptions = sortOptions ? [{ value: "", label: "Sort by\u2026" }, ...sortOptions.map((o) => ({ value: o.field, label: o.label || o.field }))] : null;
|
|
11533
|
+
const sortAutoWidth = sortSelectOptions ? Math.min(300, Math.max(120, Math.ceil(Math.max(...sortSelectOptions.map((o) => String(o.label).length)) * 7.2) + 46)) : void 0;
|
|
11534
|
+
const sortWidth = sortMinWidth != null ? sortMinWidth : sortAutoWidth;
|
|
11535
|
+
const hasToolbar = searchable || sortSelectOptions || toolbar;
|
|
11536
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-cardgrid ${className}`, id: fieldId, ...rest, children: [
|
|
11537
|
+
styles,
|
|
11538
|
+
label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__label", id: `${fieldId}-label`, children: label }) : null,
|
|
11539
|
+
hasToolbar ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-cardgrid__toolbar", children: [
|
|
11540
|
+
searchable ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__search", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
11541
|
+
Input,
|
|
11542
|
+
{
|
|
11543
|
+
size: "sm",
|
|
11544
|
+
type: "search",
|
|
11545
|
+
value: quickVal,
|
|
11546
|
+
placeholder: searchPlaceholder,
|
|
11547
|
+
"aria-label": searchPlaceholder,
|
|
11548
|
+
onChange: (e) => commitQuick(e.target.value)
|
|
11549
|
+
}
|
|
11550
|
+
) }) : null,
|
|
11551
|
+
toolbar,
|
|
11552
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__spacer" }),
|
|
11553
|
+
sortSelectOptions ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-cardgrid__sort", children: [
|
|
11554
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11555
|
+
Select,
|
|
11556
|
+
{
|
|
11557
|
+
size: "sm",
|
|
11558
|
+
searchable: false,
|
|
11559
|
+
value: sortVal?.field || "",
|
|
11560
|
+
options: sortSelectOptions,
|
|
11561
|
+
placeholder: "Sort by\u2026",
|
|
11562
|
+
style: { minWidth: sortWidth },
|
|
11563
|
+
"aria-label": "Sort by",
|
|
11564
|
+
onChange: (field) => commitSort(field ? { field, dir: sortVal?.dir || "asc" } : null)
|
|
11565
|
+
}
|
|
11566
|
+
),
|
|
11567
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11568
|
+
"button",
|
|
11569
|
+
{
|
|
11570
|
+
type: "button",
|
|
11571
|
+
className: "twc-cardgrid__dir",
|
|
11572
|
+
"data-dir": sortVal?.dir || "asc",
|
|
11573
|
+
disabled: !sortVal?.field,
|
|
11574
|
+
"aria-label": sortVal?.dir === "desc" ? "Descending \u2014 click to sort ascending" : "Ascending \u2014 click to sort descending",
|
|
11575
|
+
onClick: () => sortVal?.field && commitSort({ field: sortVal.field, dir: sortVal.dir === "desc" ? "asc" : "desc" }),
|
|
11576
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 5v14M6 11l6-6 6 6" }) })
|
|
11577
|
+
}
|
|
11578
|
+
)
|
|
11579
|
+
] }) : null
|
|
11580
|
+
] }) : null,
|
|
11581
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-cardgrid__body", "data-loading": loading || void 0, "aria-busy": loading || void 0, children: [
|
|
11582
|
+
loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__overlay", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__spinner", role: "status", "aria-label": "Loading" }) }) : null,
|
|
11583
|
+
pageRows.length === 0 && !loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-cardgrid__empty", children: emptyState }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
11584
|
+
Grid,
|
|
11585
|
+
{
|
|
11586
|
+
className: "twc-cardgrid__grid",
|
|
11587
|
+
minChildWidth,
|
|
11588
|
+
columns,
|
|
11589
|
+
gap,
|
|
11590
|
+
role: "list",
|
|
11591
|
+
"aria-labelledby": label ? `${fieldId}-label` : void 0,
|
|
11592
|
+
children: pageRows.map((row, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { role: "listitem", children: renderCard(row, i) }, keyOf(row, i) ?? i))
|
|
11593
|
+
}
|
|
11594
|
+
)
|
|
11595
|
+
] }),
|
|
11596
|
+
paginated && totalPages > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-cardgrid__footer", children: [
|
|
11597
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-cardgrid__count", children: total === 0 ? "No results" : `${from}\u2013${to} of ${total}` }),
|
|
11598
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11599
|
+
Pagination,
|
|
11600
|
+
{
|
|
11601
|
+
size: "sm",
|
|
11602
|
+
page: pageVal + 1,
|
|
11603
|
+
total: totalPages,
|
|
11604
|
+
boundaries: 1,
|
|
11605
|
+
siblings: 1,
|
|
11606
|
+
showPageJumper: totalPages > 7,
|
|
11607
|
+
onChange: (p) => commitPage(p - 1)
|
|
11608
|
+
}
|
|
11609
|
+
),
|
|
11610
|
+
showPageSize ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-cardgrid__perpage", children: [
|
|
11611
|
+
"Per page",
|
|
11612
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11613
|
+
Select,
|
|
11614
|
+
{
|
|
11615
|
+
size: "sm",
|
|
11616
|
+
searchable: false,
|
|
11617
|
+
value: String(sizeVal),
|
|
11618
|
+
options: rppOptions,
|
|
11619
|
+
placement: "top",
|
|
11620
|
+
"aria-label": "Cards per page",
|
|
11621
|
+
onChange: (v) => commitSize(Number(v))
|
|
11622
|
+
}
|
|
11623
|
+
)
|
|
11624
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx("span", {})
|
|
11625
|
+
] }) : null
|
|
11626
|
+
] });
|
|
11627
|
+
}
|
|
11628
|
+
var DIFFTABLE_CSS = `
|
|
11629
|
+
.twc-difft { font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-3); color: var(--color-text); }
|
|
11630
|
+
.twc-difft__head { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
|
|
11631
|
+
.twc-difft__label { font-size: var(--text-sm); font-weight: var(--font-semibold); }
|
|
11632
|
+
.twc-difft__summary { display: inline-flex; flex-wrap: wrap; gap: var(--space-1-5); }
|
|
11633
|
+
.twc-difft__toggle { margin-inline-start: auto; }
|
|
11634
|
+
.twc-difft__scroll { overflow-x: auto; border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-lg); }
|
|
11635
|
+
.twc-difft__table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); }
|
|
11636
|
+
.twc-difft__table th, .twc-difft__table td { text-align: start; padding: var(--space-2) var(--space-3); border-bottom: var(--border-thin) solid var(--color-divider); vertical-align: top; }
|
|
11637
|
+
.twc-difft__table thead th { position: sticky; top: 0; background: var(--color-surface-sunken); font-weight: var(--font-semibold); color: var(--color-text-muted); font-size: var(--text-xs); text-transform: uppercase; letter-spacing: 0.02em; white-space: nowrap; z-index: 1; }
|
|
11638
|
+
.twc-difft__table tbody tr:last-child td { border-bottom: none; }
|
|
11639
|
+
.twc-difft__table tbody tr[data-op="added"] { background: color-mix(in srgb, var(--color-success) 8%, transparent); }
|
|
11640
|
+
.twc-difft__table tbody tr[data-op="removed"] { background: color-mix(in srgb, var(--color-danger) 8%, transparent); }
|
|
11641
|
+
.twc-difft__table tbody tr[data-op="modified"] { background: color-mix(in srgb, var(--color-warning) 8%, transparent); }
|
|
11642
|
+
.twc-difft__op { white-space: nowrap; }
|
|
11643
|
+
.twc-difft__change { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 2px; }
|
|
11644
|
+
.twc-difft__old { text-decoration: line-through; color: var(--color-text-subtle); }
|
|
11645
|
+
.twc-difft__new { color: var(--color-success-subtle-fg); font-weight: var(--font-medium); }
|
|
11646
|
+
.twc-difft__arrow { margin-inline: 6px; color: var(--color-text-subtle); }
|
|
11647
|
+
.twc-difft__empty { padding: var(--space-8) var(--space-4); text-align: center; color: var(--color-text-muted); }
|
|
11648
|
+
[dir="rtl"] .twc-difft__arrow { transform: scaleX(-1); display: inline-block; }
|
|
11649
|
+
`;
|
|
11650
|
+
var OPS = {
|
|
11651
|
+
added: { label: "Added", tone: "success" },
|
|
11652
|
+
removed: { label: "Removed", tone: "danger" },
|
|
11653
|
+
modified: { label: "Modified", tone: "warning" },
|
|
11654
|
+
moved: { label: "Moved", tone: "info" },
|
|
11655
|
+
unchanged: { label: "Unchanged", tone: "neutral" }
|
|
11656
|
+
};
|
|
11657
|
+
function lisIndexSet(seq) {
|
|
11658
|
+
const n = seq.length;
|
|
11659
|
+
if (n === 0) return /* @__PURE__ */ new Set();
|
|
11660
|
+
const dp = new Array(n).fill(1), prev = new Array(n).fill(-1);
|
|
11661
|
+
let best = 0;
|
|
11662
|
+
for (let i = 0; i < n; i++) {
|
|
11663
|
+
for (let j = 0; j < i; j++) {
|
|
11664
|
+
if (seq[j] < seq[i] && dp[j] + 1 > dp[i]) {
|
|
11665
|
+
dp[i] = dp[j] + 1;
|
|
11666
|
+
prev[i] = j;
|
|
11667
|
+
}
|
|
11668
|
+
}
|
|
11669
|
+
if (dp[i] > dp[best]) best = i;
|
|
11670
|
+
}
|
|
11671
|
+
const set = /* @__PURE__ */ new Set();
|
|
11672
|
+
for (let i = best; i !== -1; i = prev[i]) set.add(i);
|
|
11673
|
+
return set;
|
|
11674
|
+
}
|
|
11675
|
+
var getVal = (col, row) => col.valueGetter ? col.valueGetter(row) : row == null ? void 0 : row[col.field];
|
|
11676
|
+
var fmtVal = (col, v) => col.valueFormatter ? col.valueFormatter(v) : v == null ? "" : String(v);
|
|
11677
|
+
function DiffTable({
|
|
11678
|
+
from = [],
|
|
11679
|
+
to = [],
|
|
11680
|
+
rowKey,
|
|
11681
|
+
columns = [],
|
|
11682
|
+
onlyChanged = true,
|
|
11683
|
+
showToggle = true,
|
|
11684
|
+
showSummary = true,
|
|
11685
|
+
moveDetection = true,
|
|
11686
|
+
compare,
|
|
11687
|
+
emptyState = "No differences.",
|
|
11688
|
+
toggleLabel = "Only changed",
|
|
11689
|
+
label,
|
|
11690
|
+
id,
|
|
11691
|
+
className = "",
|
|
11692
|
+
...rest
|
|
11693
|
+
}) {
|
|
11694
|
+
const styles = useScopedStyles("twc-difftable-styles", DIFFTABLE_CSS);
|
|
11695
|
+
const autoId = React51__namespace.default.useId();
|
|
11696
|
+
const fieldId = id || autoId;
|
|
11697
|
+
const [only, setOnly] = React51__namespace.default.useState(onlyChanged);
|
|
11698
|
+
const valEq = React51__namespace.default.useCallback((a, b, col) => {
|
|
11699
|
+
if (col.compare) return col.compare(a, b);
|
|
11700
|
+
if (compare) return compare(a, b, col.field);
|
|
11701
|
+
if (a === b) return true;
|
|
11702
|
+
if (a == null || b == null) return a === b;
|
|
11703
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
11704
|
+
}, [compare]);
|
|
11705
|
+
const diff = React51__namespace.default.useMemo(() => {
|
|
11706
|
+
const k = rowKey || ((r2) => r2 == null ? r2 : r2.id);
|
|
11707
|
+
const fromMap = /* @__PURE__ */ new Map(), toMap = /* @__PURE__ */ new Map();
|
|
11708
|
+
from.forEach((r2, i) => fromMap.set(k(r2), { row: r2, i }));
|
|
11709
|
+
to.forEach((r2, i) => toMap.set(k(r2), { row: r2, i }));
|
|
11710
|
+
const movedKeys = /* @__PURE__ */ new Set();
|
|
11711
|
+
if (moveDetection) {
|
|
11712
|
+
const commonFrom = from.filter((r2) => toMap.has(k(r2)));
|
|
11713
|
+
const seq = commonFrom.map((r2) => toMap.get(k(r2)).i);
|
|
11714
|
+
const stable = lisIndexSet(seq);
|
|
11715
|
+
commonFrom.forEach((r2, idx) => {
|
|
11716
|
+
if (!stable.has(idx)) movedKeys.add(k(r2));
|
|
11717
|
+
});
|
|
11718
|
+
}
|
|
11719
|
+
const classify = (key) => {
|
|
11720
|
+
const a = fromMap.get(key), b = toMap.get(key);
|
|
11721
|
+
if (a && !b) return { op: "removed", from: a.row, to: null, changed: /* @__PURE__ */ new Set() };
|
|
11722
|
+
if (!a && b) return { op: "added", from: null, to: b.row, changed: /* @__PURE__ */ new Set() };
|
|
11723
|
+
const changed = /* @__PURE__ */ new Set();
|
|
11724
|
+
for (const col of columns) if (!valEq(getVal(col, a.row), getVal(col, b.row), col)) changed.add(col.field);
|
|
11725
|
+
if (changed.size) return { op: "modified", from: a.row, to: b.row, changed };
|
|
11726
|
+
if (movedKeys.has(key)) return { op: "moved", from: a.row, to: b.row, changed };
|
|
11727
|
+
return { op: "unchanged", from: a.row, to: b.row, changed };
|
|
11728
|
+
};
|
|
11729
|
+
const rows = [];
|
|
11730
|
+
to.forEach((r2) => rows.push({ key: k(r2), ...classify(k(r2)) }));
|
|
11731
|
+
from.forEach((r2) => {
|
|
11732
|
+
const key = k(r2);
|
|
11733
|
+
if (!toMap.has(key)) rows.push({ key, ...classify(key) });
|
|
11734
|
+
});
|
|
11735
|
+
const counts = { added: 0, removed: 0, modified: 0, moved: 0, unchanged: 0 };
|
|
11736
|
+
rows.forEach((r2) => {
|
|
11737
|
+
counts[r2.op] += 1;
|
|
11738
|
+
});
|
|
11739
|
+
return { rows, counts };
|
|
11740
|
+
}, [from, to, columns, rowKey, moveDetection, valEq]);
|
|
11741
|
+
const visible = only ? diff.rows.filter((r2) => r2.op !== "unchanged") : diff.rows;
|
|
11742
|
+
const renderCell = (r2, col) => {
|
|
11743
|
+
if (r2.op === "removed") return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__old", children: fmtVal(col, getVal(col, r2.from)) });
|
|
11744
|
+
if (r2.op === "added") return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__new", children: fmtVal(col, getVal(col, r2.to)) });
|
|
11745
|
+
if (r2.op === "modified" && r2.changed.has(col.field)) {
|
|
11746
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-difft__change", children: [
|
|
11747
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__old", children: fmtVal(col, getVal(col, r2.from)) }),
|
|
11748
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__arrow", "aria-hidden": "true", children: "\u2192" }),
|
|
11749
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-difft__new", children: fmtVal(col, getVal(col, r2.to)) })
|
|
11750
|
+
] });
|
|
11751
|
+
}
|
|
11752
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: fmtVal(col, getVal(col, r2.to ?? r2.from)) });
|
|
11753
|
+
};
|
|
11754
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-difft ${className}`, id: fieldId, ...rest, children: [
|
|
11755
|
+
styles,
|
|
11756
|
+
label || showSummary || showToggle ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-difft__head", children: [
|
|
11757
|
+
label ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__label", children: label }) : null,
|
|
11758
|
+
showSummary ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-difft__summary", children: [
|
|
11759
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "success", children: [
|
|
11760
|
+
"+",
|
|
11761
|
+
diff.counts.added,
|
|
11762
|
+
" added"
|
|
11763
|
+
] }),
|
|
11764
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "warning", children: [
|
|
11765
|
+
"~",
|
|
11766
|
+
diff.counts.modified,
|
|
11767
|
+
" modified"
|
|
11768
|
+
] }),
|
|
11769
|
+
/* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "danger", children: [
|
|
11770
|
+
"-",
|
|
11771
|
+
diff.counts.removed,
|
|
11772
|
+
" removed"
|
|
11773
|
+
] }),
|
|
11774
|
+
diff.counts.moved ? /* @__PURE__ */ jsxRuntime.jsxs(Badge, { size: "sm", variant: "soft", tone: "info", children: [
|
|
11775
|
+
"\u21C5 ",
|
|
11776
|
+
diff.counts.moved,
|
|
11777
|
+
" moved"
|
|
11778
|
+
] }) : null
|
|
11779
|
+
] }) : null,
|
|
11780
|
+
showToggle ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__toggle", children: /* @__PURE__ */ jsxRuntime.jsx(Checkbox, { label: toggleLabel, checked: only, onChange: (e) => setOnly(e.target.checked) }) }) : null
|
|
11781
|
+
] }) : null,
|
|
11782
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-difft__scroll", children: /* @__PURE__ */ jsxRuntime.jsxs("table", { className: "twc-difft__table", children: [
|
|
11783
|
+
/* @__PURE__ */ jsxRuntime.jsx("thead", { children: /* @__PURE__ */ jsxRuntime.jsxs("tr", { children: [
|
|
11784
|
+
/* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: "Change" }),
|
|
11785
|
+
columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("th", { scope: "col", children: c.headerName || c.field }, c.field))
|
|
11786
|
+
] }) }),
|
|
11787
|
+
/* @__PURE__ */ jsxRuntime.jsx("tbody", { children: visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-difft__empty", colSpan: columns.length + 1, children: emptyState }) }) : visible.map((r2) => /* @__PURE__ */ jsxRuntime.jsxs("tr", { "data-op": r2.op, children: [
|
|
11788
|
+
/* @__PURE__ */ jsxRuntime.jsx("td", { className: "twc-difft__op", children: /* @__PURE__ */ jsxRuntime.jsx(Badge, { size: "sm", variant: "soft", tone: OPS[r2.op].tone, children: OPS[r2.op].label }) }),
|
|
11789
|
+
columns.map((c) => /* @__PURE__ */ jsxRuntime.jsx("td", { children: renderCell(r2, c) }, c.field))
|
|
11790
|
+
] }, r2.key)) })
|
|
11791
|
+
] }) })
|
|
11792
|
+
] });
|
|
11793
|
+
}
|
|
11277
11794
|
var FIELD_CSS3 = `
|
|
11278
11795
|
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
11279
11796
|
.twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
|
|
@@ -11285,13 +11802,15 @@ var DATEPICKER_CSS = `
|
|
|
11285
11802
|
.twc-dp { position: relative; font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-1-5); }
|
|
11286
11803
|
.twc-dp__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); }
|
|
11287
11804
|
.twc-dp__control {
|
|
11288
|
-
display: flex; align-items: center; gap: var(--space-2);
|
|
11805
|
+
display: flex; align-items: center; gap: var(--space-2); --_h: var(--control-h-md); height: var(--_h); padding: 0 var(--space-3);
|
|
11289
11806
|
background: var(--color-surface); border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md);
|
|
11290
11807
|
cursor: pointer; transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard);
|
|
11291
11808
|
}
|
|
11292
11809
|
.twc-dp__control:hover:not([data-open="true"]) { border-color: var(--color-border-strong); }
|
|
11293
11810
|
/* tone \u2192 focus/open accent (default primary; reproduces current look). */
|
|
11294
11811
|
.twc-dp__control { --_accent: var(--color-primary); --_ring: var(--ring); }
|
|
11812
|
+
.twc-dp__control[data-size="sm"] { --_h: var(--control-h-sm); }
|
|
11813
|
+
.twc-dp__control[data-size="lg"] { --_h: var(--control-h-lg); }
|
|
11295
11814
|
.twc-dp__control[data-tone="success"] { --_accent: var(--color-success); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-success) 32%, transparent); }
|
|
11296
11815
|
.twc-dp__control[data-tone="warning"] { --_accent: var(--color-warning); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-warning) 32%, transparent); }
|
|
11297
11816
|
.twc-dp__control[data-tone="danger"] { --_accent: var(--color-danger); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-danger) 32%, transparent); }
|
|
@@ -11351,6 +11870,12 @@ var DATEPICKER_CSS = `
|
|
|
11351
11870
|
.twc-dp__mo { padding: 10px 0; border: none; background: transparent; cursor: pointer; font-family: inherit; font-size: var(--text-sm); color: var(--color-text); border-radius: var(--radius-md); }
|
|
11352
11871
|
.twc-dp__mo:hover { background: var(--color-surface-sunken); }
|
|
11353
11872
|
.twc-dp__mo[data-selected="true"] { background: var(--color-primary); color: var(--color-primary-fg); font-weight: var(--font-bold); }
|
|
11873
|
+
.twc-dp__years { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
|
|
11874
|
+
.twc-dp__yr { padding: 10px 0; border: none; background: transparent; cursor: pointer; font-family: inherit; font-size: var(--text-sm); color: var(--color-text); border-radius: var(--radius-md); }
|
|
11875
|
+
.twc-dp__yr:hover:not(:disabled) { background: var(--color-surface-sunken); }
|
|
11876
|
+
.twc-dp__yr[data-outside="true"] { color: var(--color-text-subtle); }
|
|
11877
|
+
.twc-dp__yr[data-selected="true"] { background: var(--color-primary); color: var(--color-primary-fg); font-weight: var(--font-bold); }
|
|
11878
|
+
.twc-dp__yr:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
11354
11879
|
[dir="rtl"] .twc-dp__nav svg { transform: scaleX(-1); }
|
|
11355
11880
|
`;
|
|
11356
11881
|
var MONTHS = ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"];
|
|
@@ -11378,8 +11903,10 @@ function DatePicker({
|
|
|
11378
11903
|
placeholder = "Select date",
|
|
11379
11904
|
min,
|
|
11380
11905
|
max,
|
|
11906
|
+
disabledDate,
|
|
11381
11907
|
disabled = false,
|
|
11382
11908
|
tone = "primary",
|
|
11909
|
+
size = "md",
|
|
11383
11910
|
clearable = true,
|
|
11384
11911
|
editable = false,
|
|
11385
11912
|
parse,
|
|
@@ -11404,6 +11931,7 @@ function DatePicker({
|
|
|
11404
11931
|
const [mode, setMode] = React51__namespace.default.useState("days");
|
|
11405
11932
|
const [focusDate, setFocusDate] = React51__namespace.default.useState(null);
|
|
11406
11933
|
const [focusMonth, setFocusMonth] = React51__namespace.default.useState(null);
|
|
11934
|
+
const [focusYear, setFocusYear] = React51__namespace.default.useState(null);
|
|
11407
11935
|
const [editText, setEditText] = React51__namespace.default.useState(null);
|
|
11408
11936
|
const [coords, setCoords] = React51__namespace.default.useState(null);
|
|
11409
11937
|
const wrapRef = React51__namespace.default.useRef(null);
|
|
@@ -11496,11 +12024,13 @@ function DatePicker({
|
|
|
11496
12024
|
pick(parsed);
|
|
11497
12025
|
};
|
|
11498
12026
|
const y = view.getFullYear(), m = view.getMonth();
|
|
12027
|
+
const decadeStart = Math.floor(y / 10) * 10;
|
|
12028
|
+
const yearCells = Array.from({ length: 12 }, (_, i) => decadeStart - 1 + i);
|
|
11499
12029
|
const first = new Date(y, m, 1);
|
|
11500
12030
|
const startOffset = (first.getDay() - weekStartsOn + 7) % 7;
|
|
11501
12031
|
const gridStart = new Date(y, m, 1 - startOffset);
|
|
11502
12032
|
const today = /* @__PURE__ */ new Date();
|
|
11503
|
-
const outOfRange = (d) => min && d < new Date(min.getFullYear(), min.getMonth(), min.getDate()) || max && d > new Date(max.getFullYear(), max.getMonth(), max.getDate());
|
|
12033
|
+
const outOfRange = (d) => min && d < new Date(min.getFullYear(), min.getMonth(), min.getDate()) || max && d > new Date(max.getFullYear(), max.getMonth(), max.getDate()) || Boolean(disabledDate && disabledDate(d));
|
|
11504
12034
|
const keyOf = (d) => `${d.getFullYear()}-${d.getMonth()}-${d.getDate()}`;
|
|
11505
12035
|
const addDays = (d, n) => new Date(d.getFullYear(), d.getMonth(), d.getDate() + n);
|
|
11506
12036
|
const addMonths = (d, n) => {
|
|
@@ -11537,6 +12067,24 @@ function DatePicker({
|
|
|
11537
12067
|
}
|
|
11538
12068
|
setFocusMonth(next);
|
|
11539
12069
|
};
|
|
12070
|
+
React51__namespace.default.useEffect(() => {
|
|
12071
|
+
if (!open || mode !== "years" || focusYear == null) return;
|
|
12072
|
+
gridRef.current?.querySelector(`[data-yr="${focusYear}"]`)?.focus();
|
|
12073
|
+
}, [focusYear, open, mode]);
|
|
12074
|
+
const onYearsKeyDown = (e) => {
|
|
12075
|
+
const cur = focusYear == null ? y : focusYear;
|
|
12076
|
+
let next;
|
|
12077
|
+
if (e.key === "ArrowRight") next = cur + 1;
|
|
12078
|
+
else if (e.key === "ArrowLeft") next = cur - 1;
|
|
12079
|
+
else if (e.key === "ArrowDown") next = cur + 3;
|
|
12080
|
+
else if (e.key === "ArrowUp") next = cur - 3;
|
|
12081
|
+
else if (e.key === "Home") next = decadeStart;
|
|
12082
|
+
else if (e.key === "End") next = decadeStart + 9;
|
|
12083
|
+
else return;
|
|
12084
|
+
e.preventDefault();
|
|
12085
|
+
setView(new Date(next, m, 1));
|
|
12086
|
+
setFocusYear(next);
|
|
12087
|
+
};
|
|
11540
12088
|
const onGridKeyDown = (e) => {
|
|
11541
12089
|
const btn = e.target.closest?.("[data-key]");
|
|
11542
12090
|
if (!btn) return;
|
|
@@ -11581,6 +12129,7 @@ function DatePicker({
|
|
|
11581
12129
|
"data-disabled": disabled || void 0,
|
|
11582
12130
|
"data-tone": tone,
|
|
11583
12131
|
"data-invalid": invalid || void 0,
|
|
12132
|
+
"data-size": size,
|
|
11584
12133
|
children: [
|
|
11585
12134
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
11586
12135
|
"input",
|
|
@@ -11654,6 +12203,7 @@ function DatePicker({
|
|
|
11654
12203
|
id: fieldId,
|
|
11655
12204
|
"data-open": open || void 0,
|
|
11656
12205
|
"data-disabled": disabled || void 0,
|
|
12206
|
+
"data-size": size,
|
|
11657
12207
|
"data-tone": tone,
|
|
11658
12208
|
"data-has-clear": clearable && selected && !disabled ? "true" : void 0,
|
|
11659
12209
|
"data-invalid": invalid || void 0,
|
|
@@ -11697,13 +12247,18 @@ function DatePicker({
|
|
|
11697
12247
|
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
|
|
11698
12248
|
children: [
|
|
11699
12249
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dp__head", children: [
|
|
11700
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dp__nav", "aria-label": "Previous", onClick: () => setView(mode === "months" ? new Date(y - 1, m, 1) : new Date(y, m - 1, 1)), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
12250
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dp__nav", "aria-label": mode === "years" ? "Previous decade" : mode === "months" ? "Previous year" : "Previous month", onClick: () => setView(mode === "years" ? new Date(y - 10, m, 1) : mode === "months" ? new Date(y - 1, m, 1) : new Date(y, m - 1, 1)), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
11701
12251
|
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dp__title", onClick: () => {
|
|
11702
|
-
if (mode === "days")
|
|
11703
|
-
|
|
11704
|
-
|
|
11705
|
-
|
|
11706
|
-
|
|
12252
|
+
if (mode === "days") {
|
|
12253
|
+
setFocusMonth(m);
|
|
12254
|
+
setMode("months");
|
|
12255
|
+
} else if (mode === "months") {
|
|
12256
|
+
setFocusYear(y);
|
|
12257
|
+
setMode("years");
|
|
12258
|
+
} else setMode("days");
|
|
12259
|
+
}, children: mode === "days" ? `${months[m]} ${y}` : mode === "months" ? y : `${decadeStart}\u2013${decadeStart + 9}` }),
|
|
12260
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-dp__sr", "aria-live": "polite", children: mode === "days" ? `${months[m]} ${y}` : mode === "months" ? y : `${decadeStart}\u2013${decadeStart + 9}` }),
|
|
12261
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-dp__nav", "aria-label": mode === "years" ? "Next decade" : mode === "months" ? "Next year" : "Next month", onClick: () => setView(mode === "years" ? new Date(y + 10, m, 1) : mode === "months" ? new Date(y + 1, m, 1) : new Date(y, m + 1, 1)), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) }) })
|
|
11707
12262
|
] }),
|
|
11708
12263
|
mode === "days" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dp__grid", ref: gridRef, onKeyDown: onGridKeyDown, children: [
|
|
11709
12264
|
dows.map((d, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dp__dow", children: d }, i)),
|
|
@@ -11729,7 +12284,7 @@ function DatePicker({
|
|
|
11729
12284
|
i
|
|
11730
12285
|
);
|
|
11731
12286
|
})
|
|
11732
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dp__months", ref: gridRef, onKeyDown: onMonthsKeyDown, role: "grid", children: monthsShort.map((name, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
12287
|
+
] }) : mode === "months" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dp__months", ref: gridRef, onKeyDown: onMonthsKeyDown, role: "grid", children: monthsShort.map((name, i) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
11733
12288
|
"button",
|
|
11734
12289
|
{
|
|
11735
12290
|
type: "button",
|
|
@@ -11745,7 +12300,30 @@ function DatePicker({
|
|
|
11745
12300
|
children: name
|
|
11746
12301
|
},
|
|
11747
12302
|
i
|
|
11748
|
-
)) })
|
|
12303
|
+
)) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dp__years", ref: gridRef, onKeyDown: onYearsKeyDown, role: "grid", children: yearCells.map((yr) => {
|
|
12304
|
+
const outside = yr < decadeStart || yr > decadeStart + 9;
|
|
12305
|
+
const disabled2 = min && yr < min.getFullYear() || max && yr > max.getFullYear();
|
|
12306
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12307
|
+
"button",
|
|
12308
|
+
{
|
|
12309
|
+
type: "button",
|
|
12310
|
+
className: "twc-dp__yr",
|
|
12311
|
+
role: "gridcell",
|
|
12312
|
+
"data-yr": yr,
|
|
12313
|
+
"data-outside": outside || void 0,
|
|
12314
|
+
disabled: disabled2,
|
|
12315
|
+
"data-selected": selected && selected.getFullYear() === yr || void 0,
|
|
12316
|
+
tabIndex: yr === (focusYear ?? y) ? 0 : -1,
|
|
12317
|
+
onClick: () => {
|
|
12318
|
+
setView(new Date(yr, m, 1));
|
|
12319
|
+
setFocusMonth(m);
|
|
12320
|
+
setMode("months");
|
|
12321
|
+
},
|
|
12322
|
+
children: yr
|
|
12323
|
+
},
|
|
12324
|
+
yr
|
|
12325
|
+
);
|
|
12326
|
+
}) })
|
|
11749
12327
|
]
|
|
11750
12328
|
}
|
|
11751
12329
|
),
|
|
@@ -11764,12 +12342,14 @@ var FIELD_CSS4 = `
|
|
|
11764
12342
|
var RANGE_CSS2 = `
|
|
11765
12343
|
.twc-drp { position: relative; font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-1-5); }
|
|
11766
12344
|
.twc-drp__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); }
|
|
11767
|
-
.twc-drp__control { display: flex; align-items: center; gap: var(--space-2);
|
|
12345
|
+
.twc-drp__control { display: flex; align-items: center; gap: var(--space-2); --_h: var(--control-h-md); height: var(--_h); padding: 0 var(--space-3);
|
|
11768
12346
|
background: var(--color-surface); border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md); cursor: pointer;
|
|
11769
12347
|
transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); }
|
|
11770
12348
|
.twc-drp__control:hover:not([data-open="true"]):not([data-disabled="true"]) { border-color: var(--color-border-strong); }
|
|
11771
12349
|
/* tone \u2192 focus/open accent (default primary; reproduces current look). */
|
|
11772
12350
|
.twc-drp__control { --_accent: var(--color-primary); --_ring: var(--ring); }
|
|
12351
|
+
.twc-drp__control[data-size="sm"] { --_h: var(--control-h-sm); }
|
|
12352
|
+
.twc-drp__control[data-size="lg"] { --_h: var(--control-h-lg); }
|
|
11773
12353
|
.twc-drp__control[data-tone="success"] { --_accent: var(--color-success); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-success) 32%, transparent); }
|
|
11774
12354
|
.twc-drp__control[data-tone="warning"] { --_accent: var(--color-warning); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-warning) 32%, transparent); }
|
|
11775
12355
|
.twc-drp__control[data-tone="danger"] { --_accent: var(--color-danger); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-danger) 32%, transparent); }
|
|
@@ -11783,6 +12363,9 @@ var RANGE_CSS2 = `
|
|
|
11783
12363
|
.twc-drp__ic svg { width: 17px; height: 17px; }
|
|
11784
12364
|
.twc-drp__text { flex: 1; font-size: var(--text-sm); color: var(--color-text); white-space: nowrap; }
|
|
11785
12365
|
.twc-drp__text[data-placeholder="true"] { color: var(--color-text-subtle); }
|
|
12366
|
+
.twc-drp__clear { flex: none; display: inline-grid; place-items: center; width: 20px; height: 20px; border: none; padding: 0; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-full); }
|
|
12367
|
+
.twc-drp__clear:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
12368
|
+
.twc-drp__clear svg { width: 14px; height: 14px; }
|
|
11786
12369
|
/* #105: editable (typed entry) variant. */
|
|
11787
12370
|
.twc-drp__control--editable { cursor: text; gap: 0; padding-inline-end: var(--space-1); }
|
|
11788
12371
|
.twc-drp__input { flex: 1; min-width: 0; height: 100%; border: none; background: transparent; outline: none; padding: 0;
|
|
@@ -11806,7 +12389,14 @@ var RANGE_CSS2 = `
|
|
|
11806
12389
|
.twc-drp__nav { display: inline-grid; place-items: center; width: 30px; height: 30px; border: none; background: transparent; color: var(--color-text-muted); cursor: pointer; border-radius: var(--radius-md); }
|
|
11807
12390
|
.twc-drp__nav:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
11808
12391
|
.twc-drp__nav svg { width: 17px; height: 17px; }
|
|
11809
|
-
.twc-drp__title { font-size: var(--text-sm); font-weight: var(--font-bold); }
|
|
12392
|
+
.twc-drp__title { font-size: var(--text-sm); font-weight: var(--font-bold); color: var(--color-text); border: none; background: transparent; cursor: pointer; padding: 5px 10px; border-radius: var(--radius-md); }
|
|
12393
|
+
.twc-drp__title:hover { background: var(--color-surface-sunken); }
|
|
12394
|
+
.twc-drp__months, .twc-drp__years { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; }
|
|
12395
|
+
.twc-drp__mo, .twc-drp__yr { padding: 10px 0; border: none; background: transparent; cursor: pointer; font-family: inherit; font-size: var(--text-sm); color: var(--color-text); border-radius: var(--radius-md); }
|
|
12396
|
+
.twc-drp__mo:hover:not(:disabled), .twc-drp__yr:hover:not(:disabled) { background: var(--color-surface-sunken); }
|
|
12397
|
+
.twc-drp__yr[data-outside="true"] { color: var(--color-text-subtle); }
|
|
12398
|
+
.twc-drp__mo[data-selected="true"], .twc-drp__yr[data-selected="true"] { background: var(--color-primary); color: var(--color-primary-fg); font-weight: var(--font-bold); }
|
|
12399
|
+
.twc-drp__mo:disabled, .twc-drp__yr:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
11810
12400
|
.twc-drp__grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 1px; }
|
|
11811
12401
|
.twc-drp__dow { text-align: center; font-size: 11px; font-weight: var(--font-bold); color: var(--color-text-subtle); padding: 4px 0; }
|
|
11812
12402
|
.twc-drp__day { aspect-ratio: 1; border: none; background: transparent; cursor: pointer; font-family: inherit; font-size: var(--text-sm); color: var(--color-text); display: grid; place-items: center; position: relative; }
|
|
@@ -11832,6 +12422,18 @@ var weekdayNames2 = (locale, weekStartsOn) => {
|
|
|
11832
12422
|
};
|
|
11833
12423
|
var ymd = (d) => d ? new Date(d.getFullYear(), d.getMonth(), d.getDate()).getTime() : null;
|
|
11834
12424
|
var fmtD = (d, locale) => d ? d.toLocaleDateString(locale, { month: "short", day: "numeric", year: "numeric" }) : "";
|
|
12425
|
+
var rollingDays = (days) => {
|
|
12426
|
+
const end = /* @__PURE__ */ new Date();
|
|
12427
|
+
const start = /* @__PURE__ */ new Date();
|
|
12428
|
+
start.setDate(end.getDate() - days + 1);
|
|
12429
|
+
return { start, end };
|
|
12430
|
+
};
|
|
12431
|
+
var DEFAULT_PRESETS2 = [
|
|
12432
|
+
{ label: "Last 7 days", range: () => rollingDays(7) },
|
|
12433
|
+
{ label: "Last 14 days", range: () => rollingDays(14) },
|
|
12434
|
+
{ label: "Last 30 days", range: () => rollingDays(30) },
|
|
12435
|
+
{ label: "Last 90 days", range: () => rollingDays(90) }
|
|
12436
|
+
];
|
|
11835
12437
|
function DateRangePicker({
|
|
11836
12438
|
label,
|
|
11837
12439
|
hint,
|
|
@@ -11848,6 +12450,9 @@ function DateRangePicker({
|
|
|
11848
12450
|
disabledDate,
|
|
11849
12451
|
disabled = false,
|
|
11850
12452
|
tone = "primary",
|
|
12453
|
+
size = "md",
|
|
12454
|
+
clearable = true,
|
|
12455
|
+
format,
|
|
11851
12456
|
editable = false,
|
|
11852
12457
|
parse,
|
|
11853
12458
|
onChange,
|
|
@@ -11857,11 +12462,14 @@ function DateRangePicker({
|
|
|
11857
12462
|
const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS4);
|
|
11858
12463
|
const __twcStyles1 = useScopedStyles("twc-drp-styles", RANGE_CSS2);
|
|
11859
12464
|
const [internal, setInternal] = React51__namespace.default.useState(defaultValue);
|
|
11860
|
-
const
|
|
12465
|
+
const range2 = value !== void 0 ? value : internal;
|
|
11861
12466
|
const [open, setOpen] = React51__namespace.default.useState(false);
|
|
11862
|
-
const [view, setView] = React51__namespace.default.useState(
|
|
12467
|
+
const [view, setView] = React51__namespace.default.useState(range2.start || /* @__PURE__ */ new Date());
|
|
11863
12468
|
const [hover, setHover] = React51__namespace.default.useState(null);
|
|
11864
12469
|
const [focusDate, setFocusDate] = React51__namespace.default.useState(null);
|
|
12470
|
+
const [mode, setMode] = React51__namespace.default.useState("days");
|
|
12471
|
+
const [focusMonth, setFocusMonth] = React51__namespace.default.useState(null);
|
|
12472
|
+
const [focusYear, setFocusYear] = React51__namespace.default.useState(null);
|
|
11865
12473
|
const [editText, setEditText] = React51__namespace.default.useState(null);
|
|
11866
12474
|
const [coords, setCoords] = React51__namespace.default.useState(null);
|
|
11867
12475
|
const wrapRef = React51__namespace.default.useRef(null);
|
|
@@ -11933,7 +12541,7 @@ function DateRangePicker({
|
|
|
11933
12541
|
const raw = editText.trim();
|
|
11934
12542
|
if (raw === "") {
|
|
11935
12543
|
setEditText(null);
|
|
11936
|
-
if (
|
|
12544
|
+
if (range2.start || range2.end) set({ start: null, end: null });
|
|
11937
12545
|
return;
|
|
11938
12546
|
}
|
|
11939
12547
|
const parts = raw.split(/\s*(?:–|—|\bto\b|\.\.+)\s*/i).map((p) => p.trim());
|
|
@@ -11965,8 +12573,15 @@ function DateRangePicker({
|
|
|
11965
12573
|
if (!open) {
|
|
11966
12574
|
setFocusDate(null);
|
|
11967
12575
|
setHover(null);
|
|
12576
|
+
setMode("days");
|
|
11968
12577
|
}
|
|
11969
12578
|
}, [open]);
|
|
12579
|
+
React51__namespace.default.useEffect(() => {
|
|
12580
|
+
if (open && mode === "months" && focusMonth != null) gridRef.current?.querySelector(`[data-mo="${focusMonth}"]`)?.focus();
|
|
12581
|
+
}, [focusMonth, open, mode]);
|
|
12582
|
+
React51__namespace.default.useEffect(() => {
|
|
12583
|
+
if (open && mode === "years" && focusYear != null) gridRef.current?.querySelector(`[data-yr="${focusYear}"]`)?.focus();
|
|
12584
|
+
}, [focusYear, open, mode]);
|
|
11970
12585
|
React51__namespace.default.useEffect(() => {
|
|
11971
12586
|
if (!open || !focusDate) return;
|
|
11972
12587
|
gridRef.current?.querySelector(`[data-key="${keyOf(focusDate)}"]`)?.focus();
|
|
@@ -11997,35 +12612,74 @@ function DateRangePicker({
|
|
|
11997
12612
|
setHover(next);
|
|
11998
12613
|
if (next.getFullYear() !== view.getFullYear() || next.getMonth() !== view.getMonth()) setView(new Date(next.getFullYear(), next.getMonth(), 1));
|
|
11999
12614
|
};
|
|
12000
|
-
const
|
|
12615
|
+
const onMonthsKeyDown = (e) => {
|
|
12616
|
+
const vy = view.getFullYear();
|
|
12617
|
+
const cur = focusMonth == null ? view.getMonth() : focusMonth;
|
|
12618
|
+
let next;
|
|
12619
|
+
if (e.key === "ArrowRight") next = cur + 1;
|
|
12620
|
+
else if (e.key === "ArrowLeft") next = cur - 1;
|
|
12621
|
+
else if (e.key === "ArrowDown") next = cur + 3;
|
|
12622
|
+
else if (e.key === "ArrowUp") next = cur - 3;
|
|
12623
|
+
else if (e.key === "Home") next = 0;
|
|
12624
|
+
else if (e.key === "End") next = 11;
|
|
12625
|
+
else return;
|
|
12626
|
+
e.preventDefault();
|
|
12627
|
+
if (next < 0) {
|
|
12628
|
+
setView(new Date(vy - 1, 0, 1));
|
|
12629
|
+
next += 12;
|
|
12630
|
+
} else if (next > 11) {
|
|
12631
|
+
setView(new Date(vy + 1, 0, 1));
|
|
12632
|
+
next -= 12;
|
|
12633
|
+
}
|
|
12634
|
+
setFocusMonth(next);
|
|
12635
|
+
};
|
|
12636
|
+
const onYearsKeyDown = (e) => {
|
|
12637
|
+
const vm = view.getMonth(), ds = Math.floor(view.getFullYear() / 10) * 10;
|
|
12638
|
+
const cur = focusYear == null ? view.getFullYear() : focusYear;
|
|
12639
|
+
let next;
|
|
12640
|
+
if (e.key === "ArrowRight") next = cur + 1;
|
|
12641
|
+
else if (e.key === "ArrowLeft") next = cur - 1;
|
|
12642
|
+
else if (e.key === "ArrowDown") next = cur + 3;
|
|
12643
|
+
else if (e.key === "ArrowUp") next = cur - 3;
|
|
12644
|
+
else if (e.key === "Home") next = ds;
|
|
12645
|
+
else if (e.key === "End") next = ds + 9;
|
|
12646
|
+
else return;
|
|
12647
|
+
e.preventDefault();
|
|
12648
|
+
setView(new Date(next, vm, 1));
|
|
12649
|
+
setFocusYear(next);
|
|
12650
|
+
};
|
|
12651
|
+
const tabbableDate = focusDate || range2.start || /* @__PURE__ */ new Date();
|
|
12001
12652
|
const clickDay = (d) => {
|
|
12002
12653
|
if (outOfRange(d)) return;
|
|
12003
|
-
if (!
|
|
12654
|
+
if (!range2.start || range2.start && range2.end) {
|
|
12004
12655
|
set({ start: d, end: null });
|
|
12005
12656
|
} else {
|
|
12006
|
-
const [start, end] = ymd(d) < ymd(
|
|
12657
|
+
const [start, end] = ymd(d) < ymd(range2.start) ? [d, range2.start] : [range2.start, d];
|
|
12007
12658
|
set({ start, end });
|
|
12008
12659
|
setOpen(false);
|
|
12009
12660
|
}
|
|
12010
12661
|
};
|
|
12011
|
-
const
|
|
12012
|
-
|
|
12013
|
-
const
|
|
12014
|
-
|
|
12015
|
-
set(
|
|
12016
|
-
setView(start);
|
|
12662
|
+
const presetItems = presets === true ? DEFAULT_PRESETS2 : Array.isArray(presets) ? presets : [];
|
|
12663
|
+
const applyPreset = (preset) => {
|
|
12664
|
+
const r2 = typeof preset.range === "function" ? preset.range() : preset.range;
|
|
12665
|
+
if (!r2) return;
|
|
12666
|
+
set(r2);
|
|
12667
|
+
if (r2.start) setView(r2.start);
|
|
12017
12668
|
setOpen(false);
|
|
12018
12669
|
};
|
|
12019
12670
|
const months = React51__namespace.default.useMemo(() => locale === void 0 ? MONTHS2 : monthNames2(locale), [locale]);
|
|
12671
|
+
const monthsShort = React51__namespace.default.useMemo(() => months.map((n) => n.slice(0, 3)), [months]);
|
|
12020
12672
|
const dows = React51__namespace.default.useMemo(
|
|
12021
12673
|
() => locale === void 0 ? Array.from({ length: 7 }, (_, i) => DOW2[(i + weekStartsOn) % 7]) : weekdayNames2(locale, weekStartsOn),
|
|
12022
12674
|
[locale, weekStartsOn]
|
|
12023
12675
|
);
|
|
12024
12676
|
const y = view.getFullYear(), m = view.getMonth();
|
|
12677
|
+
const decadeStart = Math.floor(y / 10) * 10;
|
|
12678
|
+
const yearCells = Array.from({ length: 12 }, (_, i) => decadeStart - 1 + i);
|
|
12025
12679
|
const startOffset = (new Date(y, m, 1).getDay() - weekStartsOn + 7) % 7;
|
|
12026
12680
|
const gridStart = new Date(y, m, 1 - startOffset);
|
|
12027
12681
|
const edgeOf = (t) => {
|
|
12028
|
-
const s = ymd(
|
|
12682
|
+
const s = ymd(range2.start), e = ymd(range2.end) || (range2.start && hover ? ymd(hover) : null);
|
|
12029
12683
|
const lo = s != null && e != null ? Math.min(s, e) : s, hi = s != null && e != null ? Math.max(s, e) : s;
|
|
12030
12684
|
if (s != null && hi === lo && t === s) return "both";
|
|
12031
12685
|
if (t === lo) return "start";
|
|
@@ -12033,13 +12687,13 @@ function DateRangePicker({
|
|
|
12033
12687
|
return null;
|
|
12034
12688
|
};
|
|
12035
12689
|
const inRange = (t) => {
|
|
12036
|
-
const s = ymd(
|
|
12037
|
-
let e = ymd(
|
|
12690
|
+
const s = ymd(range2.start);
|
|
12691
|
+
let e = ymd(range2.end);
|
|
12038
12692
|
if (s != null && e == null && hover) e = ymd(hover);
|
|
12039
12693
|
if (s == null || e == null) return false;
|
|
12040
12694
|
return t > Math.min(s, e) && t < Math.max(s, e);
|
|
12041
12695
|
};
|
|
12042
|
-
const text =
|
|
12696
|
+
const text = range2.start ? format ? format(range2) : `${fmtD(range2.start, locale)} \u2013 ${range2.end ? fmtD(range2.end, locale) : "\u2026"}` : "";
|
|
12043
12697
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-drp twc-field ${className}`, ref: wrapRef, ...rest, children: [
|
|
12044
12698
|
__twcStyles0,
|
|
12045
12699
|
__twcStyles1,
|
|
@@ -12049,7 +12703,7 @@ function DateRangePicker({
|
|
|
12049
12703
|
] }) : null,
|
|
12050
12704
|
editable ? (
|
|
12051
12705
|
// #105: typed entry — a text input accepting "start – end"; commits via `parse` on Enter/blur.
|
|
12052
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drp__control twc-drp__control--editable", "data-open": open || void 0, "data-disabled": disabled || void 0, "data-invalid": invalid || void 0, "data-tone": tone, children: [
|
|
12706
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drp__control twc-drp__control--editable", "data-open": open || void 0, "data-disabled": disabled || void 0, "data-invalid": invalid || void 0, "data-tone": tone, "data-size": size, children: [
|
|
12053
12707
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12054
12708
|
"input",
|
|
12055
12709
|
{
|
|
@@ -12081,14 +12735,26 @@ function DateRangePicker({
|
|
|
12081
12735
|
}
|
|
12082
12736
|
}
|
|
12083
12737
|
),
|
|
12084
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12738
|
+
clearable && (range2.start || range2.end) && !disabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12085
12739
|
"button",
|
|
12086
12740
|
{
|
|
12087
12741
|
type: "button",
|
|
12088
|
-
className: "twc-
|
|
12089
|
-
"aria-label": "
|
|
12742
|
+
className: "twc-drp__clear",
|
|
12743
|
+
"aria-label": "Clear",
|
|
12090
12744
|
tabIndex: -1,
|
|
12091
|
-
|
|
12745
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
12746
|
+
onClick: () => set({ start: null, end: null }),
|
|
12747
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
12748
|
+
}
|
|
12749
|
+
) : null,
|
|
12750
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12751
|
+
"button",
|
|
12752
|
+
{
|
|
12753
|
+
type: "button",
|
|
12754
|
+
className: "twc-drp__toggle",
|
|
12755
|
+
"aria-label": "Open calendar",
|
|
12756
|
+
tabIndex: -1,
|
|
12757
|
+
disabled,
|
|
12092
12758
|
onClick: () => !disabled && setOpen((o) => !o),
|
|
12093
12759
|
children: /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
12094
12760
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
@@ -12106,6 +12772,7 @@ function DateRangePicker({
|
|
|
12106
12772
|
"data-disabled": disabled || void 0,
|
|
12107
12773
|
"data-invalid": invalid || void 0,
|
|
12108
12774
|
"data-tone": tone,
|
|
12775
|
+
"data-size": size,
|
|
12109
12776
|
role: "button",
|
|
12110
12777
|
tabIndex: disabled ? -1 : 0,
|
|
12111
12778
|
"aria-haspopup": "dialog",
|
|
@@ -12126,7 +12793,22 @@ function DateRangePicker({
|
|
|
12126
12793
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "4", width: "18", height: "18", rx: "2" }),
|
|
12127
12794
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M16 2v4M8 2v4M3 10h18" })
|
|
12128
12795
|
] }) }),
|
|
12129
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-drp__text", "data-placeholder": !
|
|
12796
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-drp__text", "data-placeholder": !range2.start || void 0, children: range2.start ? text : placeholder }),
|
|
12797
|
+
clearable && (range2.start || range2.end) && !disabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
12798
|
+
"button",
|
|
12799
|
+
{
|
|
12800
|
+
type: "button",
|
|
12801
|
+
className: "twc-drp__clear",
|
|
12802
|
+
"aria-label": "Clear",
|
|
12803
|
+
tabIndex: -1,
|
|
12804
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
12805
|
+
onClick: (e) => {
|
|
12806
|
+
e.stopPropagation();
|
|
12807
|
+
set({ start: null, end: null });
|
|
12808
|
+
},
|
|
12809
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
12810
|
+
}
|
|
12811
|
+
) : null
|
|
12130
12812
|
]
|
|
12131
12813
|
}
|
|
12132
12814
|
),
|
|
@@ -12141,23 +12823,23 @@ function DateRangePicker({
|
|
|
12141
12823
|
"aria-label": "Choose date range",
|
|
12142
12824
|
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
|
|
12143
12825
|
children: [
|
|
12144
|
-
|
|
12826
|
+
presetItems.length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drp__presets", children: presetItems.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-drp__preset", onClick: () => applyPreset(p), children: p.label }, i)) }) : null,
|
|
12145
12827
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drp__cal", children: [
|
|
12146
12828
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drp__head", children: [
|
|
12147
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-drp__nav", "aria-label": "Previous month", onClick: () => setView(new Date(y, m - 1, 1)), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
12148
|
-
/* @__PURE__ */ jsxRuntime.
|
|
12149
|
-
|
|
12150
|
-
|
|
12151
|
-
|
|
12152
|
-
|
|
12153
|
-
|
|
12154
|
-
|
|
12155
|
-
|
|
12156
|
-
|
|
12157
|
-
] }),
|
|
12158
|
-
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-drp__nav", "aria-label": "Next month", onClick: () => setView(new Date(y, m + 1, 1)), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) }) })
|
|
12829
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-drp__nav", "aria-label": mode === "years" ? "Previous decade" : mode === "months" ? "Previous year" : "Previous month", onClick: () => setView(mode === "years" ? new Date(y - 10, m, 1) : mode === "months" ? new Date(y - 1, m, 1) : new Date(y, m - 1, 1)), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m15 18-6-6 6-6" }) }) }),
|
|
12830
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-drp__title", "aria-label": "Switch calendar view", onClick: () => {
|
|
12831
|
+
if (mode === "days") {
|
|
12832
|
+
setFocusMonth(m);
|
|
12833
|
+
setMode("months");
|
|
12834
|
+
} else if (mode === "months") {
|
|
12835
|
+
setFocusYear(y);
|
|
12836
|
+
setMode("years");
|
|
12837
|
+
} else setMode("days");
|
|
12838
|
+
}, children: mode === "days" ? `${months[m]} ${y}` : mode === "months" ? y : `${decadeStart}\u2013${decadeStart + 9}` }),
|
|
12839
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-drp__sr", "aria-live": "polite", children: mode === "days" ? `${months[m]} ${y}` : mode === "months" ? y : `${decadeStart}\u2013${decadeStart + 9}` }),
|
|
12840
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-drp__nav", "aria-label": mode === "years" ? "Next decade" : mode === "months" ? "Next year" : "Next month", onClick: () => setView(mode === "years" ? new Date(y + 10, m, 1) : mode === "months" ? new Date(y + 1, m, 1) : new Date(y, m + 1, 1)), children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "m9 18 6-6-6-6" }) }) })
|
|
12159
12841
|
] }),
|
|
12160
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drp__grid", ref: gridRef, onKeyDown: onGridKeyDown, role: "grid", children: [
|
|
12842
|
+
mode === "days" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-drp__grid", ref: gridRef, onKeyDown: onGridKeyDown, role: "grid", children: [
|
|
12161
12843
|
dows.map((d, i) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drp__dow", children: d }, i)),
|
|
12162
12844
|
Array.from({ length: 42 }).map((_, i) => {
|
|
12163
12845
|
const d = new Date(gridStart.getFullYear(), gridStart.getMonth(), gridStart.getDate() + i);
|
|
@@ -12182,7 +12864,53 @@ function DateRangePicker({
|
|
|
12182
12864
|
i
|
|
12183
12865
|
);
|
|
12184
12866
|
})
|
|
12185
|
-
] })
|
|
12867
|
+
] }) : mode === "months" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drp__months", ref: gridRef, onKeyDown: onMonthsKeyDown, role: "grid", children: monthsShort.map((mo, i) => {
|
|
12868
|
+
const disabled2 = min && ymd(new Date(y, i + 1, 0)) < ymd(min) || max && ymd(new Date(y, i, 1)) > ymd(max);
|
|
12869
|
+
const sel = range2.start && range2.start.getFullYear() === y && range2.start.getMonth() === i || range2.end && range2.end.getFullYear() === y && range2.end.getMonth() === i;
|
|
12870
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12871
|
+
"button",
|
|
12872
|
+
{
|
|
12873
|
+
type: "button",
|
|
12874
|
+
className: "twc-drp__mo",
|
|
12875
|
+
role: "gridcell",
|
|
12876
|
+
"data-mo": i,
|
|
12877
|
+
disabled: disabled2 || void 0,
|
|
12878
|
+
"data-selected": sel || void 0,
|
|
12879
|
+
tabIndex: i === (focusMonth ?? m) ? 0 : -1,
|
|
12880
|
+
onClick: () => {
|
|
12881
|
+
setView(new Date(y, i, 1));
|
|
12882
|
+
setFocusDate(null);
|
|
12883
|
+
setMode("days");
|
|
12884
|
+
},
|
|
12885
|
+
children: mo
|
|
12886
|
+
},
|
|
12887
|
+
i
|
|
12888
|
+
);
|
|
12889
|
+
}) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-drp__years", ref: gridRef, onKeyDown: onYearsKeyDown, role: "grid", children: yearCells.map((yr) => {
|
|
12890
|
+
const outside = yr < decadeStart || yr > decadeStart + 9;
|
|
12891
|
+
const disabled2 = min && ymd(new Date(yr, 11, 31)) < ymd(min) || max && ymd(new Date(yr, 0, 1)) > ymd(max);
|
|
12892
|
+
const sel = range2.start && range2.start.getFullYear() === yr || range2.end && range2.end.getFullYear() === yr;
|
|
12893
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
12894
|
+
"button",
|
|
12895
|
+
{
|
|
12896
|
+
type: "button",
|
|
12897
|
+
className: "twc-drp__yr",
|
|
12898
|
+
role: "gridcell",
|
|
12899
|
+
"data-yr": yr,
|
|
12900
|
+
"data-outside": outside || void 0,
|
|
12901
|
+
disabled: disabled2 || void 0,
|
|
12902
|
+
"data-selected": sel || void 0,
|
|
12903
|
+
tabIndex: yr === (focusYear ?? y) ? 0 : -1,
|
|
12904
|
+
onClick: () => {
|
|
12905
|
+
setView(new Date(yr, m, 1));
|
|
12906
|
+
setFocusMonth(m);
|
|
12907
|
+
setMode("months");
|
|
12908
|
+
},
|
|
12909
|
+
children: yr
|
|
12910
|
+
},
|
|
12911
|
+
yr
|
|
12912
|
+
);
|
|
12913
|
+
}) })
|
|
12186
12914
|
] })
|
|
12187
12915
|
]
|
|
12188
12916
|
}
|
|
@@ -12192,6 +12920,776 @@ function DateRangePicker({
|
|
|
12192
12920
|
error ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
|
|
12193
12921
|
] });
|
|
12194
12922
|
}
|
|
12923
|
+
var FIELD_CSS5 = `
|
|
12924
|
+
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
12925
|
+
.twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
|
|
12926
|
+
.twc-field__req { color: var(--color-danger); }
|
|
12927
|
+
.twc-field__hint { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
12928
|
+
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
12929
|
+
`;
|
|
12930
|
+
var TIMEPICKER_CSS = `
|
|
12931
|
+
.twc-tp { position: relative; font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-1-5); }
|
|
12932
|
+
.twc-tp__control {
|
|
12933
|
+
display: flex; align-items: center; gap: var(--space-2); --_h: var(--control-h-md); height: var(--_h); padding: 0 var(--space-3);
|
|
12934
|
+
background: var(--color-surface); border: var(--border-thin) solid var(--color-border); border-radius: var(--radius-md);
|
|
12935
|
+
cursor: pointer; transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard);
|
|
12936
|
+
}
|
|
12937
|
+
.twc-tp__control:hover:not([data-open="true"]) { border-color: var(--color-border-strong); }
|
|
12938
|
+
.twc-tp__control { --_accent: var(--color-primary); --_ring: var(--ring); }
|
|
12939
|
+
.twc-tp__control[data-size="sm"] { --_h: var(--control-h-sm); }
|
|
12940
|
+
.twc-tp__control[data-size="lg"] { --_h: var(--control-h-lg); }
|
|
12941
|
+
.twc-tp__control[data-tone="success"] { --_accent: var(--color-success); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-success) 32%, transparent); }
|
|
12942
|
+
.twc-tp__control[data-tone="warning"] { --_accent: var(--color-warning); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-warning) 32%, transparent); }
|
|
12943
|
+
.twc-tp__control[data-tone="danger"] { --_accent: var(--color-danger); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-danger) 32%, transparent); }
|
|
12944
|
+
.twc-tp__control[data-tone="info"] { --_accent: var(--color-info); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-info) 32%, transparent); }
|
|
12945
|
+
.twc-tp__control[data-tone="neutral"] { --_accent: var(--color-border-strong); --_ring: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-text) 14%, transparent); }
|
|
12946
|
+
.twc-tp__control[data-open="true"] { border-color: var(--_accent); box-shadow: var(--_ring); }
|
|
12947
|
+
.twc-tp__control[data-invalid="true"] { border-color: var(--color-danger); }
|
|
12948
|
+
.twc-tp__control[data-invalid="true"][data-open="true"] { box-shadow: 0 0 0 var(--ring-width) color-mix(in srgb, var(--color-danger) 28%, transparent); }
|
|
12949
|
+
.twc-tp__control[data-disabled="true"] { background: var(--color-surface-sunken); opacity: 0.7; cursor: not-allowed; }
|
|
12950
|
+
.twc-tp__field { position: relative; display: flex; flex-direction: column; }
|
|
12951
|
+
.twc-tp__control[data-has-clear="true"] { padding-inline-end: 34px; }
|
|
12952
|
+
.twc-tp__ic { flex: none; color: var(--color-text-subtle); display: inline-flex; }
|
|
12953
|
+
.twc-tp__ic svg { width: 17px; height: 17px; }
|
|
12954
|
+
.twc-tp__text { flex: 1; font-size: var(--text-sm); color: var(--color-text); font-variant-numeric: tabular-nums; }
|
|
12955
|
+
.twc-tp__text[data-placeholder="true"] { color: var(--color-text-subtle); font-variant-numeric: normal; }
|
|
12956
|
+
.twc-tp__clear { position: absolute; inset-inline-end: 10px; top: 50%; transform: translateY(-50%); display: inline-grid; place-items: center; width: 20px; height: 20px; border: none; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-full); }
|
|
12957
|
+
.twc-tp__clear:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
12958
|
+
.twc-tp__clear svg { width: 14px; height: 14px; }
|
|
12959
|
+
.twc-tp__control--editable { cursor: text; gap: 0; padding-inline-end: var(--space-1); }
|
|
12960
|
+
.twc-tp__input { flex: 1; min-width: 0; height: 100%; border: none; background: transparent; outline: none; padding: 0; font-family: inherit; font-size: var(--text-sm); color: var(--color-text); font-variant-numeric: tabular-nums; }
|
|
12961
|
+
.twc-tp__input::placeholder { color: var(--color-text-subtle); font-variant-numeric: normal; }
|
|
12962
|
+
.twc-tp__input:disabled { cursor: not-allowed; }
|
|
12963
|
+
.twc-tp__clear--inline { position: static; transform: none; flex: none; }
|
|
12964
|
+
.twc-tp__toggle { flex: none; display: inline-grid; place-items: center; width: 26px; height: 26px; border: none; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-md); transition: background-color var(--duration-fast), color var(--duration-fast); }
|
|
12965
|
+
.twc-tp__toggle:hover:not(:disabled) { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
12966
|
+
.twc-tp__toggle:disabled { cursor: not-allowed; }
|
|
12967
|
+
.twc-tp__toggle svg { width: 17px; height: 17px; }
|
|
12968
|
+
|
|
12969
|
+
.twc-tp__pop {
|
|
12970
|
+
position: fixed; z-index: var(--z-popover);
|
|
12971
|
+
background: var(--color-surface-raised); border: var(--border-thin) solid var(--color-border);
|
|
12972
|
+
border-radius: var(--radius-lg); box-shadow: var(--shadow-lg); padding: var(--space-2);
|
|
12973
|
+
animation: twico-scale-in var(--duration-fast) var(--ease-spring); transform-origin: top;
|
|
12974
|
+
}
|
|
12975
|
+
.twc-tp__cols { display: flex; gap: var(--space-1); max-height: 232px; }
|
|
12976
|
+
.twc-tp__col { display: flex; flex-direction: column; gap: 2px; overflow-y: auto; scrollbar-width: thin; padding-inline: 2px; scroll-behavior: smooth; }
|
|
12977
|
+
.twc-tp__col::-webkit-scrollbar { width: 6px; }
|
|
12978
|
+
.twc-tp__col::-webkit-scrollbar-thumb { background: var(--color-border-strong); border-radius: var(--radius-full); }
|
|
12979
|
+
.twc-tp__col + .twc-tp__col { border-inline-start: var(--border-thin) solid var(--color-divider); }
|
|
12980
|
+
.twc-tp__colhead { text-align: center; font-size: 11px; font-weight: var(--font-bold); color: var(--color-text-subtle); text-transform: uppercase; padding: 2px 0 4px; position: sticky; top: 0; background: var(--color-surface-raised); }
|
|
12981
|
+
.twc-tp__opt { min-width: 46px; padding: 6px 10px; border: none; background: transparent; cursor: pointer; font-family: inherit; font-size: var(--text-sm); color: var(--color-text); border-radius: var(--radius-md); text-align: center; font-variant-numeric: tabular-nums; transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard); }
|
|
12982
|
+
.twc-tp__opt:hover:not(:disabled):not([data-selected="true"]) { background: var(--color-surface-sunken); }
|
|
12983
|
+
.twc-tp__opt[data-selected="true"] { background: var(--color-primary); color: var(--color-primary-fg); font-weight: var(--font-bold); }
|
|
12984
|
+
.twc-tp__opt:disabled { opacity: 0.35; cursor: not-allowed; }
|
|
12985
|
+
.twc-tp__opt:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
12986
|
+
`;
|
|
12987
|
+
var pad = (n) => String(n).padStart(2, "0");
|
|
12988
|
+
var range = (start, end, step) => {
|
|
12989
|
+
const out = [];
|
|
12990
|
+
for (let i = start; i < end; i += step) out.push(i);
|
|
12991
|
+
return out;
|
|
12992
|
+
};
|
|
12993
|
+
var tod = (h, m, s) => h * 3600 + m * 60 + s;
|
|
12994
|
+
var to24 = (dh, mer) => mer === "PM" ? dh === 12 ? 12 : dh + 12 : dh === 12 ? 0 : dh;
|
|
12995
|
+
function TimePicker({
|
|
12996
|
+
label,
|
|
12997
|
+
hint,
|
|
12998
|
+
error,
|
|
12999
|
+
required = false,
|
|
13000
|
+
value,
|
|
13001
|
+
defaultValue = null,
|
|
13002
|
+
placeholder = "Select time",
|
|
13003
|
+
min,
|
|
13004
|
+
max,
|
|
13005
|
+
minuteStep = 5,
|
|
13006
|
+
secondStep = 5,
|
|
13007
|
+
granularity = "minute",
|
|
13008
|
+
// "hour" | "minute" | "second"
|
|
13009
|
+
hourCycle = 24,
|
|
13010
|
+
// 24 | 12
|
|
13011
|
+
referenceDate,
|
|
13012
|
+
disabled = false,
|
|
13013
|
+
tone = "primary",
|
|
13014
|
+
size = "md",
|
|
13015
|
+
clearable = true,
|
|
13016
|
+
editable = false,
|
|
13017
|
+
parse,
|
|
13018
|
+
format,
|
|
13019
|
+
locale,
|
|
13020
|
+
onChange,
|
|
13021
|
+
id,
|
|
13022
|
+
className = "",
|
|
13023
|
+
...rest
|
|
13024
|
+
}) {
|
|
13025
|
+
const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS5);
|
|
13026
|
+
const __twcStyles1 = useScopedStyles("twc-timepicker-styles", TIMEPICKER_CSS);
|
|
13027
|
+
const autoId = React51__namespace.default.useId();
|
|
13028
|
+
const fieldId = id || autoId;
|
|
13029
|
+
const descId = `${fieldId}-desc`;
|
|
13030
|
+
const invalid = Boolean(error);
|
|
13031
|
+
const [internal, setInternal] = React51__namespace.default.useState(defaultValue);
|
|
13032
|
+
const selected = value !== void 0 ? value : internal;
|
|
13033
|
+
const [open, setOpen] = React51__namespace.default.useState(false);
|
|
13034
|
+
const [editText, setEditText] = React51__namespace.default.useState(null);
|
|
13035
|
+
const [coords, setCoords] = React51__namespace.default.useState(null);
|
|
13036
|
+
const wrapRef = React51__namespace.default.useRef(null);
|
|
13037
|
+
const triggerRef = React51__namespace.default.useRef(null);
|
|
13038
|
+
const popRef = React51__namespace.default.useRef(null);
|
|
13039
|
+
const place = React51__namespace.default.useCallback(() => {
|
|
13040
|
+
const el = triggerRef.current;
|
|
13041
|
+
if (!el) return;
|
|
13042
|
+
const r2 = el.getBoundingClientRect();
|
|
13043
|
+
const vh = window.innerHeight, POP_W = 220;
|
|
13044
|
+
const below = vh - r2.bottom;
|
|
13045
|
+
const flip = below < 300 && r2.top > below;
|
|
13046
|
+
let left = Math.min(r2.left, window.innerWidth - POP_W - 8);
|
|
13047
|
+
left = Math.max(8, left);
|
|
13048
|
+
setCoords({ left, top: flip ? void 0 : Math.round(r2.bottom + 6), bottom: flip ? Math.round(vh - r2.top + 6) : void 0 });
|
|
13049
|
+
}, []);
|
|
13050
|
+
React51__namespace.default.useEffect(() => {
|
|
13051
|
+
if (!open) return void 0;
|
|
13052
|
+
place();
|
|
13053
|
+
const onMove = () => place();
|
|
13054
|
+
window.addEventListener("scroll", onMove, true);
|
|
13055
|
+
window.addEventListener("resize", onMove);
|
|
13056
|
+
return () => {
|
|
13057
|
+
window.removeEventListener("scroll", onMove, true);
|
|
13058
|
+
window.removeEventListener("resize", onMove);
|
|
13059
|
+
};
|
|
13060
|
+
}, [open, place]);
|
|
13061
|
+
React51__namespace.default.useEffect(() => {
|
|
13062
|
+
if (!open) return void 0;
|
|
13063
|
+
const onDown = (e) => {
|
|
13064
|
+
if (wrapRef.current && wrapRef.current.contains(e.target)) return;
|
|
13065
|
+
if (popRef.current && popRef.current.contains(e.target)) return;
|
|
13066
|
+
setOpen(false);
|
|
13067
|
+
};
|
|
13068
|
+
const onKey = (e) => {
|
|
13069
|
+
if (e.key === "Escape") setOpen(false);
|
|
13070
|
+
};
|
|
13071
|
+
document.addEventListener("mousedown", onDown);
|
|
13072
|
+
document.addEventListener("keydown", onKey);
|
|
13073
|
+
return () => {
|
|
13074
|
+
document.removeEventListener("mousedown", onDown);
|
|
13075
|
+
document.removeEventListener("keydown", onKey);
|
|
13076
|
+
};
|
|
13077
|
+
}, [open]);
|
|
13078
|
+
useFocusTrap(popRef, open && !!coords, {
|
|
13079
|
+
initialFocus: () => popRef.current?.querySelector('.twc-tp__opt[data-selected="true"]') || popRef.current?.querySelector('.twc-tp__opt[tabindex="0"]')
|
|
13080
|
+
});
|
|
13081
|
+
React51__namespace.default.useEffect(() => {
|
|
13082
|
+
if (!open || !coords) return;
|
|
13083
|
+
popRef.current?.querySelectorAll('.twc-tp__opt[data-selected="true"]').forEach((el) => el.scrollIntoView({ block: "center" }));
|
|
13084
|
+
}, [open, coords]);
|
|
13085
|
+
const refBase = referenceDate || /* @__PURE__ */ new Date();
|
|
13086
|
+
const minTod = min ? tod(min.getHours(), min.getMinutes(), min.getSeconds()) : null;
|
|
13087
|
+
const maxTod = max ? tod(max.getHours(), max.getMinutes(), max.getSeconds()) : null;
|
|
13088
|
+
const outOfRange = (h, m, s) => minTod != null && tod(h, m, s) < minTod || maxTod != null && tod(h, m, s) > maxTod;
|
|
13089
|
+
const curH = selected ? selected.getHours() : null;
|
|
13090
|
+
const curM = selected ? selected.getMinutes() : null;
|
|
13091
|
+
const curS = selected ? selected.getSeconds() : null;
|
|
13092
|
+
const curMer = curH == null ? "AM" : curH < 12 ? "AM" : "PM";
|
|
13093
|
+
const fmt = (d) => {
|
|
13094
|
+
if (!d) return "";
|
|
13095
|
+
if (format) return format(d);
|
|
13096
|
+
const opts = { hour: hourCycle === 12 ? "numeric" : "2-digit", minute: "2-digit", hour12: hourCycle === 12 };
|
|
13097
|
+
if (granularity === "second") opts.second = "2-digit";
|
|
13098
|
+
if (granularity === "hour") delete opts.minute;
|
|
13099
|
+
return d.toLocaleTimeString(locale, opts);
|
|
13100
|
+
};
|
|
13101
|
+
const commit = (h, m, s) => {
|
|
13102
|
+
const b = selected || refBase;
|
|
13103
|
+
const d = new Date(b.getFullYear(), b.getMonth(), b.getDate(), h, m, s, 0);
|
|
13104
|
+
if (value === void 0) setInternal(d);
|
|
13105
|
+
onChange?.(d);
|
|
13106
|
+
setEditText(null);
|
|
13107
|
+
};
|
|
13108
|
+
const pickHour = (h) => commit(h, granularity === "hour" ? 0 : curM ?? 0, granularity === "second" ? curS ?? 0 : 0);
|
|
13109
|
+
const pickMinute = (m) => commit(curH ?? refBase.getHours(), m, granularity === "second" ? curS ?? 0 : 0);
|
|
13110
|
+
const pickSecond = (s) => commit(curH ?? refBase.getHours(), curM ?? 0, s);
|
|
13111
|
+
const pickMeridiem = (mer) => {
|
|
13112
|
+
const dh = curH == null ? 0 : curH % 12 === 0 ? 12 : curH % 12;
|
|
13113
|
+
commit(to24(dh, mer), curM ?? 0, granularity === "second" ? curS ?? 0 : 0);
|
|
13114
|
+
};
|
|
13115
|
+
const clear = () => {
|
|
13116
|
+
if (value === void 0) setInternal(null);
|
|
13117
|
+
onChange?.(null);
|
|
13118
|
+
setEditText(null);
|
|
13119
|
+
};
|
|
13120
|
+
const parseTyped = (str) => {
|
|
13121
|
+
const s = str.trim();
|
|
13122
|
+
if (s === "") return null;
|
|
13123
|
+
if (parse) {
|
|
13124
|
+
const d = parse(s);
|
|
13125
|
+
return d instanceof Date && !Number.isNaN(d.getTime()) ? d : void 0;
|
|
13126
|
+
}
|
|
13127
|
+
const mm = s.match(/^(\d{1,2}):(\d{2})(?::(\d{2}))?\s*([ap]m)?$/i);
|
|
13128
|
+
if (!mm) return void 0;
|
|
13129
|
+
let h = +mm[1];
|
|
13130
|
+
const mi = +mm[2];
|
|
13131
|
+
const se = mm[3] ? +mm[3] : 0;
|
|
13132
|
+
const mer = mm[4] && mm[4].toLowerCase();
|
|
13133
|
+
if (mer === "pm" && h < 12) h += 12;
|
|
13134
|
+
else if (mer === "am" && h === 12) h = 0;
|
|
13135
|
+
if (h > 23 || mi > 59 || se > 59) return void 0;
|
|
13136
|
+
const b = selected || refBase;
|
|
13137
|
+
return new Date(b.getFullYear(), b.getMonth(), b.getDate(), h, mi, se, 0);
|
|
13138
|
+
};
|
|
13139
|
+
const commitText = () => {
|
|
13140
|
+
if (editText == null) return;
|
|
13141
|
+
const parsed = parseTyped(editText);
|
|
13142
|
+
if (parsed === null) {
|
|
13143
|
+
setEditText(null);
|
|
13144
|
+
if (selected) clear();
|
|
13145
|
+
return;
|
|
13146
|
+
}
|
|
13147
|
+
if (parsed === void 0 || outOfRange(parsed.getHours(), parsed.getMinutes(), parsed.getSeconds())) {
|
|
13148
|
+
setEditText(null);
|
|
13149
|
+
return;
|
|
13150
|
+
}
|
|
13151
|
+
commit(parsed.getHours(), parsed.getMinutes(), parsed.getSeconds());
|
|
13152
|
+
setOpen(false);
|
|
13153
|
+
};
|
|
13154
|
+
const hourVals = hourCycle === 12 ? [12, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11] : range(0, 24, 1);
|
|
13155
|
+
const columns = [
|
|
13156
|
+
{
|
|
13157
|
+
key: "h",
|
|
13158
|
+
head: "hr",
|
|
13159
|
+
aria: "Hour",
|
|
13160
|
+
items: hourVals.map((hv) => {
|
|
13161
|
+
const h24 = hourCycle === 12 ? to24(hv, curMer) : hv;
|
|
13162
|
+
return {
|
|
13163
|
+
val: hv,
|
|
13164
|
+
text: hourCycle === 12 ? String(hv) : pad(hv),
|
|
13165
|
+
selected: curH != null && h24 === curH,
|
|
13166
|
+
disabled: outOfRange(h24, 0, 0) && outOfRange(h24, 59, 59),
|
|
13167
|
+
onSelect: () => pickHour(h24)
|
|
13168
|
+
};
|
|
13169
|
+
})
|
|
13170
|
+
}
|
|
13171
|
+
];
|
|
13172
|
+
if (granularity !== "hour") {
|
|
13173
|
+
const h = curH ?? refBase.getHours();
|
|
13174
|
+
columns.push({ key: "m", head: "min", aria: "Minute", items: range(0, 60, minuteStep).map((mv) => ({
|
|
13175
|
+
val: mv,
|
|
13176
|
+
text: pad(mv),
|
|
13177
|
+
selected: curM != null && mv === curM,
|
|
13178
|
+
disabled: outOfRange(h, mv, 0) && outOfRange(h, mv, 59),
|
|
13179
|
+
onSelect: () => pickMinute(mv)
|
|
13180
|
+
})) });
|
|
13181
|
+
}
|
|
13182
|
+
if (granularity === "second") {
|
|
13183
|
+
const h = curH ?? refBase.getHours(), m = curM ?? 0;
|
|
13184
|
+
columns.push({ key: "s", head: "sec", aria: "Second", items: range(0, 60, secondStep).map((sv) => ({
|
|
13185
|
+
val: sv,
|
|
13186
|
+
text: pad(sv),
|
|
13187
|
+
selected: curS != null && sv === curS,
|
|
13188
|
+
disabled: outOfRange(h, m, sv),
|
|
13189
|
+
onSelect: () => pickSecond(sv)
|
|
13190
|
+
})) });
|
|
13191
|
+
}
|
|
13192
|
+
if (hourCycle === 12) {
|
|
13193
|
+
columns.push({ key: "mer", head: "", aria: "AM or PM", items: ["AM", "PM"].map((mer) => ({
|
|
13194
|
+
val: mer,
|
|
13195
|
+
text: mer,
|
|
13196
|
+
selected: curH != null && curMer === mer,
|
|
13197
|
+
disabled: [...Array(12)].every((_, i) => {
|
|
13198
|
+
const hh = mer === "AM" ? i : i + 12;
|
|
13199
|
+
return outOfRange(hh, 0, 0) && outOfRange(hh, 59, 59);
|
|
13200
|
+
}),
|
|
13201
|
+
onSelect: () => pickMeridiem(mer)
|
|
13202
|
+
})) });
|
|
13203
|
+
}
|
|
13204
|
+
const onOptKey = (e) => {
|
|
13205
|
+
const btn = e.target;
|
|
13206
|
+
const col = btn.closest("[data-col]");
|
|
13207
|
+
if (!col) return;
|
|
13208
|
+
const opts = Array.from(col.querySelectorAll(".twc-tp__opt:not(:disabled)"));
|
|
13209
|
+
const i = opts.indexOf(btn);
|
|
13210
|
+
let target;
|
|
13211
|
+
if (e.key === "ArrowDown") target = opts[Math.min(i + 1, opts.length - 1)];
|
|
13212
|
+
else if (e.key === "ArrowUp") target = opts[Math.max(i - 1, 0)];
|
|
13213
|
+
else if (e.key === "Home") target = opts[0];
|
|
13214
|
+
else if (e.key === "End") target = opts[opts.length - 1];
|
|
13215
|
+
else if (e.key === "ArrowRight" || e.key === "ArrowLeft") {
|
|
13216
|
+
const cols = Array.from(popRef.current.querySelectorAll("[data-col]"));
|
|
13217
|
+
const nextCol = cols[cols.indexOf(col) + (e.key === "ArrowRight" ? 1 : -1)];
|
|
13218
|
+
if (nextCol) {
|
|
13219
|
+
const nopts = Array.from(nextCol.querySelectorAll(".twc-tp__opt:not(:disabled)"));
|
|
13220
|
+
target = nextCol.querySelector('.twc-tp__opt[data-selected="true"]') || nopts[Math.min(i, nopts.length - 1)] || nopts[0];
|
|
13221
|
+
}
|
|
13222
|
+
} else return;
|
|
13223
|
+
e.preventDefault();
|
|
13224
|
+
target?.focus();
|
|
13225
|
+
};
|
|
13226
|
+
const clockIcon = /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
13227
|
+
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "9" }),
|
|
13228
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 7v5l3 2" })
|
|
13229
|
+
] });
|
|
13230
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-tp twc-field ${className}`, ref: wrapRef, ...rest, children: [
|
|
13231
|
+
__twcStyles0,
|
|
13232
|
+
__twcStyles1,
|
|
13233
|
+
label ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-field__label", id: `${fieldId}-label`, children: [
|
|
13234
|
+
label,
|
|
13235
|
+
required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-field__req", children: "*" }) : null
|
|
13236
|
+
] }) : null,
|
|
13237
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-tp__field", children: editable ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
13238
|
+
"div",
|
|
13239
|
+
{
|
|
13240
|
+
className: "twc-tp__control twc-tp__control--editable",
|
|
13241
|
+
"data-open": open || void 0,
|
|
13242
|
+
"data-disabled": disabled || void 0,
|
|
13243
|
+
"data-tone": tone,
|
|
13244
|
+
"data-invalid": invalid || void 0,
|
|
13245
|
+
"data-size": size,
|
|
13246
|
+
children: [
|
|
13247
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13248
|
+
"input",
|
|
13249
|
+
{
|
|
13250
|
+
ref: triggerRef,
|
|
13251
|
+
className: "twc-tp__input",
|
|
13252
|
+
id: fieldId,
|
|
13253
|
+
type: "text",
|
|
13254
|
+
inputMode: "numeric",
|
|
13255
|
+
autoComplete: "off",
|
|
13256
|
+
disabled,
|
|
13257
|
+
placeholder,
|
|
13258
|
+
value: editText != null ? editText : selected ? fmt(selected) : "",
|
|
13259
|
+
"aria-haspopup": "dialog",
|
|
13260
|
+
"aria-expanded": open,
|
|
13261
|
+
"aria-labelledby": label ? `${fieldId}-label` : void 0,
|
|
13262
|
+
"aria-invalid": invalid || void 0,
|
|
13263
|
+
"aria-describedby": error || hint ? descId : void 0,
|
|
13264
|
+
onChange: (e) => setEditText(e.target.value),
|
|
13265
|
+
onKeyDown: (e) => {
|
|
13266
|
+
if (e.key === "Enter") {
|
|
13267
|
+
e.preventDefault();
|
|
13268
|
+
commitText();
|
|
13269
|
+
} else if (e.key === "ArrowDown" && (e.altKey || !open)) {
|
|
13270
|
+
e.preventDefault();
|
|
13271
|
+
setOpen(true);
|
|
13272
|
+
} else if (e.key === "Escape" && open) setOpen(false);
|
|
13273
|
+
},
|
|
13274
|
+
onBlur: (e) => {
|
|
13275
|
+
if (popRef.current && popRef.current.contains(e.relatedTarget)) return;
|
|
13276
|
+
commitText();
|
|
13277
|
+
}
|
|
13278
|
+
}
|
|
13279
|
+
),
|
|
13280
|
+
clearable && selected && !disabled ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
13281
|
+
"button",
|
|
13282
|
+
{
|
|
13283
|
+
type: "button",
|
|
13284
|
+
className: "twc-tp__clear twc-tp__clear--inline",
|
|
13285
|
+
"aria-label": "Clear",
|
|
13286
|
+
tabIndex: -1,
|
|
13287
|
+
onMouseDown: (e) => e.preventDefault(),
|
|
13288
|
+
onClick: clear,
|
|
13289
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) })
|
|
13290
|
+
}
|
|
13291
|
+
) : null,
|
|
13292
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13293
|
+
"button",
|
|
13294
|
+
{
|
|
13295
|
+
type: "button",
|
|
13296
|
+
className: "twc-tp__toggle",
|
|
13297
|
+
"aria-label": "Open time list",
|
|
13298
|
+
tabIndex: -1,
|
|
13299
|
+
disabled,
|
|
13300
|
+
onClick: () => !disabled && setOpen((o) => !o),
|
|
13301
|
+
children: clockIcon
|
|
13302
|
+
}
|
|
13303
|
+
)
|
|
13304
|
+
]
|
|
13305
|
+
}
|
|
13306
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
13307
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
13308
|
+
"div",
|
|
13309
|
+
{
|
|
13310
|
+
ref: triggerRef,
|
|
13311
|
+
className: "twc-tp__control",
|
|
13312
|
+
id: fieldId,
|
|
13313
|
+
"data-open": open || void 0,
|
|
13314
|
+
"data-disabled": disabled || void 0,
|
|
13315
|
+
"data-size": size,
|
|
13316
|
+
"data-tone": tone,
|
|
13317
|
+
"data-has-clear": clearable && selected && !disabled ? "true" : void 0,
|
|
13318
|
+
"data-invalid": invalid || void 0,
|
|
13319
|
+
role: "button",
|
|
13320
|
+
tabIndex: disabled ? -1 : 0,
|
|
13321
|
+
"aria-haspopup": "dialog",
|
|
13322
|
+
"aria-expanded": open,
|
|
13323
|
+
"aria-labelledby": label ? `${fieldId}-label` : void 0,
|
|
13324
|
+
"aria-invalid": invalid || void 0,
|
|
13325
|
+
"aria-describedby": error || hint ? descId : void 0,
|
|
13326
|
+
onClick: () => !disabled && setOpen((o) => !o),
|
|
13327
|
+
onKeyDown: (e) => {
|
|
13328
|
+
if ((e.key === "Enter" || e.key === " ") && !disabled) {
|
|
13329
|
+
e.preventDefault();
|
|
13330
|
+
setOpen((o) => !o);
|
|
13331
|
+
}
|
|
13332
|
+
},
|
|
13333
|
+
children: [
|
|
13334
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-tp__ic", "aria-hidden": "true", children: clockIcon }),
|
|
13335
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-tp__text", "data-placeholder": !selected || void 0, children: selected ? fmt(selected) : placeholder })
|
|
13336
|
+
]
|
|
13337
|
+
}
|
|
13338
|
+
),
|
|
13339
|
+
clearable && selected && !disabled ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-tp__clear", "aria-label": "Clear", onClick: (e) => {
|
|
13340
|
+
e.stopPropagation();
|
|
13341
|
+
clear();
|
|
13342
|
+
}, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) }) : null
|
|
13343
|
+
] }) }),
|
|
13344
|
+
open && coords ? reactDom.createPortal(
|
|
13345
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13346
|
+
"div",
|
|
13347
|
+
{
|
|
13348
|
+
className: "twc-tp__pop",
|
|
13349
|
+
ref: popRef,
|
|
13350
|
+
role: "dialog",
|
|
13351
|
+
"aria-modal": "true",
|
|
13352
|
+
"aria-label": "Choose time",
|
|
13353
|
+
style: { position: "fixed", left: coords.left, right: "auto", top: coords.top, bottom: coords.bottom, zIndex: "var(--z-tooltip)" },
|
|
13354
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-tp__cols", children: columns.map((col) => {
|
|
13355
|
+
const firstTab = col.items.find((it) => it.selected) || col.items.find((it) => !it.disabled);
|
|
13356
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-tp__col", role: "listbox", "aria-label": col.aria, "data-col": col.key, children: [
|
|
13357
|
+
col.head ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-tp__colhead", "aria-hidden": "true", children: col.head }) : null,
|
|
13358
|
+
col.items.map((it) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
13359
|
+
"button",
|
|
13360
|
+
{
|
|
13361
|
+
type: "button",
|
|
13362
|
+
className: "twc-tp__opt",
|
|
13363
|
+
role: "option",
|
|
13364
|
+
"aria-selected": it.selected || false,
|
|
13365
|
+
"data-selected": it.selected || void 0,
|
|
13366
|
+
"data-val": it.val,
|
|
13367
|
+
disabled: it.disabled || void 0,
|
|
13368
|
+
tabIndex: it === firstTab ? 0 : -1,
|
|
13369
|
+
onClick: it.onSelect,
|
|
13370
|
+
onKeyDown: onOptKey,
|
|
13371
|
+
children: it.text
|
|
13372
|
+
},
|
|
13373
|
+
it.val
|
|
13374
|
+
))
|
|
13375
|
+
] }, col.key);
|
|
13376
|
+
}) })
|
|
13377
|
+
}
|
|
13378
|
+
),
|
|
13379
|
+
document.body
|
|
13380
|
+
) : null,
|
|
13381
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
|
|
13382
|
+
] });
|
|
13383
|
+
}
|
|
13384
|
+
var FIELD_CSS6 = `
|
|
13385
|
+
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
13386
|
+
.twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
|
|
13387
|
+
.twc-field__req { color: var(--color-danger); }
|
|
13388
|
+
.twc-field__hint { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
13389
|
+
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
13390
|
+
`;
|
|
13391
|
+
var DTP_CSS = `
|
|
13392
|
+
.twc-dtp { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
13393
|
+
.twc-dtp__row { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: flex-start; }
|
|
13394
|
+
.twc-dtp__date { flex: 1 1 11rem; min-width: 9rem; }
|
|
13395
|
+
.twc-dtp__time { flex: 0 1 8rem; min-width: 7rem; }
|
|
13396
|
+
`;
|
|
13397
|
+
function DateTimePicker({
|
|
13398
|
+
label,
|
|
13399
|
+
hint,
|
|
13400
|
+
error,
|
|
13401
|
+
required = false,
|
|
13402
|
+
value,
|
|
13403
|
+
defaultValue = null,
|
|
13404
|
+
disabled = false,
|
|
13405
|
+
tone = "primary",
|
|
13406
|
+
size = "md",
|
|
13407
|
+
clearable = true,
|
|
13408
|
+
min,
|
|
13409
|
+
max,
|
|
13410
|
+
disabledDate,
|
|
13411
|
+
minuteStep = 5,
|
|
13412
|
+
secondStep = 5,
|
|
13413
|
+
granularity = "minute",
|
|
13414
|
+
hourCycle = 24,
|
|
13415
|
+
locale,
|
|
13416
|
+
weekStartsOn = 0,
|
|
13417
|
+
dateFormat,
|
|
13418
|
+
timeFormat,
|
|
13419
|
+
datePlaceholder = "Select date",
|
|
13420
|
+
timePlaceholder = "Time",
|
|
13421
|
+
onChange,
|
|
13422
|
+
id,
|
|
13423
|
+
className = "",
|
|
13424
|
+
...rest
|
|
13425
|
+
}) {
|
|
13426
|
+
const __twcStyles0 = useScopedStyles("twc-field-styles", FIELD_CSS6);
|
|
13427
|
+
const __twcStyles1 = useScopedStyles("twc-datetimepicker-styles", DTP_CSS);
|
|
13428
|
+
const autoId = React51__namespace.default.useId();
|
|
13429
|
+
const fieldId = id || autoId;
|
|
13430
|
+
const descId = `${fieldId}-desc`;
|
|
13431
|
+
const [internal, setInternal] = React51__namespace.default.useState(defaultValue);
|
|
13432
|
+
const selected = value !== void 0 ? value : internal;
|
|
13433
|
+
const commitVal = (d) => {
|
|
13434
|
+
if (value === void 0) setInternal(d);
|
|
13435
|
+
onChange?.(d);
|
|
13436
|
+
};
|
|
13437
|
+
const onDateChange = (d) => {
|
|
13438
|
+
if (!d) return commitVal(null);
|
|
13439
|
+
const b = selected;
|
|
13440
|
+
commitVal(new Date(d.getFullYear(), d.getMonth(), d.getDate(), b ? b.getHours() : 0, b ? b.getMinutes() : 0, b ? b.getSeconds() : 0, 0));
|
|
13441
|
+
};
|
|
13442
|
+
const onTimeChange = (t) => {
|
|
13443
|
+
if (!t) return;
|
|
13444
|
+
const b = selected;
|
|
13445
|
+
commitVal(new Date(b ? b.getFullYear() : t.getFullYear(), b ? b.getMonth() : t.getMonth(), b ? b.getDate() : t.getDate(), t.getHours(), t.getMinutes(), t.getSeconds(), 0));
|
|
13446
|
+
};
|
|
13447
|
+
const childTone = error ? "danger" : tone;
|
|
13448
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-dtp twc-field ${className}`, id: fieldId, ...rest, children: [
|
|
13449
|
+
__twcStyles0,
|
|
13450
|
+
__twcStyles1,
|
|
13451
|
+
label ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-field__label", id: `${fieldId}-label`, children: [
|
|
13452
|
+
label,
|
|
13453
|
+
required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-field__req", children: "*" }) : null
|
|
13454
|
+
] }) : null,
|
|
13455
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-dtp__row", role: "group", "aria-labelledby": label ? `${fieldId}-label` : void 0, "aria-describedby": error || hint ? descId : void 0, children: [
|
|
13456
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dtp__date", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13457
|
+
DatePicker,
|
|
13458
|
+
{
|
|
13459
|
+
value: selected,
|
|
13460
|
+
onChange: onDateChange,
|
|
13461
|
+
disabled,
|
|
13462
|
+
tone: childTone,
|
|
13463
|
+
size,
|
|
13464
|
+
clearable,
|
|
13465
|
+
min,
|
|
13466
|
+
max,
|
|
13467
|
+
disabledDate,
|
|
13468
|
+
locale,
|
|
13469
|
+
weekStartsOn,
|
|
13470
|
+
format: dateFormat,
|
|
13471
|
+
placeholder: datePlaceholder,
|
|
13472
|
+
"aria-label": "Date"
|
|
13473
|
+
}
|
|
13474
|
+
) }),
|
|
13475
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-dtp__time", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
13476
|
+
TimePicker,
|
|
13477
|
+
{
|
|
13478
|
+
value: selected,
|
|
13479
|
+
onChange: onTimeChange,
|
|
13480
|
+
disabled,
|
|
13481
|
+
tone: childTone,
|
|
13482
|
+
size,
|
|
13483
|
+
clearable: false,
|
|
13484
|
+
minuteStep,
|
|
13485
|
+
secondStep,
|
|
13486
|
+
granularity,
|
|
13487
|
+
hourCycle,
|
|
13488
|
+
locale,
|
|
13489
|
+
referenceDate: selected || void 0,
|
|
13490
|
+
format: timeFormat,
|
|
13491
|
+
placeholder: timePlaceholder,
|
|
13492
|
+
"aria-label": "Time"
|
|
13493
|
+
}
|
|
13494
|
+
) })
|
|
13495
|
+
] }),
|
|
13496
|
+
error ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__error", children: error }) : hint ? /* @__PURE__ */ jsxRuntime.jsx("span", { id: descId, className: "twc-field__hint", children: hint }) : null
|
|
13497
|
+
] });
|
|
13498
|
+
}
|
|
13499
|
+
var FILTERBAR_CSS = `
|
|
13500
|
+
.twc-fbar { font-family: var(--font-sans); display: flex; flex-wrap: wrap; align-items: flex-end; gap: var(--space-3); }
|
|
13501
|
+
.twc-fbar__field { display: flex; flex-direction: column; min-width: 170px; }
|
|
13502
|
+
.twc-fbar__field[data-type="search"], .twc-fbar__field[data-type="text"] { flex: 1 1 200px; }
|
|
13503
|
+
.twc-fbar__field[data-type="daterange"] { min-width: 220px; }
|
|
13504
|
+
.twc-fbar__field[data-type="boolean"], .twc-fbar__field[data-type="number"] { min-width: 130px; }
|
|
13505
|
+
.twc-fbar__labelrow { display: flex; align-items: center; gap: 6px; min-height: 18px; margin-bottom: var(--space-1); }
|
|
13506
|
+
.twc-fbar__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); }
|
|
13507
|
+
.twc-fbar__clearone { display: inline-grid; place-items: center; width: 16px; height: 16px; border: none; background: transparent; color: var(--color-text-subtle); cursor: pointer; border-radius: var(--radius-full); padding: 0; }
|
|
13508
|
+
.twc-fbar__clearone:hover { background: var(--color-surface-sunken); color: var(--color-text); }
|
|
13509
|
+
.twc-fbar__clearone svg { width: 11px; height: 11px; }
|
|
13510
|
+
.twc-fbar__actions { display: flex; align-items: center; gap: var(--space-2); }
|
|
13511
|
+
.twc-fbar__clearall { display: inline-flex; align-items: center; gap: 6px; height: var(--control-h-md); padding: 0 var(--space-3); border: var(--border-thin) solid var(--color-border); background: var(--color-surface); color: var(--color-text-muted); border-radius: var(--radius-md); cursor: pointer; font-family: inherit; font-size: var(--text-sm); font-weight: var(--font-medium); transition: background-color var(--duration-fast), color var(--duration-fast), border-color var(--duration-fast); }
|
|
13512
|
+
.twc-fbar__clearall:hover:not(:disabled) { background: var(--color-surface-sunken); color: var(--color-text); border-color: var(--color-border-strong); }
|
|
13513
|
+
.twc-fbar__clearall:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
13514
|
+
.twc-fbar__clearall svg { width: 15px; height: 15px; }
|
|
13515
|
+
`;
|
|
13516
|
+
var isEmpty = (f, v) => {
|
|
13517
|
+
if (v == null) return true;
|
|
13518
|
+
if (f.type === "multiselect" || f.type === "select-multiple") return !Array.isArray(v) || v.length === 0;
|
|
13519
|
+
if (f.type === "daterange") return v.start == null && v.end == null;
|
|
13520
|
+
return v === "";
|
|
13521
|
+
};
|
|
13522
|
+
var emptyFor = (f) => f.type === "multiselect" ? [] : f.type === "daterange" ? { start: null, end: null } : void 0;
|
|
13523
|
+
function valuesToClauses(fields, values) {
|
|
13524
|
+
const out = [];
|
|
13525
|
+
for (const f of fields) {
|
|
13526
|
+
const v = values[f.field];
|
|
13527
|
+
if (isEmpty(f, v)) continue;
|
|
13528
|
+
if (f.type === "multiselect") out.push({ field: f.field, op: "isAnyOf", value: v });
|
|
13529
|
+
else if (f.type === "daterange") {
|
|
13530
|
+
if (v.start != null) out.push({ field: f.field, op: ">=", value: v.start });
|
|
13531
|
+
if (v.end != null) out.push({ field: f.field, op: "<", value: v.end });
|
|
13532
|
+
} else if (f.type === "search" || f.type === "text") out.push({ field: f.field, op: f.op || "contains", value: v });
|
|
13533
|
+
else if (f.type === "number") out.push({ field: f.field, op: f.op || "=", value: v });
|
|
13534
|
+
else if (f.type === "boolean") out.push({ field: f.field, op: "=", value: v });
|
|
13535
|
+
else out.push({ field: f.field, op: f.op || "=", value: v });
|
|
13536
|
+
}
|
|
13537
|
+
return out;
|
|
13538
|
+
}
|
|
13539
|
+
function clausesToValues(fields, clauses) {
|
|
13540
|
+
const v = {};
|
|
13541
|
+
for (const f of fields) v[f.field] = emptyFor(f);
|
|
13542
|
+
for (const c of clauses || []) {
|
|
13543
|
+
const f = fields.find((x) => x.field === c.field);
|
|
13544
|
+
if (!f) continue;
|
|
13545
|
+
if (f.type === "daterange") {
|
|
13546
|
+
v[f.field] = { ...v[f.field] || { start: null, end: null } };
|
|
13547
|
+
if (c.op === ">=" || c.op === ">") v[f.field].start = c.value;
|
|
13548
|
+
else if (c.op === "<" || c.op === "<=") v[f.field].end = c.value;
|
|
13549
|
+
} else if (f.type === "multiselect") {
|
|
13550
|
+
v[f.field] = Array.isArray(c.value) ? c.value : [];
|
|
13551
|
+
} else {
|
|
13552
|
+
v[f.field] = c.value;
|
|
13553
|
+
}
|
|
13554
|
+
}
|
|
13555
|
+
return v;
|
|
13556
|
+
}
|
|
13557
|
+
var xIcon = /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.4", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 6 6 18M6 6l12 12" }) });
|
|
13558
|
+
function FilterBar({
|
|
13559
|
+
fields = [],
|
|
13560
|
+
value,
|
|
13561
|
+
defaultValue = [],
|
|
13562
|
+
onChange,
|
|
13563
|
+
onValuesChange,
|
|
13564
|
+
showClearAll = false,
|
|
13565
|
+
clearAllLabel = "Clear all",
|
|
13566
|
+
showFieldClear = true,
|
|
13567
|
+
size = "md",
|
|
13568
|
+
tone = "primary",
|
|
13569
|
+
disabled = false,
|
|
13570
|
+
id,
|
|
13571
|
+
className = "",
|
|
13572
|
+
...rest
|
|
13573
|
+
}) {
|
|
13574
|
+
const styles = useScopedStyles("twc-filterbar-styles", FILTERBAR_CSS);
|
|
13575
|
+
const autoId = React51__namespace.default.useId();
|
|
13576
|
+
const fieldId = id || autoId;
|
|
13577
|
+
const [internal, setInternal] = React51__namespace.default.useState(defaultValue);
|
|
13578
|
+
const clauses = value !== void 0 ? value : internal;
|
|
13579
|
+
const values = React51__namespace.default.useMemo(() => clausesToValues(fields, clauses), [fields, clauses]);
|
|
13580
|
+
const emit = (nextValues) => {
|
|
13581
|
+
const next = valuesToClauses(fields, nextValues);
|
|
13582
|
+
if (value === void 0) setInternal(next);
|
|
13583
|
+
onChange?.(next);
|
|
13584
|
+
onValuesChange?.(nextValues);
|
|
13585
|
+
};
|
|
13586
|
+
const setField = (f, v) => emit({ ...values, [f.field]: v });
|
|
13587
|
+
const clearField = (f) => setField(f, emptyFor(f));
|
|
13588
|
+
const clearAll = () => {
|
|
13589
|
+
const cleared = {};
|
|
13590
|
+
for (const f of fields) cleared[f.field] = emptyFor(f);
|
|
13591
|
+
emit(cleared);
|
|
13592
|
+
};
|
|
13593
|
+
const activeCount = fields.reduce((n, f) => n + (isEmpty(f, values[f.field]) ? 0 : 1), 0);
|
|
13594
|
+
const control = (f) => {
|
|
13595
|
+
const v = values[f.field];
|
|
13596
|
+
const name = f.label || f.field;
|
|
13597
|
+
const opts = typeof f.options === "function" ? f.options(values) : f.options;
|
|
13598
|
+
const common = { size, disabled: disabled || f.disabled, "aria-label": name };
|
|
13599
|
+
if (f.type === "multiselect") {
|
|
13600
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13601
|
+
MultiSelect,
|
|
13602
|
+
{
|
|
13603
|
+
...common,
|
|
13604
|
+
options: opts || [],
|
|
13605
|
+
value: v || [],
|
|
13606
|
+
placeholder: f.placeholder || "Any",
|
|
13607
|
+
clearable: true,
|
|
13608
|
+
onChange: (next) => setField(f, next)
|
|
13609
|
+
}
|
|
13610
|
+
);
|
|
13611
|
+
}
|
|
13612
|
+
if (f.type === "daterange") {
|
|
13613
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13614
|
+
DateRangePicker,
|
|
13615
|
+
{
|
|
13616
|
+
...common,
|
|
13617
|
+
tone,
|
|
13618
|
+
value: v || { start: null, end: null },
|
|
13619
|
+
clearable: true,
|
|
13620
|
+
onChange: (range2) => setField(f, range2)
|
|
13621
|
+
}
|
|
13622
|
+
);
|
|
13623
|
+
}
|
|
13624
|
+
if (f.type === "boolean") {
|
|
13625
|
+
const boolOpts = [{ value: "", label: f.anyLabel || "Any" }, { value: "true", label: f.trueLabel || "Yes" }, { value: "false", label: f.falseLabel || "No" }];
|
|
13626
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13627
|
+
Select,
|
|
13628
|
+
{
|
|
13629
|
+
...common,
|
|
13630
|
+
searchable: false,
|
|
13631
|
+
options: boolOpts,
|
|
13632
|
+
value: v == null ? "" : String(v),
|
|
13633
|
+
onChange: (next) => setField(f, next === "" ? void 0 : next === "true")
|
|
13634
|
+
}
|
|
13635
|
+
);
|
|
13636
|
+
}
|
|
13637
|
+
if (f.type === "select") {
|
|
13638
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13639
|
+
Select,
|
|
13640
|
+
{
|
|
13641
|
+
...common,
|
|
13642
|
+
searchable: f.searchable,
|
|
13643
|
+
options: opts || [],
|
|
13644
|
+
value: v ?? "",
|
|
13645
|
+
placeholder: f.placeholder || "Any",
|
|
13646
|
+
portal: f.portal,
|
|
13647
|
+
onChange: (next) => setField(f, next === "" ? void 0 : next)
|
|
13648
|
+
}
|
|
13649
|
+
);
|
|
13650
|
+
}
|
|
13651
|
+
if (f.type === "number") {
|
|
13652
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13653
|
+
Input,
|
|
13654
|
+
{
|
|
13655
|
+
...common,
|
|
13656
|
+
type: "number",
|
|
13657
|
+
value: v ?? "",
|
|
13658
|
+
placeholder: f.placeholder,
|
|
13659
|
+
onChange: (e) => setField(f, e.target.value === "" ? void 0 : Number(e.target.value))
|
|
13660
|
+
}
|
|
13661
|
+
);
|
|
13662
|
+
}
|
|
13663
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
13664
|
+
Input,
|
|
13665
|
+
{
|
|
13666
|
+
...common,
|
|
13667
|
+
type: f.type === "search" ? "search" : "text",
|
|
13668
|
+
value: v ?? "",
|
|
13669
|
+
placeholder: f.placeholder || (f.type === "search" ? "Search\u2026" : ""),
|
|
13670
|
+
onChange: (e) => setField(f, e.target.value)
|
|
13671
|
+
}
|
|
13672
|
+
);
|
|
13673
|
+
};
|
|
13674
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-fbar ${className}`, id: fieldId, role: "group", "aria-label": "Filters", ...rest, children: [
|
|
13675
|
+
styles,
|
|
13676
|
+
fields.map((f) => {
|
|
13677
|
+
const active = !isEmpty(f, values[f.field]);
|
|
13678
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-fbar__field", "data-type": f.type, children: [
|
|
13679
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-fbar__labelrow", children: [
|
|
13680
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-fbar__label", children: f.label || f.field }),
|
|
13681
|
+
showFieldClear && active && !disabled ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-fbar__clearone", "aria-label": `Clear ${f.label || f.field}`, onClick: () => clearField(f), children: xIcon }) : null
|
|
13682
|
+
] }),
|
|
13683
|
+
control(f)
|
|
13684
|
+
] }, f.field);
|
|
13685
|
+
}),
|
|
13686
|
+
showClearAll ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-fbar__actions", children: /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "twc-fbar__clearall", onClick: clearAll, disabled: disabled || activeCount === 0, children: [
|
|
13687
|
+
xIcon,
|
|
13688
|
+
clearAllLabel,
|
|
13689
|
+
activeCount > 0 ? ` (${activeCount})` : ""
|
|
13690
|
+
] }) }) : null
|
|
13691
|
+
] });
|
|
13692
|
+
}
|
|
12195
13693
|
var DIALOG_CSS = `
|
|
12196
13694
|
.twc-dialog__overlay {
|
|
12197
13695
|
position: fixed; inset: 0; z-index: var(--z-modal);
|
|
@@ -12509,7 +14007,7 @@ function EmptyState({
|
|
|
12509
14007
|
actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-empty__actions", children: actions }) : null
|
|
12510
14008
|
] });
|
|
12511
14009
|
}
|
|
12512
|
-
var
|
|
14010
|
+
var FIELD_CSS7 = `
|
|
12513
14011
|
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
12514
14012
|
.twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
|
|
12515
14013
|
.twc-field__req { color: var(--color-danger); }
|
|
@@ -12528,7 +14026,7 @@ function Field({
|
|
|
12528
14026
|
children,
|
|
12529
14027
|
...rest
|
|
12530
14028
|
}) {
|
|
12531
|
-
const __twcStyles = useScopedStyles("twc-field-styles",
|
|
14029
|
+
const __twcStyles = useScopedStyles("twc-field-styles", FIELD_CSS7);
|
|
12532
14030
|
const autoId = React51__namespace.default.useId();
|
|
12533
14031
|
const fieldId = id || autoId;
|
|
12534
14032
|
const descId = `${fieldId}-desc`;
|
|
@@ -12549,6 +14047,8 @@ function Field({
|
|
|
12549
14047
|
}
|
|
12550
14048
|
var UPLOAD_CSS = `
|
|
12551
14049
|
.twc-upload { font-family: var(--font-sans); display: flex; flex-direction: column; gap: var(--space-3); }
|
|
14050
|
+
.twc-upload[data-size="sm"] { --_pad-y: var(--space-5); --_pad-x: var(--space-4); }
|
|
14051
|
+
.twc-upload[data-size="lg"] { --_pad-y: var(--space-10); --_pad-x: var(--space-8); }
|
|
12552
14052
|
.twc-field__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); display: flex; gap: 4px; align-items: center; }
|
|
12553
14053
|
.twc-field__req { color: var(--color-danger); }
|
|
12554
14054
|
.twc-field__hint { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
@@ -12556,7 +14056,7 @@ var UPLOAD_CSS = `
|
|
|
12556
14056
|
.twc-upload__zone[data-invalid="true"] { border-color: var(--color-danger); }
|
|
12557
14057
|
.twc-upload__zone {
|
|
12558
14058
|
display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center;
|
|
12559
|
-
gap: 6px; padding: var(--space-8) var(--space-6); cursor: pointer;
|
|
14059
|
+
gap: 6px; padding: var(--_pad-y, var(--space-8)) var(--_pad-x, var(--space-6)); cursor: pointer;
|
|
12560
14060
|
border: var(--border-medium) dashed var(--color-border-strong); border-radius: var(--radius-xl);
|
|
12561
14061
|
background: var(--color-surface); color: var(--color-text-muted);
|
|
12562
14062
|
transition: border-color var(--duration-fast) var(--ease-standard), background-color var(--duration-fast) var(--ease-standard);
|
|
@@ -12609,6 +14109,7 @@ function FileUpload({
|
|
|
12609
14109
|
accept,
|
|
12610
14110
|
multiple = false,
|
|
12611
14111
|
disabled = false,
|
|
14112
|
+
size = "md",
|
|
12612
14113
|
tone = "primary",
|
|
12613
14114
|
label,
|
|
12614
14115
|
hint,
|
|
@@ -12664,7 +14165,7 @@ function FileUpload({
|
|
|
12664
14165
|
function remove(i) {
|
|
12665
14166
|
set(files.filter((_, idx) => idx !== i));
|
|
12666
14167
|
}
|
|
12667
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-upload ${className}`, ...rest, children: [
|
|
14168
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-upload ${className}`, "data-size": size, ...rest, children: [
|
|
12668
14169
|
__twcStyles,
|
|
12669
14170
|
label ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "twc-field__label", htmlFor: fieldId, children: [
|
|
12670
14171
|
label,
|
|
@@ -13077,7 +14578,7 @@ button.twc-navbar__brand, a.twc-navbar__brand { cursor: pointer; }
|
|
|
13077
14578
|
.twc-navbar__menu-btn { display: inline-grid; }
|
|
13078
14579
|
}
|
|
13079
14580
|
`;
|
|
13080
|
-
function
|
|
14581
|
+
function safeHref6(url) {
|
|
13081
14582
|
if (url == null) return void 0;
|
|
13082
14583
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
13083
14584
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -13100,9 +14601,9 @@ function Navbar({
|
|
|
13100
14601
|
return /* @__PURE__ */ jsxRuntime.jsxs("header", { className: `twc-navbar ${className}`, "data-sticky": sticky || void 0, ...rest, children: [
|
|
13101
14602
|
__twcStyles,
|
|
13102
14603
|
onMenuClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-navbar__menu-btn", "aria-expanded": menuOpen, "aria-controls": menuControls, "aria-label": menuOpen ? "Close menu" : "Open menu", onClick: onMenuClick, children: /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M4 6h16M4 12h16M4 18h16" }) }) }) : null,
|
|
13103
|
-
brand ? brandHref ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "twc-navbar__brand", href:
|
|
14604
|
+
brand ? brandHref ? /* @__PURE__ */ jsxRuntime.jsx("a", { className: "twc-navbar__brand", href: safeHref6(brandHref), children: brand }) : onBrandClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "twc-navbar__brand", onClick: onBrandClick, children: brand }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-navbar__brand", children: brand }) : null,
|
|
13104
14605
|
/* @__PURE__ */ jsxRuntime.jsx("nav", { className: "twc-navbar__links", "aria-label": navLabel, children: links.map((l, i) => {
|
|
13105
|
-
const href =
|
|
14606
|
+
const href = safeHref6(l.href);
|
|
13106
14607
|
const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
13107
14608
|
l.icon,
|
|
13108
14609
|
l.label
|
|
@@ -13462,6 +14963,7 @@ function Radio({
|
|
|
13462
14963
|
.twc-radio[data-invalid="true"] .twc-radio__dot { border-color: var(--color-danger); }
|
|
13463
14964
|
.twc-radio__text { display: flex; flex-direction: column; gap: 2px; }
|
|
13464
14965
|
.twc-radio__label { font-size: var(--text-sm); font-weight: var(--font-medium); color: var(--color-text); line-height: 1.3; }
|
|
14966
|
+
.twc-field__req { color: var(--color-danger); }
|
|
13465
14967
|
.twc-radio__desc { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
13466
14968
|
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
13467
14969
|
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
@@ -13497,7 +14999,10 @@ function Radio({
|
|
|
13497
14999
|
),
|
|
13498
15000
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-radio__dot", "aria-hidden": "true" }),
|
|
13499
15001
|
label || description ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-radio__text", children: [
|
|
13500
|
-
label ? /* @__PURE__ */ jsxRuntime.
|
|
15002
|
+
label ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-radio__label", children: [
|
|
15003
|
+
label,
|
|
15004
|
+
required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-field__req", children: "*" }) : null
|
|
15005
|
+
] }) : null,
|
|
13501
15006
|
description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-radio__desc", children: description }) : null
|
|
13502
15007
|
] }) : null
|
|
13503
15008
|
] });
|
|
@@ -14027,20 +15532,23 @@ var SLIDER_CSS = `
|
|
|
14027
15532
|
.twc-slider__msgs { display: flex; flex-direction: column; gap: var(--space-1-5); margin-top: var(--space-2); }
|
|
14028
15533
|
.twc-field__hint { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
14029
15534
|
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
15535
|
+
.twc-slider { --_track-h: 22px; --_thumb: 18px; --_rail: 6px; }
|
|
15536
|
+
.twc-slider[data-size="sm"] { --_track-h: 18px; --_thumb: 14px; --_rail: 4px; }
|
|
15537
|
+
.twc-slider[data-size="lg"] { --_track-h: 28px; --_thumb: 22px; --_rail: 8px; }
|
|
14030
15538
|
.twc-slider__head { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: var(--space-2); }
|
|
14031
15539
|
.twc-slider__label { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--color-text); }
|
|
14032
15540
|
.twc-slider__value { font-size: var(--text-sm); font-weight: var(--font-semibold); color: var(--_accent); font-variant-numeric: tabular-nums; }
|
|
14033
15541
|
.twc-slider__track {
|
|
14034
|
-
position: relative; height:
|
|
15542
|
+
position: relative; height: var(--_track-h); display: flex; align-items: center; cursor: pointer; touch-action: none;
|
|
14035
15543
|
}
|
|
14036
15544
|
.twc-slider[data-disabled="true"] { opacity: 0.55; }
|
|
14037
15545
|
.twc-slider[data-disabled="true"] .twc-slider__track { cursor: not-allowed; }
|
|
14038
|
-
.twc-slider__rail { position: absolute; left: 0; right: 0; height:
|
|
14039
|
-
.twc-slider__fill { position: absolute; height:
|
|
15546
|
+
.twc-slider__rail { position: absolute; left: 0; right: 0; height: var(--_rail); border-radius: var(--radius-full); background: var(--color-surface-sunken); box-shadow: inset 0 0 0 1px var(--color-border); }
|
|
15547
|
+
.twc-slider__fill { position: absolute; height: var(--_rail); border-radius: var(--radius-full); background: var(--_accent); }
|
|
14040
15548
|
.twc-slider__thumb {
|
|
14041
|
-
position: absolute; width:
|
|
15549
|
+
position: absolute; width: var(--_thumb); height: var(--_thumb); border-radius: var(--radius-full);
|
|
14042
15550
|
background: var(--color-surface); border: var(--border-thick) solid var(--_accent);
|
|
14043
|
-
box-shadow: var(--shadow-sm); transform: translateX(-50%); top: 50%; margin-top: -
|
|
15551
|
+
box-shadow: var(--shadow-sm); transform: translateX(-50%); top: 50%; margin-top: calc(var(--_thumb) / -2);
|
|
14044
15552
|
transition: box-shadow var(--duration-fast) var(--ease-standard), transform var(--duration-fast) var(--ease-spring);
|
|
14045
15553
|
}
|
|
14046
15554
|
.twc-slider__thumb:focus-visible { outline: none; box-shadow: var(--ring); }
|
|
@@ -14068,7 +15576,8 @@ function Slider({
|
|
|
14068
15576
|
precision,
|
|
14069
15577
|
tone = "primary",
|
|
14070
15578
|
disabled = false,
|
|
14071
|
-
|
|
15579
|
+
size = "md",
|
|
15580
|
+
range: range2 = false,
|
|
14072
15581
|
showValue = true,
|
|
14073
15582
|
showTicks = false,
|
|
14074
15583
|
formatValue,
|
|
@@ -14096,7 +15605,7 @@ function Slider({
|
|
|
14096
15605
|
const __twcStyles = useScopedStyles("twc-slider-styles", SLIDER_CSS);
|
|
14097
15606
|
const autoId = React51__namespace.default.useId();
|
|
14098
15607
|
const fieldId = id || autoId;
|
|
14099
|
-
const isRange =
|
|
15608
|
+
const isRange = range2 || Array.isArray(value) || Array.isArray(defaultValue);
|
|
14100
15609
|
const [internal, setInternal] = React51__namespace.default.useState(() => {
|
|
14101
15610
|
if (isRange) {
|
|
14102
15611
|
const dv = Array.isArray(defaultValue) ? defaultValue : [min, max];
|
|
@@ -14184,7 +15693,7 @@ function Slider({
|
|
|
14184
15693
|
const fillLo = (Math.min(...clampedVals) - min) / (max - min) * 100;
|
|
14185
15694
|
const fillHi = (Math.max(...clampedVals) - min) / (max - min) * 100;
|
|
14186
15695
|
const fillStyle = isRange ? { left: `${fillLo}%`, width: `${fillHi - fillLo}%` } : { width: `${fillHi}%` };
|
|
14187
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-slider ${className}`, "data-tone": tone, "data-disabled": disabled || void 0, ...rest, children: [
|
|
15696
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `twc-slider ${className}`, "data-tone": tone, "data-size": size, "data-disabled": disabled || void 0, ...rest, children: [
|
|
14188
15697
|
__twcStyles,
|
|
14189
15698
|
name ? clampedVals.map((v, i) => /* @__PURE__ */ jsxRuntime.jsx("input", { type: "hidden", name, value: v, disabled: disabled || void 0 }, i)) : null,
|
|
14190
15699
|
label || showValue ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "twc-slider__head", children: [
|
|
@@ -14236,10 +15745,10 @@ function Spinner({
|
|
|
14236
15745
|
className = "",
|
|
14237
15746
|
...rest
|
|
14238
15747
|
}) {
|
|
14239
|
-
if (process.env.NODE_ENV !== "production" &&
|
|
14240
|
-
warnOnce("Spinner.
|
|
15748
|
+
if (process.env.NODE_ENV !== "production" && color !== void 0 && tone === void 0) {
|
|
15749
|
+
warnOnce("Spinner.color", "Spinner: `color` is deprecated and will be removed in 2.0 \u2014 use `tone` (matches every other tone-driven component).");
|
|
14241
15750
|
}
|
|
14242
|
-
const
|
|
15751
|
+
const resolvedTone = tone ?? color ?? "current";
|
|
14243
15752
|
const __twcStyles = useScopedStyles("twc-spinner-styles", `
|
|
14244
15753
|
.twc-spinner {
|
|
14245
15754
|
--_sz: 24px; --_bw: 2.5px;
|
|
@@ -14265,7 +15774,7 @@ function Spinner({
|
|
|
14265
15774
|
.twc-spinner { animation-duration: 0.65s !important; animation-iteration-count: infinite !important; }
|
|
14266
15775
|
}
|
|
14267
15776
|
`);
|
|
14268
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `twc-spinner ${className}`, "data-size": size, "data-tone":
|
|
15777
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: `twc-spinner ${className}`, "data-size": size, "data-tone": resolvedTone, role: "status", "aria-label": label, ...rest, children: __twcStyles });
|
|
14269
15778
|
}
|
|
14270
15779
|
var STAT_CSS = `
|
|
14271
15780
|
.twc-stat { display: flex; flex-direction: column; gap: 6px; font-family: var(--font-sans);
|
|
@@ -14499,6 +16008,7 @@ function Switch({
|
|
|
14499
16008
|
.twc-switch[data-invalid="true"] .twc-switch__track { box-shadow: inset 0 0 0 var(--border-medium) var(--color-danger); }
|
|
14500
16009
|
.twc-switch__text { display: flex; flex-direction: column; gap: 2px; }
|
|
14501
16010
|
.twc-switch__label { font-size: var(--text-sm); font-weight: var(--font-medium); color: var(--color-text); line-height: 1.3; }
|
|
16011
|
+
.twc-field__req { color: var(--color-danger); }
|
|
14502
16012
|
.twc-switch__desc { font-size: var(--text-xs); color: var(--color-text-muted); }
|
|
14503
16013
|
.twc-field { display: flex; flex-direction: column; gap: var(--space-1-5); font-family: var(--font-sans); }
|
|
14504
16014
|
.twc-field__error { font-size: var(--text-xs); color: var(--color-danger-subtle-fg); font-weight: var(--font-medium); }
|
|
@@ -14533,7 +16043,10 @@ function Switch({
|
|
|
14533
16043
|
),
|
|
14534
16044
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-switch__track", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-switch__thumb" }) }),
|
|
14535
16045
|
label || description ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-switch__text", children: [
|
|
14536
|
-
label ? /* @__PURE__ */ jsxRuntime.
|
|
16046
|
+
label ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "twc-switch__label", children: [
|
|
16047
|
+
label,
|
|
16048
|
+
required ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-field__req", children: "*" }) : null
|
|
16049
|
+
] }) : null,
|
|
14537
16050
|
description ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "twc-switch__desc", children: description }) : null
|
|
14538
16051
|
] }) : null
|
|
14539
16052
|
] });
|
|
@@ -14746,6 +16259,11 @@ var TABS_CSS = `
|
|
|
14746
16259
|
top: auto; inset-inline-end: 4px; inset-inline-start: 4px; width: auto;
|
|
14747
16260
|
}
|
|
14748
16261
|
.twc-tabs[data-orientation="vertical"] .twc-tabs__panel { padding-top: 0; flex: 1; min-width: 0; }
|
|
16262
|
+
/* WCAG 2.3.3: the active-tab indicator jumps instead of sliding under reduced motion (both
|
|
16263
|
+
the horizontal left/width and vertical top/height variants). */
|
|
16264
|
+
@media (prefers-reduced-motion: reduce) {
|
|
16265
|
+
.twc-tabs__indicator, .twc-tabs[data-orientation="vertical"] .twc-tabs__indicator { transition: none; }
|
|
16266
|
+
}
|
|
14749
16267
|
`;
|
|
14750
16268
|
function Tabs({
|
|
14751
16269
|
items,
|
|
@@ -15124,6 +16642,12 @@ var TOAST_CSS = `
|
|
|
15124
16642
|
from { opacity: 0; transform: translateX(-24px); }
|
|
15125
16643
|
to { opacity: 1; transform: translateX(0); }
|
|
15126
16644
|
}
|
|
16645
|
+
/* WCAG 2.3.3: appear without the slide under reduced motion (covers the RTL variant too). */
|
|
16646
|
+
@media (prefers-reduced-motion: reduce) {
|
|
16647
|
+
.twc-toast, [dir="rtl"] .twc-toast { animation: none; }
|
|
16648
|
+
}
|
|
16649
|
+
/* #209: visually-hidden persistent live-region announcers (rendered by ToastProvider). */
|
|
16650
|
+
.twc-toast-sr { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
|
|
15127
16651
|
.twc-toast::before { content: ""; position: absolute; inset-inline-start: 0; top: 0; bottom: 0; width: 4px; background: var(--_accent, var(--color-primary)); }
|
|
15128
16652
|
.twc-toast[data-tone="success"] { --_accent: var(--color-success); }
|
|
15129
16653
|
.twc-toast[data-tone="warning"] { --_accent: var(--color-warning); }
|
|
@@ -15240,6 +16764,8 @@ function useToast() {
|
|
|
15240
16764
|
}
|
|
15241
16765
|
function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps }) {
|
|
15242
16766
|
const [toasts, setToasts] = React51__namespace.default.useState([]);
|
|
16767
|
+
const [politeMsg, setPoliteMsg] = React51__namespace.default.useState("");
|
|
16768
|
+
const [assertiveMsg, setAssertiveMsg] = React51__namespace.default.useState("");
|
|
15243
16769
|
const idRef = React51__namespace.default.useRef(0);
|
|
15244
16770
|
const limitRef = React51__namespace.default.useRef(limit);
|
|
15245
16771
|
React51__namespace.default.useEffect(() => {
|
|
@@ -15258,6 +16784,12 @@ function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps
|
|
|
15258
16784
|
const n = limitRef.current;
|
|
15259
16785
|
return n && n > 0 ? arr.slice(-n) : arr;
|
|
15260
16786
|
});
|
|
16787
|
+
const parts = [next.title, next.description != null ? next.description : next.children].filter((p) => typeof p === "string" || typeof p === "number").map(String);
|
|
16788
|
+
const msg = parts.join(". ").trim();
|
|
16789
|
+
if (msg) {
|
|
16790
|
+
const setter = next.tone === "danger" || next.tone === "warning" ? setAssertiveMsg : setPoliteMsg;
|
|
16791
|
+
setter((prev) => prev === msg ? msg + "\u200B" : msg);
|
|
16792
|
+
}
|
|
15261
16793
|
return id;
|
|
15262
16794
|
};
|
|
15263
16795
|
const withTone = (tone) => (title, options) => push(typeof title === "object" && title !== null ? { tone, ...title } : { tone, title, ...options });
|
|
@@ -15273,12 +16805,15 @@ function ToastProvider({ children, limit = 4, duration = 4500, ...viewportProps
|
|
|
15273
16805
|
const value = React51__namespace.default.useMemo(() => ({ ...api, toasts }), [api, toasts]);
|
|
15274
16806
|
return /* @__PURE__ */ jsxRuntime.jsxs(ToastContext.Provider, { value, children: [
|
|
15275
16807
|
children,
|
|
16808
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-toast-sr", "aria-live": "polite", "aria-atomic": "true", children: politeMsg }),
|
|
16809
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "twc-toast-sr", "aria-live": "assertive", "aria-atomic": "true", children: assertiveMsg }),
|
|
15276
16810
|
/* @__PURE__ */ jsxRuntime.jsx(ToastViewport, { limit, ...viewportProps, children: toasts.map((t) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
15277
16811
|
Toast,
|
|
15278
16812
|
{
|
|
15279
16813
|
tone: t.tone,
|
|
15280
16814
|
title: t.title,
|
|
15281
16815
|
icon: t.icon,
|
|
16816
|
+
role: "group",
|
|
15282
16817
|
duration: t.duration != null ? t.duration : duration,
|
|
15283
16818
|
onClose: () => dismiss(t.id),
|
|
15284
16819
|
children: t.description != null ? t.description : t.children
|
|
@@ -15552,7 +17087,7 @@ function bgValue(bg) {
|
|
|
15552
17087
|
if (BG[bg]) return `var(${BG[bg]})`;
|
|
15553
17088
|
return String(bg).startsWith("--") ? `var(${bg})` : bg;
|
|
15554
17089
|
}
|
|
15555
|
-
function
|
|
17090
|
+
function safeHref7(url) {
|
|
15556
17091
|
if (url == null) return void 0;
|
|
15557
17092
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15558
17093
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -15600,7 +17135,7 @@ var Box = React51__namespace.default.forwardRef(function Box2({
|
|
|
15600
17135
|
...style,
|
|
15601
17136
|
...flatStyle
|
|
15602
17137
|
};
|
|
15603
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
17138
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref7(rest.href);
|
|
15604
17139
|
return /* @__PURE__ */ jsxRuntime.jsxs(Tag2, { ref, className: `twc-box ${className}`.trim(), style: s, "data-twc-sx": sxAttr, ...rest, children: [
|
|
15605
17140
|
styleNode,
|
|
15606
17141
|
children
|
|
@@ -15608,7 +17143,7 @@ var Box = React51__namespace.default.forwardRef(function Box2({
|
|
|
15608
17143
|
});
|
|
15609
17144
|
Box.displayName = "Box";
|
|
15610
17145
|
var SIZES = { sm: 640, md: 768, lg: 1024, xl: 1280, full: "100%" };
|
|
15611
|
-
function
|
|
17146
|
+
function safeHref8(url) {
|
|
15612
17147
|
if (url == null) return void 0;
|
|
15613
17148
|
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15614
17149
|
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
@@ -15625,7 +17160,7 @@ var Container = React51__namespace.default.forwardRef(function Container2({
|
|
|
15625
17160
|
}, ref) {
|
|
15626
17161
|
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
15627
17162
|
const max = SIZES[size] ?? size;
|
|
15628
|
-
if (Tag2 === "a" && rest.href != null) rest.href =
|
|
17163
|
+
if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
|
|
15629
17164
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15630
17165
|
Tag2,
|
|
15631
17166
|
{
|
|
@@ -15651,83 +17186,6 @@ var Container = React51__namespace.default.forwardRef(function Container2({
|
|
|
15651
17186
|
);
|
|
15652
17187
|
});
|
|
15653
17188
|
Container.displayName = "Container";
|
|
15654
|
-
function space(v) {
|
|
15655
|
-
if (v == null) return void 0;
|
|
15656
|
-
if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
|
|
15657
|
-
return v;
|
|
15658
|
-
}
|
|
15659
|
-
function len(v) {
|
|
15660
|
-
return typeof v === "number" ? `${v}px` : v;
|
|
15661
|
-
}
|
|
15662
|
-
var BP = { sm: 640, md: 768, lg: 1024, xl: 1280 };
|
|
15663
|
-
function safeHref8(url) {
|
|
15664
|
-
if (url == null) return void 0;
|
|
15665
|
-
const s = String(url).replace(/[\x00-\x20]+/g, "").toLowerCase();
|
|
15666
|
-
return s.startsWith("javascript:") || s.startsWith("data:") || s.startsWith("vbscript:") ? void 0 : url;
|
|
15667
|
-
}
|
|
15668
|
-
var Grid = React51__namespace.default.forwardRef(function Grid2({
|
|
15669
|
-
as: Tag2 = "div",
|
|
15670
|
-
columns,
|
|
15671
|
-
minChildWidth,
|
|
15672
|
-
gap = 4,
|
|
15673
|
-
rowGap,
|
|
15674
|
-
columnGap,
|
|
15675
|
-
align,
|
|
15676
|
-
justify,
|
|
15677
|
-
alignContent,
|
|
15678
|
-
justifyContent,
|
|
15679
|
-
sx,
|
|
15680
|
-
className = "",
|
|
15681
|
-
style,
|
|
15682
|
-
children,
|
|
15683
|
-
...rest
|
|
15684
|
-
}, ref) {
|
|
15685
|
-
const { flatStyle, styleNode, sxAttr } = useSx(sx);
|
|
15686
|
-
const responsive = columns != null && typeof columns === "object";
|
|
15687
|
-
const uid = React51__namespace.default.useId();
|
|
15688
|
-
const gridId = responsive ? `g${uid.replace(/[^a-zA-Z0-9]/g, "")}` : null;
|
|
15689
|
-
let css = "";
|
|
15690
|
-
if (responsive) {
|
|
15691
|
-
const base = columns.base ?? 1;
|
|
15692
|
-
const sel = `[data-twc-grid-id="${gridId}"]`;
|
|
15693
|
-
css = `${sel} { --twc-grid-cols: ${base}; }`;
|
|
15694
|
-
for (const bp of ["sm", "md", "lg", "xl"]) {
|
|
15695
|
-
if (columns[bp] != null) css += `
|
|
15696
|
-
@media (min-width: ${BP[bp]}px) { ${sel} { --twc-grid-cols: ${columns[bp]}; } }`;
|
|
15697
|
-
}
|
|
15698
|
-
}
|
|
15699
|
-
const __twcStyles = useScopedStyles(gridId ? `twc-grid-${gridId}` : "twc-grid", css);
|
|
15700
|
-
const templateColumns = minChildWidth ? `repeat(auto-fill, minmax(min(${len(minChildWidth)}, 100%), 1fr))` : responsive ? `repeat(var(--twc-grid-cols, ${columns.base ?? 1}), minmax(0, 1fr))` : `repeat(${columns || 1}, minmax(0, 1fr))`;
|
|
15701
|
-
if (Tag2 === "a" && rest.href != null) rest.href = safeHref8(rest.href);
|
|
15702
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15703
|
-
Tag2,
|
|
15704
|
-
{
|
|
15705
|
-
ref,
|
|
15706
|
-
className: `twc-grid ${className}`.trim(),
|
|
15707
|
-
"data-twc-grid-id": gridId || void 0,
|
|
15708
|
-
"data-twc-sx": sxAttr,
|
|
15709
|
-
style: {
|
|
15710
|
-
display: "grid",
|
|
15711
|
-
gridTemplateColumns: templateColumns,
|
|
15712
|
-
rowGap: space(rowGap ?? gap),
|
|
15713
|
-
columnGap: space(columnGap ?? gap),
|
|
15714
|
-
alignItems: align,
|
|
15715
|
-
justifyItems: justify,
|
|
15716
|
-
alignContent,
|
|
15717
|
-
justifyContent,
|
|
15718
|
-
...style,
|
|
15719
|
-
...flatStyle
|
|
15720
|
-
},
|
|
15721
|
-
...rest,
|
|
15722
|
-
children: [
|
|
15723
|
-
responsive ? __twcStyles : null,
|
|
15724
|
-
styleNode,
|
|
15725
|
-
children
|
|
15726
|
-
]
|
|
15727
|
-
}
|
|
15728
|
-
);
|
|
15729
|
-
});
|
|
15730
|
-
Grid.displayName = "Grid";
|
|
15731
17189
|
function space2(v) {
|
|
15732
17190
|
if (v == null) return void 0;
|
|
15733
17191
|
if (typeof v === "number") return `var(--space-${String(v).replace(".", "-")})`;
|
|
@@ -16331,6 +17789,7 @@ exports.BubbleChart = BubbleChart;
|
|
|
16331
17789
|
exports.Button = Button;
|
|
16332
17790
|
exports.Candlestick = Candlestick;
|
|
16333
17791
|
exports.Card = Card;
|
|
17792
|
+
exports.CardGrid = CardGrid;
|
|
16334
17793
|
exports.Carousel = Carousel;
|
|
16335
17794
|
exports.Chart = Chart;
|
|
16336
17795
|
exports.Checkbox = Checkbox;
|
|
@@ -16345,13 +17804,16 @@ exports.CurrencyField = CurrencyField;
|
|
|
16345
17804
|
exports.Datatable = Datatable;
|
|
16346
17805
|
exports.DatePicker = DatePicker;
|
|
16347
17806
|
exports.DateRangePicker = DateRangePicker;
|
|
17807
|
+
exports.DateTimePicker = DateTimePicker;
|
|
16348
17808
|
exports.Dialog = Dialog;
|
|
17809
|
+
exports.DiffTable = DiffTable;
|
|
16349
17810
|
exports.Divider = Divider;
|
|
16350
17811
|
exports.DonutChart = DonutChart;
|
|
16351
17812
|
exports.Drawer = Drawer;
|
|
16352
17813
|
exports.EmptyState = EmptyState;
|
|
16353
17814
|
exports.Field = Field;
|
|
16354
17815
|
exports.FileUpload = FileUpload;
|
|
17816
|
+
exports.FilterBar = FilterBar;
|
|
16355
17817
|
exports.Form = Form;
|
|
16356
17818
|
exports.FunnelChart = FunnelChart;
|
|
16357
17819
|
exports.Gauge = Gauge;
|
|
@@ -16397,6 +17859,7 @@ exports.Tag = Tag;
|
|
|
16397
17859
|
exports.Text = Text;
|
|
16398
17860
|
exports.Textarea = Textarea;
|
|
16399
17861
|
exports.ThemeProvider = ThemeProvider;
|
|
17862
|
+
exports.TimePicker = TimePicker;
|
|
16400
17863
|
exports.Timeline = Timeline;
|
|
16401
17864
|
exports.Toast = Toast;
|
|
16402
17865
|
exports.ToastProvider = ToastProvider;
|