@roy-ui/ui 0.0.6 → 0.0.8

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.
Files changed (69) hide show
  1. package/dist/Button-OZLAH5NO.css +179 -0
  2. package/dist/{Pagination-FUYIHYSD.css → Pagination-LLKV7XXI.css} +3 -1
  3. package/dist/Table-qVdGZkB4.d.ts +42 -0
  4. package/dist/TimePicker-BhRta4MK.d.ts +39 -0
  5. package/dist/chunk-4SGMAZBG.js +161 -0
  6. package/dist/chunk-4SGMAZBG.js.map +1 -0
  7. package/dist/chunk-5CIBIH7R.js +98 -0
  8. package/dist/chunk-5CIBIH7R.js.map +1 -0
  9. package/dist/chunk-75IGGPXL.js +518 -0
  10. package/dist/chunk-75IGGPXL.js.map +1 -0
  11. package/dist/chunk-C5X3TE5U.js +87 -0
  12. package/dist/chunk-C5X3TE5U.js.map +1 -0
  13. package/dist/chunk-HUCK7AM7.js +840 -0
  14. package/dist/chunk-HUCK7AM7.js.map +1 -0
  15. package/dist/chunk-KSHKVSNK.js +82 -0
  16. package/dist/chunk-KSHKVSNK.js.map +1 -0
  17. package/dist/chunk-M6HB6BMA.js +101 -0
  18. package/dist/chunk-M6HB6BMA.js.map +1 -0
  19. package/dist/chunk-MDPMEW4K.js +58 -0
  20. package/dist/chunk-MDPMEW4K.js.map +1 -0
  21. package/dist/chunk-PGV55XSZ.js +107 -0
  22. package/dist/chunk-PGV55XSZ.js.map +1 -0
  23. package/dist/chunk-RLBVY3DG.js +64 -0
  24. package/dist/chunk-RLBVY3DG.js.map +1 -0
  25. package/dist/chunk-SFENGB5N.js +410 -0
  26. package/dist/chunk-SFENGB5N.js.map +1 -0
  27. package/dist/chunk-XERZVDIT.js +194 -0
  28. package/dist/chunk-XERZVDIT.js.map +1 -0
  29. package/dist/components/button/index.d.ts +37 -0
  30. package/dist/components/button/index.js +4 -0
  31. package/dist/components/button/index.js.map +1 -0
  32. package/dist/components/data-table/index.d.ts +145 -0
  33. package/dist/components/data-table/index.js +9 -0
  34. package/dist/components/data-table/index.js.map +1 -0
  35. package/dist/components/date-range-picker/index.d.ts +30 -0
  36. package/dist/components/date-range-picker/index.js +4 -0
  37. package/dist/components/date-range-picker/index.js.map +1 -0
  38. package/dist/components/gradient-button/index.d.ts +12 -0
  39. package/dist/components/gradient-button/index.js +4 -0
  40. package/dist/components/gradient-button/index.js.map +1 -0
  41. package/dist/components/made-by/index.d.ts +23 -0
  42. package/dist/components/made-by/index.js +4 -0
  43. package/dist/components/made-by/index.js.map +1 -0
  44. package/dist/components/pagination/index.d.ts +23 -0
  45. package/dist/components/pagination/index.js +4 -0
  46. package/dist/components/pagination/index.js.map +1 -0
  47. package/dist/components/popover/index.d.ts +18 -0
  48. package/dist/components/popover/index.js +4 -0
  49. package/dist/components/popover/index.js.map +1 -0
  50. package/dist/components/table/index.d.ts +28 -0
  51. package/dist/components/table/index.js +4 -0
  52. package/dist/components/table/index.js.map +1 -0
  53. package/dist/components/table-search/index.d.ts +19 -0
  54. package/dist/components/table-search/index.js +4 -0
  55. package/dist/components/table-search/index.js.map +1 -0
  56. package/dist/components/text-morph/index.d.ts +28 -0
  57. package/dist/components/text-morph/index.js +4 -0
  58. package/dist/components/text-morph/index.js.map +1 -0
  59. package/dist/components/time-picker/index.d.ts +14 -0
  60. package/dist/components/time-picker/index.js +4 -0
  61. package/dist/components/time-picker/index.js.map +1 -0
  62. package/dist/components/tree-nav/index.d.ts +30 -0
  63. package/dist/components/tree-nav/index.js +4 -0
  64. package/dist/components/tree-nav/index.js.map +1 -0
  65. package/dist/dateUtils-B_m_EICl.d.ts +14 -0
  66. package/dist/index.d.ts +17 -408
  67. package/dist/index.js +12 -2462
  68. package/dist/index.js.map +1 -1
  69. package/package.json +51 -2
package/dist/index.js CHANGED
@@ -1,2465 +1,15 @@
1
1
  "use client";
2
- import { forwardRef, useState, useRef, useEffect, Children, isValidElement, cloneElement, useMemo, useCallback } from 'react';
3
- import './GradientButton-TX2GJRIQ.css';
4
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
5
- import './Popover-LSYVKT4M.css';
6
- import './MadeBy-JCYGHWSD.css';
7
- import './TextMorph-RX2BX25F.css';
8
- import './TreeNav-22DY7TP5.css';
9
- import './Table-YTEWR635.css';
10
- import './TableSearch-UZO4ZJVE.css';
11
- import './Pagination-FUYIHYSD.css';
12
- import './DateRangePicker-BCP26AOC.css';
13
- import './TimePicker-44EKHQEJ.css';
14
- import './DataTable-TQ5OBNZF.css';
15
-
16
- // src/components/gradient-button/GradientButton.tsx
17
- var DefaultSpinner = () => /* @__PURE__ */ jsx("span", { className: "gradient-btn__spinner", "aria-hidden": "true", children: /* @__PURE__ */ jsxs("svg", { viewBox: "0 0 24 24", width: "18", height: "18", fill: "none", children: [
18
- /* @__PURE__ */ jsx(
19
- "circle",
20
- {
21
- cx: "12",
22
- cy: "12",
23
- r: "9",
24
- stroke: "currentColor",
25
- strokeOpacity: "0.3",
26
- strokeWidth: "2.5"
27
- }
28
- ),
29
- /* @__PURE__ */ jsx(
30
- "path",
31
- {
32
- d: "M21 12a9 9 0 0 0-9-9",
33
- stroke: "currentColor",
34
- strokeWidth: "2.5",
35
- strokeLinecap: "round"
36
- }
37
- )
38
- ] }) });
39
- var GradientButton = forwardRef(
40
- ({
41
- loading = false,
42
- loadingLabel,
43
- fullWidth = true,
44
- disabled,
45
- className = "",
46
- children,
47
- type = "button",
48
- ...rest
49
- }, ref) => {
50
- const classes = [
51
- "gradient-btn",
52
- fullWidth ? "gradient-btn--full" : "",
53
- loading ? "gradient-btn--loading" : "",
54
- className
55
- ].filter(Boolean).join(" ");
56
- return /* @__PURE__ */ jsx(
57
- "button",
58
- {
59
- ref,
60
- type,
61
- disabled: disabled || loading,
62
- className: classes,
63
- "aria-busy": loading || void 0,
64
- ...rest,
65
- children: loading ? loadingLabel ?? /* @__PURE__ */ jsx(DefaultSpinner, {}) : children
66
- }
67
- );
68
- }
69
- );
70
- GradientButton.displayName = "GradientButton";
71
- var InfoIcon = () => /* @__PURE__ */ jsxs(
72
- "svg",
73
- {
74
- width: "14",
75
- height: "14",
76
- viewBox: "0 0 24 24",
77
- fill: "none",
78
- stroke: "currentColor",
79
- strokeWidth: "1.5",
80
- strokeLinecap: "round",
81
- strokeLinejoin: "round",
82
- "aria-hidden": true,
83
- children: [
84
- /* @__PURE__ */ jsx("circle", { cx: "12", cy: "12", r: "9" }),
85
- /* @__PURE__ */ jsx("path", { d: "M12 16v-5M12 8h.01" })
86
- ]
87
- }
88
- );
89
- function Popover({
90
- children,
91
- title,
92
- align = "right",
93
- width = "md",
94
- label = "Open menu",
95
- defaultOpen = false,
96
- renderTrigger
97
- }) {
98
- const [open, setOpen] = useState(defaultOpen);
99
- const wrap2 = useRef(null);
100
- const toggle = () => setOpen((o) => !o);
101
- useEffect(() => {
102
- if (!open) return;
103
- function onDown(e) {
104
- if (wrap2.current && !wrap2.current.contains(e.target)) {
105
- setOpen(false);
106
- }
107
- }
108
- function onKey(e) {
109
- if (e.key === "Escape") setOpen(false);
110
- }
111
- document.addEventListener("mousedown", onDown);
112
- document.addEventListener("keydown", onKey);
113
- return () => {
114
- document.removeEventListener("mousedown", onDown);
115
- document.removeEventListener("keydown", onKey);
116
- };
117
- }, [open]);
118
- const trigger = renderTrigger ? renderTrigger({ isOpen: open, toggle }) : /* @__PURE__ */ jsx(
119
- "button",
120
- {
121
- type: "button",
122
- onClick: toggle,
123
- "aria-label": label,
124
- "aria-expanded": open,
125
- className: `royui-popover__trigger ${open ? "royui-popover__trigger--on" : ""}`,
126
- children: /* @__PURE__ */ jsx(InfoIcon, {})
127
- }
128
- );
129
- const widthClass = typeof width === "string" ? `royui-popover__panel--${width}` : "";
130
- const customWidth = typeof width === "number" ? { width: `${width}px` } : void 0;
131
- const alignClass = `royui-popover__panel--${align}`;
132
- return /* @__PURE__ */ jsxs("div", { ref: wrap2, className: "royui-popover", children: [
133
- trigger,
134
- open && /* @__PURE__ */ jsxs(
135
- "div",
136
- {
137
- className: `royui-popover__panel ${widthClass} ${alignClass}`,
138
- style: customWidth,
139
- role: "dialog",
140
- children: [
141
- title && /* @__PURE__ */ jsx("div", { className: "royui-popover__title", children: title }),
142
- /* @__PURE__ */ jsx("div", { className: "royui-popover__body", children })
143
- ]
144
- }
145
- )
146
- ] });
147
- }
148
- var MadeBy = forwardRef(
149
- ({
150
- name,
151
- href,
152
- prefix = "Made by",
153
- position = "bottom-right",
154
- icon,
155
- nameFont,
156
- nameStyle,
157
- className = "",
158
- target = "_blank",
159
- rel = "noopener noreferrer",
160
- ...rest
161
- }, ref) => {
162
- const classes = [
163
- "royui-madeby",
164
- `royui-madeby--${position}`,
165
- className
166
- ].filter(Boolean).join(" ");
167
- const nameStyles = {};
168
- if (nameFont) nameStyles.fontFamily = nameFont;
169
- if (nameStyle) nameStyles.fontStyle = nameStyle;
170
- return /* @__PURE__ */ jsxs(
171
- "a",
172
- {
173
- ref,
174
- href,
175
- target,
176
- rel,
177
- className: classes,
178
- ...rest,
179
- children: [
180
- icon && /* @__PURE__ */ jsx("span", { className: "royui-madeby__icon", "aria-hidden": true, children: icon }),
181
- /* @__PURE__ */ jsx("span", { className: "royui-madeby__prefix", children: prefix }),
182
- /* @__PURE__ */ jsx(
183
- "span",
184
- {
185
- className: "royui-madeby__name",
186
- style: Object.keys(nameStyles).length ? nameStyles : void 0,
187
- children: name
188
- }
189
- )
190
- ]
191
- }
192
- );
193
- }
194
- );
195
- MadeBy.displayName = "MadeBy";
196
- function sleep(ms) {
197
- return new Promise((resolve) => setTimeout(resolve, ms));
198
- }
199
- function findDiff(from, to) {
200
- let p = 0;
201
- const maxP = Math.min(from.length, to.length);
202
- while (p < maxP && from[p] === to[p]) p++;
203
- let s = 0;
204
- while (s < from.length - p && s < to.length - p && from[from.length - 1 - s] === to[to.length - 1 - s]) {
205
- s++;
206
- }
207
- return {
208
- prefix: from.slice(0, p),
209
- suffix: from.slice(from.length - s),
210
- oldMid: from.slice(p, from.length - s),
211
- newMid: to.slice(p, to.length - s)
212
- };
213
- }
214
- function rand(min, max) {
215
- return min + Math.random() * (max - min);
216
- }
217
- var TextMorph = forwardRef(
218
- function TextMorph2({
219
- value,
220
- renderText,
221
- typeDelay = [30, 60],
222
- backspaceDelay = [18, 30],
223
- hardChars = /[\/{}\-_@]/,
224
- hardCharExtraDelay = [30, 65],
225
- pauseMs = 70,
226
- disabled = false,
227
- className = "",
228
- ...rest
229
- }, ref) {
230
- const [displayed, setDisplayed] = useState(value);
231
- const tokenRef = useRef(0);
232
- const reducedRef = useRef(false);
233
- const prevValueRef = useRef(value);
234
- const displayedRef = useRef(value);
235
- useEffect(() => {
236
- if (typeof window !== "undefined") {
237
- reducedRef.current = window.matchMedia(
238
- "(prefers-reduced-motion: reduce)"
239
- ).matches;
240
- }
241
- }, []);
242
- useEffect(() => {
243
- displayedRef.current = displayed;
244
- }, [displayed]);
245
- useEffect(() => {
246
- if (value === prevValueRef.current) return;
247
- const source = displayedRef.current;
248
- prevValueRef.current = value;
249
- if (disabled || reducedRef.current) {
250
- setDisplayed(value);
251
- return;
252
- }
253
- const myToken = ++tokenRef.current;
254
- (async () => {
255
- const { prefix, suffix, oldMid, newMid } = findDiff(source, value);
256
- for (let i = oldMid.length - 1; i >= 0; i--) {
257
- if (myToken !== tokenRef.current) return;
258
- setDisplayed(prefix + oldMid.slice(0, i) + suffix);
259
- await sleep(rand(backspaceDelay[0], backspaceDelay[1]));
260
- }
261
- if (myToken !== tokenRef.current) return;
262
- await sleep(pauseMs);
263
- for (let i = 1; i <= newMid.length; i++) {
264
- if (myToken !== tokenRef.current) return;
265
- setDisplayed(prefix + newMid.slice(0, i) + suffix);
266
- const ch = newMid.charAt(i - 1);
267
- const base = rand(typeDelay[0], typeDelay[1]);
268
- const extra = hardChars.test(ch) ? rand(hardCharExtraDelay[0], hardCharExtraDelay[1]) : 0;
269
- await sleep(base + extra);
270
- }
271
- })();
272
- }, [
273
- value,
274
- disabled,
275
- typeDelay,
276
- backspaceDelay,
277
- hardChars,
278
- hardCharExtraDelay,
279
- pauseMs
280
- ]);
281
- return /* @__PURE__ */ jsx(
282
- "span",
283
- {
284
- ref,
285
- className: `royui-textmorph ${className}`.trim(),
286
- "aria-live": "polite",
287
- ...rest,
288
- children: renderText ? renderText(displayed) : displayed
289
- }
290
- );
291
- }
292
- );
293
- var TreeNav = forwardRef(
294
- ({ indent = 24, gap = 2, className = "", style, children, ...rest }, ref) => {
295
- const mergedStyle = {
296
- ...style,
297
- ["--royui-treenav-indent"]: `${indent}px`,
298
- ["--royui-treenav-gap"]: `${gap}px`
299
- };
300
- const classes = ["royui-treenav", className].filter(Boolean).join(" ");
301
- return /* @__PURE__ */ jsx("ul", { ref, className: classes, style: mergedStyle, ...rest, children });
302
- }
303
- );
304
- TreeNav.displayName = "TreeNav";
305
- var TreeNavItem = forwardRef(
306
- ({
307
- href,
308
- active = false,
309
- asChild = false,
310
- hideTip = false,
311
- icon,
312
- children,
313
- linkProps,
314
- className = "",
315
- ...rest
316
- }, ref) => {
317
- const itemClasses = [
318
- "royui-treenav__item",
319
- hideTip && "royui-treenav__item--no-tip",
320
- className
321
- ].filter(Boolean).join(" ");
322
- const linkContent = /* @__PURE__ */ jsxs(Fragment, { children: [
323
- icon && /* @__PURE__ */ jsx("span", { className: "royui-treenav__icon", "aria-hidden": true, children: icon }),
324
- /* @__PURE__ */ jsx("span", { className: "royui-treenav__label", children })
325
- ] });
326
- let renderedLink;
327
- if (asChild) {
328
- const onlyChild = Children.only(children);
329
- if (!isValidElement(onlyChild)) {
330
- throw new Error(
331
- "TreeNavItem: asChild requires a single React element child."
332
- );
333
- }
334
- const childClassName = [
335
- "royui-treenav__link",
336
- onlyChild.props.className
337
- ].filter(Boolean).join(" ");
338
- renderedLink = cloneElement(onlyChild, {
339
- className: childClassName,
340
- ...active ? { "aria-current": "page" } : {}
341
- });
342
- } else {
343
- const { className: linkClassName, ...linkRest } = linkProps ?? {};
344
- const mergedLinkClass = ["royui-treenav__link", linkClassName].filter(Boolean).join(" ");
345
- renderedLink = /* @__PURE__ */ jsx(
346
- "a",
347
- {
348
- href,
349
- className: mergedLinkClass,
350
- ...active ? { "aria-current": "page" } : {},
351
- ...linkRest,
352
- children: linkContent
353
- }
354
- );
355
- }
356
- return /* @__PURE__ */ jsxs("li", { ref, className: itemClasses, ...rest, children: [
357
- /* @__PURE__ */ jsx(
358
- "svg",
359
- {
360
- className: "royui-treenav__connector",
361
- viewBox: "0 0 20 30",
362
- preserveAspectRatio: "xMinYMid meet",
363
- "aria-hidden": true,
364
- children: hideTip ? /* @__PURE__ */ jsx(
365
- "path",
366
- {
367
- d: "M1.25 0 L1.25 7 Q1.25 15.75 11 15.75 L11 14.25 Q2.75 14.25 2.75 7 L2.75 0 Z",
368
- fill: "currentColor"
369
- }
370
- ) : /* @__PURE__ */ jsx(
371
- "path",
372
- {
373
- d: "M1.25 0 L1.25 7 Q1.25 15.75 10.33 15.75 L10.33 16.94 L14.22 15 L10.33 13.06 L10.33 14.25 Q2.75 14.25 2.75 7 L2.75 0 Z",
374
- fill: "currentColor"
375
- }
376
- )
377
- }
378
- ),
379
- renderedLink
380
- ] });
381
- }
382
- );
383
- TreeNavItem.displayName = "TreeNavItem";
384
- function Spinner({
385
- size = 16,
386
- strokeWidth = 2,
387
- label = "Loading",
388
- style,
389
- className = ""
390
- }) {
391
- const r = (size - strokeWidth) / 2;
392
- const c = size / 2;
393
- const circumference = 2 * Math.PI * r;
394
- return /* @__PURE__ */ jsx(
395
- "span",
396
- {
397
- role: "status",
398
- "aria-label": label,
399
- className: ["royui-spinner", className].filter(Boolean).join(" "),
400
- style: { width: size, height: size, ...style },
401
- children: /* @__PURE__ */ jsxs("svg", { width: size, height: size, viewBox: `0 0 ${size} ${size}`, "aria-hidden": true, children: [
402
- /* @__PURE__ */ jsx(
403
- "circle",
404
- {
405
- cx: c,
406
- cy: c,
407
- r,
408
- fill: "none",
409
- stroke: "currentColor",
410
- strokeOpacity: 0.18,
411
- strokeWidth
412
- }
413
- ),
414
- /* @__PURE__ */ jsx(
415
- "circle",
416
- {
417
- cx: c,
418
- cy: c,
419
- r,
420
- fill: "none",
421
- stroke: "currentColor",
422
- strokeWidth,
423
- strokeLinecap: "round",
424
- strokeDasharray: circumference,
425
- strokeDashoffset: circumference * 0.72,
426
- transform: `rotate(-90 ${c} ${c})`
427
- }
428
- )
429
- ] })
430
- }
431
- );
432
- }
433
- function fontVars(prefix, spec) {
434
- if (!spec) return {};
435
- const out = {};
436
- if (typeof spec === "string") {
437
- out[`${prefix}-font`] = spec;
438
- return out;
439
- }
440
- if (spec.family) out[`${prefix}-font`] = spec.family;
441
- if (spec.size != null)
442
- out[`${prefix}-size`] = typeof spec.size === "number" ? `${spec.size}px` : spec.size;
443
- if (spec.weight != null) out[`${prefix}-weight`] = String(spec.weight);
444
- if (spec.letterSpacing) out[`${prefix}-tracking`] = spec.letterSpacing;
445
- if (spec.featureSettings) out[`${prefix}-features`] = spec.featureSettings;
446
- return out;
447
- }
448
- var Table = forwardRef(function Table2({
449
- visibleRows = 7,
450
- rowHeight = 44,
451
- stickyHeader = true,
452
- density = "cozy",
453
- loading = false,
454
- empty,
455
- isEmpty = false,
456
- fitColumns = false,
457
- headerFont,
458
- rowHeaderFont,
459
- cellFont,
460
- className = "",
461
- style,
462
- children,
463
- tableProps,
464
- ...rest
465
- }, ref) {
466
- const headerH = 40;
467
- const maxH = rowHeight * visibleRows + (stickyHeader ? headerH : 0);
468
- const mergedStyle = {
469
- ...style,
470
- ["--royui-table-row-h"]: `${rowHeight}px`,
471
- ["--royui-table-max-h"]: `${maxH}px`,
472
- ...fontVars("--royui-table-header", headerFont),
473
- ...fontVars("--royui-table-row-header", rowHeaderFont),
474
- ...fontVars("--royui-table-cell", cellFont)
475
- };
476
- const classes = [
477
- "royui-table",
478
- `royui-table--${density}`,
479
- stickyHeader && "royui-table--sticky",
480
- loading && "royui-table--loading",
481
- fitColumns && "royui-table--fit",
482
- className
483
- ].filter(Boolean).join(" ");
484
- return /* @__PURE__ */ jsx("div", { ref, className: classes, style: mergedStyle, ...rest, children: /* @__PURE__ */ jsxs("div", { className: "royui-table__scroll", role: "region", "aria-label": "Table", children: [
485
- /* @__PURE__ */ jsx("table", { className: "royui-table__table", ...tableProps, children }),
486
- isEmpty && !loading && /* @__PURE__ */ jsx("div", { className: "royui-table__empty", role: "status", children: empty ?? /* @__PURE__ */ jsx("span", { children: "No results" }) }),
487
- loading && /* @__PURE__ */ jsx("div", { className: "royui-table__loading", "aria-hidden": true, children: /* @__PURE__ */ jsx(Spinner, { size: 18 }) })
488
- ] }) });
489
- });
490
- var TableHeader = forwardRef(function TableHeader2({ className = "", ...rest }, ref) {
491
- return /* @__PURE__ */ jsx(
492
- "thead",
493
- {
494
- ref,
495
- className: ["royui-table__thead", className].filter(Boolean).join(" "),
496
- ...rest
497
- }
498
- );
499
- });
500
- var TableBody = forwardRef(function TableBody2({ className = "", ...rest }, ref) {
501
- return /* @__PURE__ */ jsx(
502
- "tbody",
503
- {
504
- ref,
505
- className: ["royui-table__tbody", className].filter(Boolean).join(" "),
506
- ...rest
507
- }
508
- );
509
- });
510
- var TableRow = forwardRef(function TableRow2({ className = "", ...rest }, ref) {
511
- return /* @__PURE__ */ jsx(
512
- "tr",
513
- {
514
- ref,
515
- className: ["royui-table__tr", className].filter(Boolean).join(" "),
516
- ...rest
517
- }
518
- );
519
- });
520
- var TableHead = forwardRef(
521
- function TableHead2({ className = "", align = "left", ...rest }, ref) {
522
- return /* @__PURE__ */ jsx(
523
- "th",
524
- {
525
- ref,
526
- scope: "col",
527
- className: [
528
- "royui-table__th",
529
- align !== "left" && `royui-table__th--${align}`,
530
- className
531
- ].filter(Boolean).join(" "),
532
- ...rest
533
- }
534
- );
535
- }
536
- );
537
- var TableCell = forwardRef(
538
- function TableCell2({ className = "", align = "left", isRowHeader, ...rest }, ref) {
539
- if (isRowHeader) {
540
- return /* @__PURE__ */ jsx(
541
- "th",
542
- {
543
- ref,
544
- scope: "row",
545
- className: [
546
- "royui-table__row-header",
547
- align !== "left" && `royui-table__td--${align}`,
548
- className
549
- ].filter(Boolean).join(" "),
550
- ...rest
551
- }
552
- );
553
- }
554
- return /* @__PURE__ */ jsx(
555
- "td",
556
- {
557
- ref,
558
- className: [
559
- "royui-table__td",
560
- align !== "left" && `royui-table__td--${align}`,
561
- className
562
- ].filter(Boolean).join(" "),
563
- ...rest
564
- }
565
- );
566
- }
567
- );
568
- var TableSearch = forwardRef(
569
- function TableSearch2({
570
- value,
571
- defaultValue,
572
- onChange,
573
- debounceMs = 0,
574
- placeholder = "Search",
575
- width = 260,
576
- hideIndicator,
577
- className = "",
578
- style,
579
- ...rest
580
- }, ref) {
581
- const controlled = value !== void 0;
582
- const [internal, setInternal] = useState(defaultValue ?? "");
583
- const current = controlled ? value : internal;
584
- const timer = useRef(null);
585
- useEffect(() => () => {
586
- if (timer.current) clearTimeout(timer.current);
587
- }, []);
588
- const emit = (next) => {
589
- if (!onChange) return;
590
- if (debounceMs <= 0) {
591
- onChange(next);
592
- return;
593
- }
594
- if (timer.current) clearTimeout(timer.current);
595
- timer.current = setTimeout(() => onChange(next), debounceMs);
596
- };
597
- const handle = (e) => {
598
- const next = e.target.value;
599
- if (!controlled) setInternal(next);
600
- emit(next);
601
- };
602
- const clear = () => {
603
- if (!controlled) setInternal("");
604
- if (onChange) onChange("");
605
- };
606
- return /* @__PURE__ */ jsxs(
607
- "div",
608
- {
609
- className: ["royui-tablesearch", className].filter(Boolean).join(" "),
610
- style: { width, ...style },
611
- children: [
612
- !hideIndicator && /* @__PURE__ */ jsx("span", { className: "royui-tablesearch__dot", "aria-hidden": true }),
613
- /* @__PURE__ */ jsx(
614
- "input",
615
- {
616
- ref,
617
- type: "text",
618
- className: "royui-tablesearch__input",
619
- placeholder,
620
- value: current,
621
- onChange: handle,
622
- ...rest
623
- }
624
- ),
625
- current.length > 0 && /* @__PURE__ */ jsx(
626
- "button",
627
- {
628
- type: "button",
629
- className: "royui-tablesearch__clear",
630
- onClick: clear,
631
- "aria-label": "Clear search",
632
- children: "Clear"
633
- }
634
- )
635
- ]
636
- }
637
- );
638
- }
639
- );
640
- function buildRange(page, pageCount, sibling) {
641
- if (pageCount <= 1) return [1];
642
- const first = 1;
643
- const last = pageCount;
644
- const left = Math.max(page - sibling, first + 1);
645
- const right = Math.min(page + sibling, last - 1);
646
- const cells = [first];
647
- if (left > first + 1) cells.push("gap");
648
- for (let i = left; i <= right; i++) cells.push(i);
649
- if (right < last - 1) cells.push("gap");
650
- if (last > first) cells.push(last);
651
- return cells;
652
- }
653
- function Pagination({
654
- page,
655
- pageCount,
656
- onPageChange,
657
- siblingCount = 1,
658
- showPrevNext = true,
659
- prevLabel = "Prev",
660
- nextLabel = "Next",
661
- showSummary = false,
662
- summaryRender,
663
- className = "",
664
- style
665
- }) {
666
- const cells = useMemo(
667
- () => buildRange(page, pageCount, siblingCount),
668
- [page, pageCount, siblingCount]
669
- );
670
- const canPrev = page > 1;
671
- const canNext = page < pageCount;
672
- const go = (n) => {
673
- if (n < 1 || n > pageCount || n === page) return;
674
- onPageChange(n);
675
- };
676
- return /* @__PURE__ */ jsxs(
677
- "nav",
678
- {
679
- className: ["royui-pagination", className].filter(Boolean).join(" "),
680
- style,
681
- "aria-label": "Pagination",
682
- children: [
683
- showSummary && /* @__PURE__ */ jsx("span", { className: "royui-pagination__summary", children: summaryRender ? summaryRender(page, pageCount) : `Page ${page} of ${pageCount}` }),
684
- /* @__PURE__ */ jsxs("div", { className: "royui-pagination__group", children: [
685
- showPrevNext && /* @__PURE__ */ jsx(
686
- "button",
687
- {
688
- type: "button",
689
- className: "royui-pagination__step",
690
- onClick: () => go(page - 1),
691
- disabled: !canPrev,
692
- "aria-label": "Previous page",
693
- children: prevLabel
694
- }
695
- ),
696
- /* @__PURE__ */ jsx("ul", { className: "royui-pagination__pages", children: cells.map(
697
- (cell, i) => cell === "gap" ? /* @__PURE__ */ jsx("li", { className: "royui-pagination__gap", "aria-hidden": true, children: "\xB7" }, `gap-${i}`) : /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(
698
- "button",
699
- {
700
- type: "button",
701
- className: [
702
- "royui-pagination__page",
703
- cell === page && "royui-pagination__page--current"
704
- ].filter(Boolean).join(" "),
705
- onClick: () => go(cell),
706
- "aria-current": cell === page ? "page" : void 0,
707
- "aria-label": `Page ${cell}`,
708
- children: cell
709
- }
710
- ) }, cell)
711
- ) }),
712
- showPrevNext && /* @__PURE__ */ jsx(
713
- "button",
714
- {
715
- type: "button",
716
- className: "royui-pagination__step",
717
- onClick: () => go(page + 1),
718
- disabled: !canNext,
719
- "aria-label": "Next page",
720
- children: nextLabel
721
- }
722
- )
723
- ] })
724
- ]
725
- }
726
- );
727
- }
728
-
729
- // src/components/date-range-picker/dateUtils.ts
730
- var MONTHS = [
731
- "January",
732
- "February",
733
- "March",
734
- "April",
735
- "May",
736
- "June",
737
- "July",
738
- "August",
739
- "September",
740
- "October",
741
- "November",
742
- "December"
743
- ];
744
- var SHORT_MONTHS = [
745
- "Jan",
746
- "Feb",
747
- "Mar",
748
- "Apr",
749
- "May",
750
- "Jun",
751
- "Jul",
752
- "Aug",
753
- "Sep",
754
- "Oct",
755
- "Nov",
756
- "Dec"
757
- ];
758
- var WEEKDAYS = ["S", "M", "T", "W", "T", "F", "S"];
759
- function startOfDay(d) {
760
- const n = new Date(d);
761
- n.setHours(0, 0, 0, 0);
762
- return n;
763
- }
764
- function isSameDay(a, b) {
765
- if (!a || !b) return false;
766
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth() && a.getDate() === b.getDate();
767
- }
768
- function isSameMonth(a, b) {
769
- return a.getFullYear() === b.getFullYear() && a.getMonth() === b.getMonth();
770
- }
771
- function addMonths(d, n) {
772
- const x = new Date(d);
773
- x.setDate(1);
774
- x.setMonth(x.getMonth() + n);
775
- return x;
776
- }
777
- function addDays(d, n) {
778
- const x = new Date(d);
779
- x.setDate(x.getDate() + n);
780
- return x;
781
- }
782
- function isBefore(a, b) {
783
- return a.getTime() < b.getTime();
784
- }
785
- function isAfter(a, b) {
786
- return a.getTime() > b.getTime();
787
- }
788
- function isBetween(d, from, to) {
789
- const t = d.getTime();
790
- const a = Math.min(from.getTime(), to.getTime());
791
- const b = Math.max(from.getTime(), to.getTime());
792
- return t >= a && t <= b;
793
- }
794
- function clampToBounds(d, min, max) {
795
- let r = d;
796
- if (min && isBefore(r, min)) r = min;
797
- if (max && isAfter(r, max)) r = max;
798
- return r;
799
- }
800
- function getMonthGrid(year, month, weekStartsOn = 0) {
801
- const first = new Date(year, month, 1);
802
- const firstDow = first.getDay();
803
- const offset = (firstDow - weekStartsOn + 7) % 7;
804
- const gridStart = addDays(first, -offset);
805
- const cells = [];
806
- for (let i = 0; i < 42; i++) {
807
- const date = addDays(gridStart, i);
808
- cells.push({
809
- date,
810
- inMonth: date.getMonth() === month,
811
- iso: date.toISOString().slice(0, 10)
812
- });
813
- }
814
- return cells;
815
- }
816
- function getWeekdayLabels(weekStartsOn = 0) {
817
- return Array.from({ length: 7 }, (_, i) => WEEKDAYS[(weekStartsOn + i) % 7] ?? "");
818
- }
819
- function formatMonthYear(d) {
820
- return `${MONTHS[d.getMonth()] ?? ""} ${d.getFullYear()}`;
821
- }
822
- function formatShort(d) {
823
- if (!d) return "";
824
- const m = SHORT_MONTHS[d.getMonth()] ?? "";
825
- const sameYear = d.getFullYear() === (/* @__PURE__ */ new Date()).getFullYear();
826
- return sameYear ? `${m} ${d.getDate()}` : `${m} ${d.getDate()}, ${d.getFullYear()}`;
827
- }
828
- function formatRange(range) {
829
- if (!range.from && !range.to) return "";
830
- if (range.from && !range.to) return formatShort(range.from);
831
- if (!range.from && range.to) return formatShort(range.to);
832
- if (isSameDay(range.from, range.to)) return formatShort(range.from);
833
- return `${formatShort(range.from)} \u2013 ${formatShort(range.to)}`;
834
- }
835
- var today = () => startOfDay(/* @__PURE__ */ new Date());
836
- var DEFAULT_PRESETS = [
837
- { label: "Today", range: () => ({ from: today(), to: today() }) },
838
- {
839
- label: "Last 7 days",
840
- range: () => ({ from: addDays(today(), -6), to: today() })
841
- },
842
- {
843
- label: "Last 30 days",
844
- range: () => ({ from: addDays(today(), -29), to: today() })
845
- },
846
- {
847
- label: "This month",
848
- range: () => {
849
- const t = today();
850
- return {
851
- from: new Date(t.getFullYear(), t.getMonth(), 1),
852
- to: t
853
- };
854
- }
855
- },
856
- {
857
- label: "Last month",
858
- range: () => {
859
- const t = today();
860
- const first = new Date(t.getFullYear(), t.getMonth() - 1, 1);
861
- const last = new Date(t.getFullYear(), t.getMonth(), 0);
862
- return { from: first, to: last };
863
- }
864
- }
865
- ];
866
- function DateRangePicker({
867
- value,
868
- defaultValue,
869
- onChange,
870
- monthsVisible = 2,
871
- weekStartsOn = 0,
872
- minDate,
873
- maxDate,
874
- placeholder = "Pick a range",
875
- presets = DEFAULT_PRESETS,
876
- align = "left",
877
- className = "",
878
- style,
879
- triggerLabel,
880
- disabled
881
- }) {
882
- const controlled = value !== void 0;
883
- const [internal, setInternal] = useState(
884
- defaultValue ?? { from: null, to: null }
885
- );
886
- const current = controlled ? value : internal;
887
- const [open, setOpen] = useState(false);
888
- const [draft, setDraft] = useState(current);
889
- const [hover, setHover] = useState(null);
890
- const [anchorMonth, setAnchorMonth] = useState(
891
- () => startOfDay(current.from ?? today())
892
- );
893
- const wrap2 = useRef(null);
894
- useEffect(() => {
895
- if (!open) return;
896
- function onDown(e) {
897
- if (wrap2.current && !wrap2.current.contains(e.target)) {
898
- setOpen(false);
899
- }
900
- }
901
- function onKey(e) {
902
- if (e.key === "Escape") setOpen(false);
903
- }
904
- document.addEventListener("mousedown", onDown);
905
- document.addEventListener("keydown", onKey);
906
- return () => {
907
- document.removeEventListener("mousedown", onDown);
908
- document.removeEventListener("keydown", onKey);
909
- };
910
- }, [open]);
911
- useEffect(() => {
912
- if (open) {
913
- setDraft(current);
914
- setHover(null);
915
- setAnchorMonth(startOfDay(current.from ?? today()));
916
- }
917
- }, [open]);
918
- const months = useMemo(() => {
919
- return Array.from({ length: monthsVisible }, (_, i) => addMonths(anchorMonth, i));
920
- }, [anchorMonth, monthsVisible]);
921
- const commit = (next) => {
922
- if (!controlled) setInternal(next);
923
- onChange?.(next);
924
- };
925
- const apply = () => {
926
- commit(draft);
927
- setOpen(false);
928
- };
929
- const clear = () => {
930
- setDraft({ from: null, to: null });
931
- setHover(null);
932
- };
933
- const selectDay = (d) => {
934
- const day = startOfDay(d);
935
- const { from, to } = draft;
936
- if (!from || from && to) {
937
- setDraft({ from: day, to: null });
938
- setHover(day);
939
- return;
940
- }
941
- if (isBefore(day, from)) {
942
- setDraft({ from: day, to: from });
943
- } else {
944
- setDraft({ from, to: day });
945
- }
946
- };
947
- const isDisabled = (d) => {
948
- if (minDate && isBefore(d, startOfDay(minDate))) return true;
949
- if (maxDate && isAfter(d, startOfDay(maxDate))) return true;
950
- return false;
951
- };
952
- const previewTo = !draft.to && draft.from && hover ? hover : draft.to;
953
- const previewRange = { from: draft.from, to: previewTo };
954
- return /* @__PURE__ */ jsxs(
955
- "div",
956
- {
957
- ref: wrap2,
958
- className: ["royui-drp", className].filter(Boolean).join(" "),
959
- style,
960
- children: [
961
- /* @__PURE__ */ jsxs(
962
- "button",
963
- {
964
- type: "button",
965
- className: "royui-drp__trigger",
966
- onClick: () => !disabled && setOpen((o) => !o),
967
- "aria-haspopup": "dialog",
968
- "aria-expanded": open,
969
- disabled,
970
- children: [
971
- /* @__PURE__ */ jsx("span", { className: "royui-drp__trigger-dot", "aria-hidden": true }),
972
- /* @__PURE__ */ jsx("span", { className: "royui-drp__trigger-label", children: triggerLabel ?? (formatRange(current) || placeholder) })
973
- ]
974
- }
975
- ),
976
- open && /* @__PURE__ */ jsxs(
977
- "div",
978
- {
979
- className: `royui-drp__panel royui-drp__panel--${align}`,
980
- role: "dialog",
981
- "aria-label": "Choose date range",
982
- children: [
983
- presets.length > 0 && /* @__PURE__ */ jsx("div", { className: "royui-drp__presets", children: presets.map((p) => {
984
- const r = p.range();
985
- const isActive = isSameDay(draft.from, r.from) && isSameDay(draft.to, r.to);
986
- return /* @__PURE__ */ jsx(
987
- "button",
988
- {
989
- type: "button",
990
- className: [
991
- "royui-drp__preset",
992
- isActive && "royui-drp__preset--active"
993
- ].filter(Boolean).join(" "),
994
- onClick: () => {
995
- const next = {
996
- from: r.from ? startOfDay(clampToBounds(r.from, minDate, maxDate)) : null,
997
- to: r.to ? startOfDay(clampToBounds(r.to, minDate, maxDate)) : null
998
- };
999
- setDraft(next);
1000
- if (next.from) setAnchorMonth(next.from);
1001
- },
1002
- children: p.label
1003
- },
1004
- p.label
1005
- );
1006
- }) }),
1007
- /* @__PURE__ */ jsxs("div", { className: "royui-drp__main", children: [
1008
- /* @__PURE__ */ jsxs("div", { className: "royui-drp__nav", children: [
1009
- /* @__PURE__ */ jsx(
1010
- "button",
1011
- {
1012
- type: "button",
1013
- className: "royui-drp__nav-btn",
1014
- onClick: () => setAnchorMonth(addMonths(anchorMonth, -1)),
1015
- "aria-label": "Previous month",
1016
- children: "Prev"
1017
- }
1018
- ),
1019
- /* @__PURE__ */ jsx(
1020
- "button",
1021
- {
1022
- type: "button",
1023
- className: "royui-drp__nav-btn",
1024
- onClick: () => setAnchorMonth(addMonths(anchorMonth, 1)),
1025
- "aria-label": "Next month",
1026
- children: "Next"
1027
- }
1028
- )
1029
- ] }),
1030
- /* @__PURE__ */ jsx("div", { className: "royui-drp__months", children: months.map((m) => /* @__PURE__ */ jsx(
1031
- MonthGrid,
1032
- {
1033
- month: m,
1034
- range: previewRange,
1035
- hover,
1036
- weekStartsOn,
1037
- isDisabled,
1038
- onSelect: selectDay,
1039
- onHover: (d) => setHover(d)
1040
- },
1041
- `${m.getFullYear()}-${m.getMonth()}`
1042
- )) }),
1043
- /* @__PURE__ */ jsxs("div", { className: "royui-drp__foot", children: [
1044
- /* @__PURE__ */ jsx("div", { className: "royui-drp__readout", children: formatRange(draft) || "Select start and end" }),
1045
- /* @__PURE__ */ jsxs("div", { className: "royui-drp__foot-actions", children: [
1046
- /* @__PURE__ */ jsx(
1047
- "button",
1048
- {
1049
- type: "button",
1050
- className: "royui-drp__ghost",
1051
- onClick: clear,
1052
- children: "Clear"
1053
- }
1054
- ),
1055
- /* @__PURE__ */ jsx(
1056
- "button",
1057
- {
1058
- type: "button",
1059
- className: "royui-drp__primary",
1060
- onClick: apply,
1061
- disabled: !draft.from,
1062
- children: "Apply"
1063
- }
1064
- )
1065
- ] })
1066
- ] })
1067
- ] })
1068
- ]
1069
- }
1070
- )
1071
- ]
1072
- }
1073
- );
1074
- }
1075
- function MonthGrid({
1076
- month,
1077
- range,
1078
- hover,
1079
- weekStartsOn,
1080
- isDisabled,
1081
- onSelect,
1082
- onHover
1083
- }) {
1084
- const grid = useMemo(
1085
- () => getMonthGrid(month.getFullYear(), month.getMonth(), weekStartsOn),
1086
- [month, weekStartsOn]
1087
- );
1088
- const labels = useMemo(() => getWeekdayLabels(weekStartsOn), [weekStartsOn]);
1089
- const todayD = today();
1090
- return /* @__PURE__ */ jsxs("div", { className: "royui-drp__month", children: [
1091
- /* @__PURE__ */ jsx("div", { className: "royui-drp__month-title", children: formatMonthYear(month) }),
1092
- /* @__PURE__ */ jsx("div", { className: "royui-drp__weekdays", children: labels.map((l, i) => /* @__PURE__ */ jsx("span", { className: "royui-drp__weekday", children: l }, i)) }),
1093
- /* @__PURE__ */ jsx("div", { className: "royui-drp__grid", onMouseLeave: () => onHover(null), children: grid.map((c) => {
1094
- const inMonth = isSameMonth(c.date, month);
1095
- const disabled = isDisabled(c.date);
1096
- const isStart = isSameDay(c.date, range.from);
1097
- const isEnd = isSameDay(c.date, range.to);
1098
- const isInRange = range.from && range.to && isBetween(c.date, range.from, range.to);
1099
- const isPreview = range.from && !range.to && hover && isBetween(c.date, range.from, hover);
1100
- const isTodayCell = isSameDay(c.date, todayD);
1101
- const classes = [
1102
- "royui-drp__day",
1103
- !inMonth && "royui-drp__day--out",
1104
- disabled && "royui-drp__day--disabled",
1105
- (isStart || isEnd) && "royui-drp__day--edge",
1106
- isStart && "royui-drp__day--start",
1107
- isEnd && "royui-drp__day--end",
1108
- (isInRange || isPreview) && "royui-drp__day--in",
1109
- isTodayCell && "royui-drp__day--today"
1110
- ].filter(Boolean).join(" ");
1111
- return /* @__PURE__ */ jsx(
1112
- "button",
1113
- {
1114
- type: "button",
1115
- className: classes,
1116
- disabled,
1117
- tabIndex: inMonth ? 0 : -1,
1118
- onClick: () => inMonth && onSelect(c.date),
1119
- onMouseEnter: () => inMonth && onHover(c.date),
1120
- "aria-label": c.date.toDateString(),
1121
- children: /* @__PURE__ */ jsx("span", { children: c.date.getDate() })
1122
- },
1123
- c.iso
1124
- );
1125
- }) })
1126
- ] });
1127
- }
1128
- function angleFromCenter(cx, cy, px, py) {
1129
- const dx = px - cx;
1130
- const dy = py - cy;
1131
- const a = Math.atan2(dy, dx) * (180 / Math.PI) + 90;
1132
- return (a + 360) % 360;
1133
- }
1134
- function AnalogClock({
1135
- value,
1136
- onChange,
1137
- hourCycle = 24,
1138
- minuteStep = 1,
1139
- size = 220
1140
- }) {
1141
- const ref = useRef(null);
1142
- const [mode, setMode] = useState("hours");
1143
- const [dragging, setDragging] = useState(false);
1144
- const updateFromPointer = useCallback(
1145
- (clientX, clientY, currentMode) => {
1146
- const svg = ref.current;
1147
- if (!svg) return;
1148
- const rect = svg.getBoundingClientRect();
1149
- const cx2 = rect.left + rect.width / 2;
1150
- const cy2 = rect.top + rect.height / 2;
1151
- const a = angleFromCenter(cx2, cy2, clientX, clientY);
1152
- if (currentMode === "hours") {
1153
- const hours122 = Math.round(a / 30) % 12;
1154
- const isAm2 = value.hours < 12;
1155
- const h24 = isAm2 ? hours122 : hours122 + 12;
1156
- onChange({ ...value, hours: h24 });
1157
- } else {
1158
- let m = Math.round(a / 6) % 60;
1159
- if (minuteStep > 1) m = Math.round(m / minuteStep) * minuteStep;
1160
- if (m === 60) m = 0;
1161
- onChange({ ...value, minutes: m });
1162
- }
1163
- },
1164
- [minuteStep, onChange, value]
1165
- );
1166
- const togglePeriod = () => {
1167
- const next = value.hours < 12 ? value.hours + 12 : value.hours - 12;
1168
- onChange({ ...value, hours: next });
1169
- };
1170
- const isAm = value.hours < 12;
1171
- useEffect(() => {
1172
- if (!dragging) return;
1173
- const onMove = (e) => updateFromPointer(e.clientX, e.clientY, mode);
1174
- const onUp = () => setDragging(false);
1175
- window.addEventListener("pointermove", onMove);
1176
- window.addEventListener("pointerup", onUp);
1177
- return () => {
1178
- window.removeEventListener("pointermove", onMove);
1179
- window.removeEventListener("pointerup", onUp);
1180
- };
1181
- }, [dragging, mode, updateFromPointer]);
1182
- const handlePointerDown = (e) => {
1183
- e.preventDefault();
1184
- setDragging(true);
1185
- updateFromPointer(e.clientX, e.clientY, mode);
1186
- };
1187
- const hours12 = hourCycle === 12 ? value.hours === 0 ? 12 : value.hours > 12 ? value.hours - 12 : value.hours : value.hours % 12 === 0 ? 12 : value.hours % 12;
1188
- const hourAngle = (hours12 % 12 + value.minutes / 60) * 30 - 90;
1189
- const minuteAngle = value.minutes / 60 * 360 - 90;
1190
- const r = size / 2;
1191
- const cx = r;
1192
- const cy = r;
1193
- const hourLen = r * 0.45;
1194
- const minuteLen = r * 0.7;
1195
- const tickOuter = r * 0.92;
1196
- const tickInner = r * 0.86;
1197
- const majorInner = r * 0.82;
1198
- const handX = (len, deg) => cx + len * Math.cos(deg * Math.PI / 180);
1199
- const handY = (len, deg) => cy + len * Math.sin(deg * Math.PI / 180);
1200
- return /* @__PURE__ */ jsxs("div", { className: "royui-tp-analog", children: [
1201
- /* @__PURE__ */ jsxs(
1202
- "svg",
1203
- {
1204
- ref,
1205
- width: size,
1206
- height: size,
1207
- viewBox: `0 0 ${size} ${size}`,
1208
- onPointerDown: handlePointerDown,
1209
- className: "royui-tp-analog__face",
1210
- role: "application",
1211
- "aria-label": "Analog clock",
1212
- children: [
1213
- /* @__PURE__ */ jsx(
1214
- "circle",
1215
- {
1216
- cx,
1217
- cy,
1218
- r: r - 1,
1219
- className: "royui-tp-analog__bezel"
1220
- }
1221
- ),
1222
- Array.from({ length: 60 }).map((_, i) => {
1223
- const angle = (i * 6 - 90) * (Math.PI / 180);
1224
- const isMajor = i % 5 === 0;
1225
- const inner = isMajor ? majorInner : tickInner;
1226
- return /* @__PURE__ */ jsx(
1227
- "line",
1228
- {
1229
- x1: cx + inner * Math.cos(angle),
1230
- y1: cy + inner * Math.sin(angle),
1231
- x2: cx + tickOuter * Math.cos(angle),
1232
- y2: cy + tickOuter * Math.sin(angle),
1233
- className: isMajor ? "royui-tp-analog__tick--major" : "royui-tp-analog__tick"
1234
- },
1235
- i
1236
- );
1237
- }),
1238
- [12, 3, 6, 9].map((n) => {
1239
- const idx = n % 12;
1240
- const angle = (idx * 30 - 90) * (Math.PI / 180);
1241
- const rr = r * 0.72;
1242
- return /* @__PURE__ */ jsx(
1243
- "text",
1244
- {
1245
- x: cx + rr * Math.cos(angle),
1246
- y: cy + rr * Math.sin(angle),
1247
- dy: "0.34em",
1248
- textAnchor: "middle",
1249
- className: "royui-tp-analog__numeral",
1250
- children: n
1251
- },
1252
- n
1253
- );
1254
- }),
1255
- /* @__PURE__ */ jsx(
1256
- "line",
1257
- {
1258
- x1: cx,
1259
- y1: cy,
1260
- x2: handX(hourLen, hourAngle),
1261
- y2: handY(hourLen, hourAngle),
1262
- className: `royui-tp-analog__hand royui-tp-analog__hand--hour ${mode === "hours" ? "royui-tp-analog__hand--active" : ""}`,
1263
- onPointerDown: (e) => {
1264
- e.stopPropagation();
1265
- setMode("hours");
1266
- setDragging(true);
1267
- }
1268
- }
1269
- ),
1270
- /* @__PURE__ */ jsx(
1271
- "line",
1272
- {
1273
- x1: cx,
1274
- y1: cy,
1275
- x2: handX(minuteLen, minuteAngle),
1276
- y2: handY(minuteLen, minuteAngle),
1277
- className: `royui-tp-analog__hand royui-tp-analog__hand--minute ${mode === "minutes" ? "royui-tp-analog__hand--active" : ""}`,
1278
- onPointerDown: (e) => {
1279
- e.stopPropagation();
1280
- setMode("minutes");
1281
- setDragging(true);
1282
- }
1283
- }
1284
- ),
1285
- /* @__PURE__ */ jsx("circle", { cx, cy, r: 3.5, className: "royui-tp-analog__pin" })
1286
- ]
1287
- }
1288
- ),
1289
- /* @__PURE__ */ jsxs("div", { className: "royui-tp-analog__modes", children: [
1290
- /* @__PURE__ */ jsx(
1291
- "button",
1292
- {
1293
- type: "button",
1294
- className: [
1295
- "royui-tp-analog__mode",
1296
- mode === "hours" && "royui-tp-analog__mode--on"
1297
- ].filter(Boolean).join(" "),
1298
- onClick: () => setMode("hours"),
1299
- children: "Hours"
1300
- }
1301
- ),
1302
- /* @__PURE__ */ jsx(
1303
- "button",
1304
- {
1305
- type: "button",
1306
- className: [
1307
- "royui-tp-analog__mode",
1308
- mode === "minutes" && "royui-tp-analog__mode--on"
1309
- ].filter(Boolean).join(" "),
1310
- onClick: () => setMode("minutes"),
1311
- children: "Minutes"
1312
- }
1313
- ),
1314
- /* @__PURE__ */ jsxs("div", { className: "royui-tp-analog__period", role: "group", "aria-label": "Day half", children: [
1315
- /* @__PURE__ */ jsx(
1316
- "button",
1317
- {
1318
- type: "button",
1319
- className: [
1320
- "royui-tp-analog__period-btn",
1321
- isAm && "royui-tp-analog__period-btn--on"
1322
- ].filter(Boolean).join(" "),
1323
- onClick: () => {
1324
- if (!isAm) togglePeriod();
1325
- },
1326
- "aria-pressed": isAm,
1327
- children: "AM"
1328
- }
1329
- ),
1330
- /* @__PURE__ */ jsx(
1331
- "button",
1332
- {
1333
- type: "button",
1334
- className: [
1335
- "royui-tp-analog__period-btn",
1336
- !isAm && "royui-tp-analog__period-btn--on"
1337
- ].filter(Boolean).join(" "),
1338
- onClick: () => {
1339
- if (isAm) togglePeriod();
1340
- },
1341
- "aria-pressed": !isAm,
1342
- children: "PM"
1343
- }
1344
- )
1345
- ] })
1346
- ] })
1347
- ] });
1348
- }
1349
- function pad(n) {
1350
- return String(n).padStart(2, "0");
1351
- }
1352
- function wrap(n, max) {
1353
- return (n % max + max) % max;
1354
- }
1355
- function DigitalClock({
1356
- value,
1357
- onChange,
1358
- hourCycle = 24,
1359
- minuteStep = 1
1360
- }) {
1361
- const hourBoundary = hourCycle === 12 ? 12 : 24;
1362
- const displayHour = hourCycle === 12 ? value.hours % 12 === 0 ? 12 : value.hours % 12 : value.hours;
1363
- const isAm = value.hours < 12;
1364
- const setDisplayHour = (next) => {
1365
- if (hourCycle === 24) {
1366
- onChange({ ...value, hours: wrap(next, 24) });
1367
- return;
1368
- }
1369
- let h = next;
1370
- if (h <= 0) h = 12;
1371
- if (h > 12) h = 1;
1372
- const h24 = isAm ? h === 12 ? 0 : h : h === 12 ? 12 : h + 12;
1373
- onChange({ ...value, hours: h24 });
1374
- };
1375
- const setMinutes = (next) => {
1376
- const stepped = Math.round(next / minuteStep) * minuteStep;
1377
- onChange({ ...value, minutes: wrap(stepped, 60) });
1378
- };
1379
- const setAm = () => {
1380
- if (isAm) return;
1381
- onChange({ ...value, hours: value.hours - 12 });
1382
- };
1383
- const setPm = () => {
1384
- if (!isAm) return;
1385
- onChange({ ...value, hours: value.hours + 12 });
1386
- };
1387
- return /* @__PURE__ */ jsxs("div", { className: "royui-tp-digital", children: [
1388
- /* @__PURE__ */ jsxs("div", { className: "royui-tp-digital__row", children: [
1389
- /* @__PURE__ */ jsx(
1390
- Segment,
1391
- {
1392
- label: "Hours",
1393
- value: pad(displayHour),
1394
- onWheelStep: (d) => setDisplayHour(displayHour + d),
1395
- onArrow: (d) => setDisplayHour(displayHour + d),
1396
- max: hourBoundary
1397
- }
1398
- ),
1399
- /* @__PURE__ */ jsx("span", { className: "royui-tp-digital__sep", "aria-hidden": true, children: ":" }),
1400
- /* @__PURE__ */ jsx(
1401
- Segment,
1402
- {
1403
- label: "Minutes",
1404
- value: pad(value.minutes),
1405
- onWheelStep: (d) => setMinutes(value.minutes + d * minuteStep),
1406
- onArrow: (d) => setMinutes(value.minutes + d * minuteStep),
1407
- max: 60
1408
- }
1409
- )
1410
- ] }),
1411
- /* @__PURE__ */ jsxs("div", { className: "royui-tp-digital__period", role: "group", "aria-label": "Day half", children: [
1412
- /* @__PURE__ */ jsx(
1413
- "button",
1414
- {
1415
- type: "button",
1416
- className: [
1417
- "royui-tp-digital__period-btn",
1418
- isAm && "royui-tp-digital__period-btn--on"
1419
- ].filter(Boolean).join(" "),
1420
- onClick: setAm,
1421
- "aria-pressed": isAm,
1422
- children: "AM"
1423
- }
1424
- ),
1425
- /* @__PURE__ */ jsx(
1426
- "button",
1427
- {
1428
- type: "button",
1429
- className: [
1430
- "royui-tp-digital__period-btn",
1431
- !isAm && "royui-tp-digital__period-btn--on"
1432
- ].filter(Boolean).join(" "),
1433
- onClick: setPm,
1434
- "aria-pressed": !isAm,
1435
- children: "PM"
1436
- }
1437
- )
1438
- ] }),
1439
- /* @__PURE__ */ jsx("div", { className: "royui-tp-digital__hint", children: "Scroll or use arrow keys" })
1440
- ] });
1441
- }
1442
- function Segment({
1443
- label,
1444
- value,
1445
- onWheelStep,
1446
- onArrow,
1447
- max
1448
- }) {
1449
- const ref = useRef(null);
1450
- const handleWheel = (e) => {
1451
- e.preventDefault();
1452
- onWheelStep(e.deltaY > 0 ? 1 : -1);
1453
- };
1454
- const handleKey = (e) => {
1455
- if (e.key === "ArrowUp" || e.key === "ArrowRight") {
1456
- e.preventDefault();
1457
- onArrow(1);
1458
- } else if (e.key === "ArrowDown" || e.key === "ArrowLeft") {
1459
- e.preventDefault();
1460
- onArrow(-1);
1461
- }
1462
- };
1463
- return /* @__PURE__ */ jsx(
1464
- "div",
1465
- {
1466
- ref,
1467
- role: "spinbutton",
1468
- tabIndex: 0,
1469
- "aria-label": label,
1470
- "aria-valuetext": value,
1471
- "aria-valuemax": max,
1472
- className: "royui-tp-digital__seg",
1473
- onWheel: handleWheel,
1474
- onKeyDown: handleKey,
1475
- children: value
1476
- }
1477
- );
1478
- }
1479
- function pad2(n) {
1480
- return String(n).padStart(2, "0");
1481
- }
1482
- function formatTime(t, hourCycle = 24) {
1483
- if (!t) return "";
1484
- if (hourCycle === 24) return `${pad2(t.hours)}:${pad2(t.minutes)}`;
1485
- const h = t.hours % 12 === 0 ? 12 : t.hours % 12;
1486
- const ampm = t.hours < 12 ? "AM" : "PM";
1487
- return `${pad2(h)}:${pad2(t.minutes)} ${ampm}`;
1488
- }
1489
- function TimePicker({
1490
- value,
1491
- defaultValue,
1492
- onChange,
1493
- variant = "analog",
1494
- switchable = true,
1495
- hourCycle = 24,
1496
- minuteStep = 1,
1497
- placeholder = "Pick a time",
1498
- align = "left",
1499
- className = "",
1500
- style,
1501
- triggerLabel,
1502
- disabled
1503
- }) {
1504
- const controlled = value !== void 0;
1505
- const [internal, setInternal] = useState(defaultValue ?? null);
1506
- const current = controlled ? value : internal;
1507
- const [open, setOpen] = useState(false);
1508
- const [mode, setMode] = useState(variant);
1509
- const [draft, setDraft] = useState(current ?? { hours: 12, minutes: 0 });
1510
- const wrap2 = useRef(null);
1511
- useEffect(() => {
1512
- if (!open) return;
1513
- function onDown(e) {
1514
- if (wrap2.current && !wrap2.current.contains(e.target)) {
1515
- setOpen(false);
1516
- }
1517
- }
1518
- function onKey(e) {
1519
- if (e.key === "Escape") setOpen(false);
1520
- }
1521
- document.addEventListener("mousedown", onDown);
1522
- document.addEventListener("keydown", onKey);
1523
- return () => {
1524
- document.removeEventListener("mousedown", onDown);
1525
- document.removeEventListener("keydown", onKey);
1526
- };
1527
- }, [open]);
1528
- useEffect(() => {
1529
- if (open) setDraft(current ?? { hours: (/* @__PURE__ */ new Date()).getHours(), minutes: 0 });
1530
- }, [open]);
1531
- useEffect(() => {
1532
- setMode(variant);
1533
- }, [variant]);
1534
- const commit = (next) => {
1535
- if (!controlled) setInternal(next);
1536
- onChange?.(next);
1537
- };
1538
- const setNow = () => {
1539
- const now = /* @__PURE__ */ new Date();
1540
- setDraft({ hours: now.getHours(), minutes: now.getMinutes() });
1541
- };
1542
- const apply = () => {
1543
- commit(draft);
1544
- setOpen(false);
1545
- };
1546
- return /* @__PURE__ */ jsxs(
1547
- "div",
1548
- {
1549
- ref: wrap2,
1550
- className: ["royui-tp", className].filter(Boolean).join(" "),
1551
- style,
1552
- children: [
1553
- /* @__PURE__ */ jsxs(
1554
- "button",
1555
- {
1556
- type: "button",
1557
- className: "royui-tp__trigger",
1558
- onClick: () => !disabled && setOpen((o) => !o),
1559
- "aria-haspopup": "dialog",
1560
- "aria-expanded": open,
1561
- disabled,
1562
- children: [
1563
- /* @__PURE__ */ jsx("span", { className: "royui-tp__trigger-dot", "aria-hidden": true }),
1564
- /* @__PURE__ */ jsx("span", { className: "royui-tp__trigger-label", children: triggerLabel ?? (formatTime(current ?? null, hourCycle) || placeholder) })
1565
- ]
1566
- }
1567
- ),
1568
- open && /* @__PURE__ */ jsxs(
1569
- "div",
1570
- {
1571
- className: `royui-tp__panel royui-tp__panel--${align}`,
1572
- role: "dialog",
1573
- "aria-label": "Choose time",
1574
- children: [
1575
- /* @__PURE__ */ jsxs("div", { className: "royui-tp__head", children: [
1576
- /* @__PURE__ */ jsx("div", { className: "royui-tp__readout", children: formatTime(draft, hourCycle) }),
1577
- switchable && /* @__PURE__ */ jsxs("div", { className: "royui-tp__variants", role: "tablist", children: [
1578
- /* @__PURE__ */ jsx(
1579
- "button",
1580
- {
1581
- type: "button",
1582
- role: "tab",
1583
- "aria-selected": mode === "analog",
1584
- className: [
1585
- "royui-tp__variant",
1586
- mode === "analog" && "royui-tp__variant--on"
1587
- ].filter(Boolean).join(" "),
1588
- onClick: () => setMode("analog"),
1589
- children: "Analog"
1590
- }
1591
- ),
1592
- /* @__PURE__ */ jsx(
1593
- "button",
1594
- {
1595
- type: "button",
1596
- role: "tab",
1597
- "aria-selected": mode === "digital",
1598
- className: [
1599
- "royui-tp__variant",
1600
- mode === "digital" && "royui-tp__variant--on"
1601
- ].filter(Boolean).join(" "),
1602
- onClick: () => setMode("digital"),
1603
- children: "Digital"
1604
- }
1605
- )
1606
- ] })
1607
- ] }),
1608
- /* @__PURE__ */ jsx("div", { className: "royui-tp__body", children: mode === "analog" ? /* @__PURE__ */ jsx(
1609
- AnalogClock,
1610
- {
1611
- value: draft,
1612
- onChange: setDraft,
1613
- hourCycle,
1614
- minuteStep
1615
- }
1616
- ) : /* @__PURE__ */ jsx(
1617
- DigitalClock,
1618
- {
1619
- value: draft,
1620
- onChange: setDraft,
1621
- hourCycle,
1622
- minuteStep
1623
- }
1624
- ) }),
1625
- /* @__PURE__ */ jsxs("div", { className: "royui-tp__foot", children: [
1626
- /* @__PURE__ */ jsx("button", { type: "button", className: "royui-tp__ghost", onClick: setNow, children: "Now" }),
1627
- /* @__PURE__ */ jsx("button", { type: "button", className: "royui-tp__primary", onClick: apply, children: "Apply" })
1628
- ] })
1629
- ]
1630
- }
1631
- )
1632
- ]
1633
- }
1634
- );
1635
- }
1636
- function ColumnMenu({
1637
- columns,
1638
- layout,
1639
- onToggle,
1640
- onReset
1641
- }) {
1642
- const [open, setOpen] = useState(false);
1643
- const wrap2 = useRef(null);
1644
- useEffect(() => {
1645
- if (!open) return;
1646
- function onDown(e) {
1647
- if (wrap2.current && !wrap2.current.contains(e.target)) {
1648
- setOpen(false);
1649
- }
1650
- }
1651
- function onKey(e) {
1652
- if (e.key === "Escape") setOpen(false);
1653
- }
1654
- document.addEventListener("mousedown", onDown);
1655
- document.addEventListener("keydown", onKey);
1656
- return () => {
1657
- document.removeEventListener("mousedown", onDown);
1658
- document.removeEventListener("keydown", onKey);
1659
- };
1660
- }, [open]);
1661
- const hiddenCount = layout.hidden.length;
1662
- return /* @__PURE__ */ jsxs("div", { className: "royui-dt-colmenu", ref: wrap2, children: [
1663
- /* @__PURE__ */ jsx(
1664
- "button",
1665
- {
1666
- type: "button",
1667
- className: "royui-dt-colmenu__trigger",
1668
- onClick: () => setOpen((o) => !o),
1669
- "aria-expanded": open,
1670
- "aria-haspopup": "menu",
1671
- children: "Columns"
1672
- }
1673
- ),
1674
- hiddenCount > 0 && /* @__PURE__ */ jsxs(
1675
- "button",
1676
- {
1677
- type: "button",
1678
- className: "royui-dt-colmenu__chip",
1679
- onClick: () => setOpen(true),
1680
- children: [
1681
- hiddenCount,
1682
- " hidden"
1683
- ]
1684
- }
1685
- ),
1686
- open && /* @__PURE__ */ jsxs("div", { className: "royui-dt-colmenu__panel", role: "menu", children: [
1687
- /* @__PURE__ */ jsxs("div", { className: "royui-dt-colmenu__head", children: [
1688
- /* @__PURE__ */ jsx("span", { className: "royui-dt-colmenu__title", children: "Columns" }),
1689
- /* @__PURE__ */ jsx(
1690
- "button",
1691
- {
1692
- type: "button",
1693
- className: "royui-dt-colmenu__reset",
1694
- onClick: () => {
1695
- onReset();
1696
- },
1697
- children: "Reset"
1698
- }
1699
- )
1700
- ] }),
1701
- /* @__PURE__ */ jsx("ul", { className: "royui-dt-colmenu__list", children: columns.map((c) => {
1702
- const isHidden = layout.hidden.includes(c.key);
1703
- const disabled = c.hideable === false;
1704
- return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(
1705
- "button",
1706
- {
1707
- type: "button",
1708
- role: "menuitemcheckbox",
1709
- "aria-checked": !isHidden,
1710
- className: [
1711
- "royui-dt-colmenu__row",
1712
- isHidden && "royui-dt-colmenu__row--off",
1713
- disabled && "royui-dt-colmenu__row--locked"
1714
- ].filter(Boolean).join(" "),
1715
- onClick: () => !disabled && onToggle(c.key),
1716
- disabled,
1717
- children: [
1718
- /* @__PURE__ */ jsx(
1719
- "span",
1720
- {
1721
- className: [
1722
- "royui-dt-colmenu__dot",
1723
- !isHidden && "royui-dt-colmenu__dot--on"
1724
- ].filter(Boolean).join(" "),
1725
- "aria-hidden": true
1726
- }
1727
- ),
1728
- /* @__PURE__ */ jsx("span", { className: "royui-dt-colmenu__label", children: c.header })
1729
- ]
1730
- }
1731
- ) }, c.key);
1732
- }) })
1733
- ] })
1734
- ] });
1735
- }
1736
- function defaultLayout(columns) {
1737
- return {
1738
- order: columns.map((c) => c.key),
1739
- sizes: columns.reduce((acc, c) => {
1740
- if (c.defaultWidth != null) acc[c.key] = c.defaultWidth;
1741
- return acc;
1742
- }, {}),
1743
- hidden: columns.filter((c) => c.defaultHidden).map((c) => c.key)
1744
- };
1745
- }
1746
- function loadLayout(key) {
1747
- if (!key || typeof window === "undefined") return null;
1748
- try {
1749
- const raw = window.localStorage.getItem(key);
1750
- if (!raw) return null;
1751
- return JSON.parse(raw);
1752
- } catch {
1753
- return null;
1754
- }
1755
- }
1756
- function saveLayout(key, layout) {
1757
- if (!key || typeof window === "undefined") return;
1758
- try {
1759
- window.localStorage.setItem(key, JSON.stringify(layout));
1760
- } catch {
1761
- }
1762
- }
1763
- function useTableLayout(columns, storageKey) {
1764
- const initial = useMemo(() => {
1765
- return loadLayout(storageKey) ?? defaultLayout(columns);
1766
- }, []);
1767
- const [layout, setLayout] = useState(initial);
1768
- useEffect(() => {
1769
- setLayout((prev) => {
1770
- const known = new Set(columns.map((c) => c.key));
1771
- const order = prev.order.filter((k) => known.has(k));
1772
- columns.forEach((c) => {
1773
- if (!order.includes(c.key)) order.push(c.key);
1774
- });
1775
- const sizes = {};
1776
- Object.entries(prev.sizes).forEach(([k, v]) => {
1777
- if (known.has(k)) sizes[k] = v;
1778
- });
1779
- const hidden = prev.hidden.filter((k) => known.has(k));
1780
- return { order, sizes, hidden };
1781
- });
1782
- }, [columns]);
1783
- useEffect(() => {
1784
- saveLayout(storageKey, layout);
1785
- }, [layout, storageKey]);
1786
- const orderedColumns = useMemo(() => {
1787
- const pinnedLeft = columns.filter((c) => c.pinned === "left");
1788
- const pinnedRight = columns.filter((c) => c.pinned === "right");
1789
- const pinnedKeys = new Set(
1790
- [...pinnedLeft, ...pinnedRight].map((c) => c.key)
1791
- );
1792
- const rest = layout.order.filter((k) => !pinnedKeys.has(k)).map((k) => columns.find((c) => c.key === k)).filter(Boolean);
1793
- return [...pinnedLeft, ...rest, ...pinnedRight];
1794
- }, [columns, layout.order]);
1795
- const visibleColumns = useMemo(
1796
- () => orderedColumns.filter((c) => !layout.hidden.includes(c.key)),
1797
- [orderedColumns, layout.hidden]
1798
- );
1799
- const reorder = useCallback((key, toIndex) => {
1800
- setLayout((prev) => {
1801
- const order = [...prev.order];
1802
- const from = order.indexOf(key);
1803
- if (from === -1 || from === toIndex) return prev;
1804
- const item = order.splice(from, 1)[0];
1805
- if (item === void 0) return prev;
1806
- const insertAt = toIndex > from ? toIndex - 1 : toIndex;
1807
- order.splice(Math.max(0, Math.min(insertAt, order.length)), 0, item);
1808
- return { ...prev, order };
1809
- });
1810
- }, []);
1811
- const resize = useCallback((key, px) => {
1812
- setLayout((prev) => {
1813
- const sizes = { ...prev.sizes };
1814
- if (px == null) delete sizes[key];
1815
- else sizes[key] = Math.max(40, Math.round(px));
1816
- return { ...prev, sizes };
1817
- });
1818
- }, []);
1819
- const toggleHidden = useCallback((key) => {
1820
- setLayout((prev) => {
1821
- const hidden = prev.hidden.includes(key) ? prev.hidden.filter((k) => k !== key) : [...prev.hidden, key];
1822
- return { ...prev, hidden };
1823
- });
1824
- }, []);
1825
- const reset = useCallback(() => {
1826
- setLayout(defaultLayout(columns));
1827
- }, [columns]);
1828
- return {
1829
- layout,
1830
- orderedColumns,
1831
- visibleColumns,
1832
- reorder,
1833
- resize,
1834
- toggleHidden,
1835
- reset
1836
- };
1837
- }
1838
-
1839
- // src/components/data-table/filters.ts
1840
- function defaultSearchPredicate(row, query, columns) {
1841
- if (!query) return true;
1842
- const q = query.toLowerCase();
1843
- return columns.some((c) => {
1844
- const v = c.accessor(row);
1845
- if (v == null) return false;
1846
- const s = v instanceof Date ? v.toLocaleString() : String(v);
1847
- return s.toLowerCase().includes(q);
1848
- });
1849
- }
1850
- function applyFilters(rows, columns, filters, cfg) {
1851
- const searchFn = cfg.searchPredicate ?? defaultSearchPredicate;
1852
- return rows.filter((row) => {
1853
- if (filters.search && !searchFn(row, filters.search, columns)) return false;
1854
- if (cfg.dateColumn && (filters.dateRange.from || filters.dateRange.to)) {
1855
- const col = columns.find((c) => c.key === cfg.dateColumn);
1856
- if (col) {
1857
- const raw = col.accessor(row);
1858
- const d = raw instanceof Date ? raw : raw ? new Date(raw) : null;
1859
- if (!d || isNaN(d.getTime())) return false;
1860
- const day = startOfDay(d);
1861
- const from = filters.dateRange.from ?? day;
1862
- const to = filters.dateRange.to ?? filters.dateRange.from ?? day;
1863
- if (!isBetween(day, startOfDay(from), startOfDay(to))) return false;
1864
- }
1865
- }
1866
- if (cfg.timeColumn && filters.time) {
1867
- const col = columns.find((c) => c.key === cfg.timeColumn);
1868
- if (col) {
1869
- const raw = col.accessor(row);
1870
- const d = raw instanceof Date ? raw : raw ? new Date(raw) : null;
1871
- if (!d || isNaN(d.getTime())) return false;
1872
- const rowMin = d.getHours() * 60 + d.getMinutes();
1873
- const filterMin = filters.time.hours * 60 + filters.time.minutes;
1874
- const tol = cfg.timeTolerance ?? 0;
1875
- if (Math.abs(rowMin - filterMin) > tol) return false;
1876
- }
1877
- }
1878
- return true;
1879
- });
1880
- }
1881
- function applySort(rows, columns, sort) {
1882
- if (!sort || !sort.dir) return rows;
1883
- const col = columns.find((c) => c.key === sort.key);
1884
- if (!col) return rows;
1885
- const dirMul = sort.dir === "asc" ? 1 : -1;
1886
- const getter = col.sortBy ?? col.accessor;
1887
- return [...rows].sort((a, b) => {
1888
- const av = getter(a);
1889
- const bv = getter(b);
1890
- if (av == null && bv == null) return 0;
1891
- if (av == null) return 1;
1892
- if (bv == null) return -1;
1893
- if (av instanceof Date && bv instanceof Date) {
1894
- return (av.getTime() - bv.getTime()) * dirMul;
1895
- }
1896
- if (typeof av === "number" && typeof bv === "number") {
1897
- return (av - bv) * dirMul;
1898
- }
1899
- return String(av).localeCompare(String(bv)) * dirMul;
1900
- });
1901
- }
1902
- function paginate(rows, page, pageSize) {
1903
- const start = (page - 1) * pageSize;
1904
- return rows.slice(start, start + pageSize);
1905
- }
1906
-
1907
- // src/components/data-table/io.ts
1908
- function csvEscape(v) {
1909
- if (v == null) return "";
1910
- const s = typeof v === "string" ? v : v instanceof Date ? v.toISOString() : String(v);
1911
- if (/[",\n\r]/.test(s)) {
1912
- return `"${s.replace(/"/g, '""')}"`;
1913
- }
1914
- return s;
1915
- }
1916
- function toCsv(rows, cols) {
1917
- const visible = cols.filter((c) => !c.defaultHidden);
1918
- const header = visible.map((c) => csvEscape(c.header)).join(",");
1919
- const body = rows.map(
1920
- (row) => visible.map((c) => csvEscape(c.accessor(row))).join(",")
1921
- ).join("\n");
1922
- return body ? `${header}
1923
- ${body}` : header;
1924
- }
1925
- function fromCsv(text) {
1926
- const rows = [];
1927
- let cur = [];
1928
- let field = "";
1929
- let i = 0;
1930
- let inQuotes = false;
1931
- const len = text.length;
1932
- while (i < len) {
1933
- const ch = text[i];
1934
- if (inQuotes) {
1935
- if (ch === '"') {
1936
- if (text[i + 1] === '"') {
1937
- field += '"';
1938
- i += 2;
1939
- continue;
1940
- }
1941
- inQuotes = false;
1942
- i++;
1943
- continue;
1944
- }
1945
- field += ch;
1946
- i++;
1947
- continue;
1948
- }
1949
- if (ch === '"') {
1950
- inQuotes = true;
1951
- i++;
1952
- continue;
1953
- }
1954
- if (ch === ",") {
1955
- cur.push(field);
1956
- field = "";
1957
- i++;
1958
- continue;
1959
- }
1960
- if (ch === "\r") {
1961
- i++;
1962
- continue;
1963
- }
1964
- if (ch === "\n") {
1965
- cur.push(field);
1966
- rows.push(cur);
1967
- cur = [];
1968
- field = "";
1969
- i++;
1970
- continue;
1971
- }
1972
- field += ch;
1973
- i++;
1974
- }
1975
- if (field.length > 0 || cur.length > 0) {
1976
- cur.push(field);
1977
- rows.push(cur);
1978
- }
1979
- if (rows.length === 0) return [];
1980
- const head = rows[0] ?? [];
1981
- const body = rows.slice(1);
1982
- return body.map((r) => {
1983
- const obj = {};
1984
- head.forEach((h, idx) => {
1985
- obj[h] = r[idx] ?? "";
1986
- });
1987
- return obj;
1988
- });
1989
- }
1990
- function toJson(rows, cols) {
1991
- const visible = cols.filter((c) => !c.defaultHidden);
1992
- const out = rows.map((row) => {
1993
- const obj = {};
1994
- visible.forEach((c) => {
1995
- obj[c.key] = c.accessor(row);
1996
- });
1997
- return obj;
1998
- });
1999
- return JSON.stringify(out, null, 2);
2000
- }
2001
- function fromJson(text) {
2002
- const parsed = JSON.parse(text);
2003
- if (!Array.isArray(parsed)) {
2004
- throw new Error("Expected a JSON array of rows");
2005
- }
2006
- return parsed;
2007
- }
2008
- function downloadString(text, filename, mime) {
2009
- if (typeof window === "undefined") return;
2010
- const blob = new Blob([text], { type: mime });
2011
- const url = URL.createObjectURL(blob);
2012
- const a = document.createElement("a");
2013
- a.href = url;
2014
- a.download = filename;
2015
- document.body.appendChild(a);
2016
- a.click();
2017
- a.remove();
2018
- setTimeout(() => URL.revokeObjectURL(url), 1e3);
2019
- }
2020
- function fontStyleFor(spec) {
2021
- if (!spec) return void 0;
2022
- if (typeof spec === "string") return { fontFamily: spec };
2023
- const s = {};
2024
- if (spec.family) s.fontFamily = spec.family;
2025
- if (spec.size != null)
2026
- s.fontSize = typeof spec.size === "number" ? `${spec.size}px` : spec.size;
2027
- if (spec.weight != null) s.fontWeight = spec.weight;
2028
- if (spec.letterSpacing) s.letterSpacing = spec.letterSpacing;
2029
- if (spec.featureSettings) s.fontFeatureSettings = spec.featureSettings;
2030
- return s;
2031
- }
2032
- function renderCellValue(value, type) {
2033
- if (value == null) return "";
2034
- if (value instanceof Date) {
2035
- if (type === "time") {
2036
- return value.toLocaleTimeString([], {
2037
- hour: "2-digit",
2038
- minute: "2-digit"
2039
- });
2040
- }
2041
- if (type === "date") {
2042
- return value.toLocaleDateString();
2043
- }
2044
- return value.toLocaleString();
2045
- }
2046
- return String(value);
2047
- }
2048
- function DataTable({
2049
- data,
2050
- columns,
2051
- getRowId,
2052
- visibleRows = 7,
2053
- rowHeight = 44,
2054
- stickyHeader = true,
2055
- density = "cozy",
2056
- loading,
2057
- empty,
2058
- fitColumns = false,
2059
- search,
2060
- dateFilter,
2061
- timeFilter,
2062
- pagination,
2063
- reorderable = true,
2064
- resizable = true,
2065
- columnMenu = true,
2066
- dataIO,
2067
- headerFont,
2068
- rowHeaderFont,
2069
- cellFont,
2070
- storageKey,
2071
- className = "",
2072
- toolbarExtras
2073
- }) {
2074
- const {
2075
- layout,
2076
- orderedColumns,
2077
- visibleColumns,
2078
- reorder,
2079
- resize,
2080
- toggleHidden,
2081
- reset
2082
- } = useTableLayout(columns, storageKey);
2083
- const [filters, setFilters] = useState({
2084
- search: "",
2085
- dateRange: { from: null, to: null },
2086
- time: null
2087
- });
2088
- const [sort, setSort] = useState(null);
2089
- const pageSize = pagination === false ? Infinity : pagination?.pageSize ?? 25;
2090
- const [page, setPage] = useState(1);
2091
- const filtered = useMemo(
2092
- () => applyFilters(data, columns, filters, {
2093
- dateColumn: dateFilter?.column,
2094
- timeColumn: timeFilter?.column,
2095
- timeTolerance: timeFilter?.toleranceMinutes,
2096
- searchPredicate: search?.predicate
2097
- }),
2098
- [data, columns, filters, dateFilter?.column, timeFilter?.column, timeFilter?.toleranceMinutes, search?.predicate]
2099
- );
2100
- const sorted = useMemo(() => applySort(filtered, columns, sort), [filtered, columns, sort]);
2101
- const pageCount = pagination === false ? 1 : Math.max(1, Math.ceil(sorted.length / pageSize));
2102
- const currentPage = Math.min(page, pageCount);
2103
- const pageRows = useMemo(
2104
- () => pagination === false ? sorted : paginate(sorted, currentPage, pageSize),
2105
- [pagination, sorted, currentPage, pageSize]
2106
- );
2107
- const [dragKey, setDragKey] = useState(null);
2108
- const [dropIndex, setDropIndex] = useState(null);
2109
- const onDragStart = (e, key) => {
2110
- if (!reorderable) return;
2111
- setDragKey(key);
2112
- e.dataTransfer.effectAllowed = "move";
2113
- try {
2114
- e.dataTransfer.setData("text/plain", key);
2115
- } catch {
2116
- }
2117
- };
2118
- const onDragOver = (e, idx) => {
2119
- if (!reorderable || !dragKey) return;
2120
- e.preventDefault();
2121
- e.dataTransfer.dropEffect = "move";
2122
- const rect = e.currentTarget.getBoundingClientRect();
2123
- const isRight = e.clientX - rect.left > rect.width / 2;
2124
- setDropIndex(idx + (isRight ? 1 : 0));
2125
- };
2126
- const onDrop = (e) => {
2127
- if (!reorderable || !dragKey || dropIndex == null) return;
2128
- e.preventDefault();
2129
- reorder(dragKey, dropIndex);
2130
- setDragKey(null);
2131
- setDropIndex(null);
2132
- };
2133
- const onDragEnd = () => {
2134
- setDragKey(null);
2135
- setDropIndex(null);
2136
- };
2137
- const resizingKey = useRef(null);
2138
- const resizeStartX = useRef(0);
2139
- const resizeStartW = useRef(0);
2140
- const beginResize = (e, key) => {
2141
- if (!resizable) return;
2142
- e.stopPropagation();
2143
- e.preventDefault();
2144
- const th = e.currentTarget.parentElement ?? null;
2145
- const startW = th ? th.getBoundingClientRect().width : 120;
2146
- resizingKey.current = key;
2147
- resizeStartX.current = e.clientX;
2148
- resizeStartW.current = startW;
2149
- window.addEventListener("pointermove", onResizeMove);
2150
- window.addEventListener("pointerup", endResize);
2151
- };
2152
- const onResizeMove = (e) => {
2153
- if (!resizingKey.current) return;
2154
- const dx = e.clientX - resizeStartX.current;
2155
- const col = columns.find((c) => c.key === resizingKey.current);
2156
- const min = col?.minWidth ?? 80;
2157
- const max = col?.maxWidth ?? 2e3;
2158
- const next = Math.max(min, Math.min(max, resizeStartW.current + dx));
2159
- resize(resizingKey.current, next);
2160
- };
2161
- const endResize = () => {
2162
- resizingKey.current = null;
2163
- window.removeEventListener("pointermove", onResizeMove);
2164
- window.removeEventListener("pointerup", endResize);
2165
- };
2166
- const doubleClickReset = (key) => resize(key, null);
2167
- const cycleSort = useCallback((key) => {
2168
- setSort((prev) => {
2169
- if (!prev || prev.key !== key) return { key, dir: "asc" };
2170
- if (prev.dir === "asc") return { key, dir: "desc" };
2171
- return null;
2172
- });
2173
- }, []);
2174
- const fileInput = useRef(null);
2175
- const [ioFlash, setIoFlash] = useState(null);
2176
- const flashTimer = useRef(null);
2177
- const flash = (text, ms = 1400) => {
2178
- if (flashTimer.current) clearTimeout(flashTimer.current);
2179
- setIoFlash(text);
2180
- flashTimer.current = setTimeout(() => setIoFlash(null), ms);
2181
- };
2182
- const exportRows = (format) => {
2183
- if (!dataIO?.export) return;
2184
- const scope = dataIO.export.scope ?? "filtered";
2185
- let rows;
2186
- if (scope === "all") rows = data;
2187
- else if (scope === "page") rows = pageRows;
2188
- else rows = sorted;
2189
- const cols = visibleColumns;
2190
- const text = dataIO.export.serialize ? dataIO.export.serialize(rows, cols, format) : format === "csv" ? toCsv(rows, cols) : toJson(rows, cols);
2191
- const baseName = typeof dataIO.export.filename === "function" ? dataIO.export.filename() : dataIO.export.filename ?? "table-export";
2192
- const filename = `${baseName}.${format}`;
2193
- const mime = format === "csv" ? "text/csv;charset=utf-8" : "application/json";
2194
- downloadString(text, filename, mime);
2195
- flash("Exported");
2196
- };
2197
- const onPickFile = async (file) => {
2198
- if (!dataIO?.import) return;
2199
- const text = await file.text();
2200
- try {
2201
- const parsed = dataIO.import.parse ? await dataIO.import.parse(text, file) : file.name.endsWith(".json") ? fromJson(text) : fromCsv(text);
2202
- dataIO.import.onImport(parsed, {
2203
- mode: dataIO.import.mode ?? "replace",
2204
- file
2205
- });
2206
- flash(`Imported ${parsed.length} ${parsed.length === 1 ? "row" : "rows"}`);
2207
- } catch (err) {
2208
- dataIO.import.onError?.(err, file);
2209
- flash("Couldn't read file", 2e3);
2210
- }
2211
- };
2212
- const showToolbar = search?.enabled || !!dateFilter || !!timeFilter || columnMenu || !!dataIO?.export?.enabled || !!dataIO?.import?.enabled || !!toolbarExtras;
2213
- const exportFormats = dataIO?.export?.formats ?? ["csv", "json"];
2214
- const [exportMenuOpen, setExportMenuOpen] = useState(false);
2215
- return /* @__PURE__ */ jsxs("div", { className: ["royui-dt", className].filter(Boolean).join(" "), children: [
2216
- showToolbar && /* @__PURE__ */ jsxs("div", { className: "royui-dt__toolbar", children: [
2217
- /* @__PURE__ */ jsxs("div", { className: "royui-dt__toolbar-left", children: [
2218
- search?.enabled && /* @__PURE__ */ jsx(
2219
- TableSearch,
2220
- {
2221
- value: filters.search,
2222
- onChange: (v) => {
2223
- setFilters((f) => ({ ...f, search: v }));
2224
- setPage(1);
2225
- },
2226
- placeholder: search.placeholder,
2227
- debounceMs: search.debounceMs
2228
- }
2229
- ),
2230
- dateFilter && /* @__PURE__ */ jsx(
2231
- DateRangePicker,
2232
- {
2233
- value: filters.dateRange,
2234
- onChange: (r) => {
2235
- setFilters((f) => ({ ...f, dateRange: r }));
2236
- setPage(1);
2237
- },
2238
- monthsVisible: dateFilter.monthsVisible ?? 2,
2239
- placeholder: dateFilter.placeholder ?? "Date range"
2240
- }
2241
- ),
2242
- timeFilter && /* @__PURE__ */ jsx(
2243
- TimePicker,
2244
- {
2245
- value: filters.time,
2246
- onChange: (t) => {
2247
- setFilters((f) => ({ ...f, time: t }));
2248
- setPage(1);
2249
- },
2250
- variant: timeFilter.variant ?? "analog",
2251
- hourCycle: timeFilter.hourCycle ?? 24,
2252
- placeholder: timeFilter.placeholder ?? "Time"
2253
- }
2254
- )
2255
- ] }),
2256
- /* @__PURE__ */ jsxs("div", { className: "royui-dt__toolbar-right", children: [
2257
- toolbarExtras,
2258
- columnMenu && /* @__PURE__ */ jsx(
2259
- ColumnMenu,
2260
- {
2261
- columns: orderedColumns,
2262
- layout,
2263
- onToggle: toggleHidden,
2264
- onReset: reset
2265
- }
2266
- ),
2267
- (dataIO?.export?.enabled || dataIO?.import?.enabled) && /* @__PURE__ */ jsx("span", { className: "royui-dt__sep", "aria-hidden": true, children: "\xB7" }),
2268
- dataIO?.export?.enabled && /* @__PURE__ */ jsxs("div", { className: "royui-dt-io", children: [
2269
- /* @__PURE__ */ jsx(
2270
- "button",
2271
- {
2272
- type: "button",
2273
- className: "royui-dt-io__btn",
2274
- onClick: () => {
2275
- const only = exportFormats[0];
2276
- if (exportFormats.length === 1 && only) {
2277
- exportRows(only);
2278
- } else {
2279
- setExportMenuOpen((o) => !o);
2280
- }
2281
- },
2282
- children: ioFlash && ioFlash.startsWith("Export") ? ioFlash : "Export"
2283
- }
2284
- ),
2285
- exportMenuOpen && exportFormats.length > 1 && /* @__PURE__ */ jsx(
2286
- "div",
2287
- {
2288
- className: "royui-dt-io__menu",
2289
- onMouseLeave: () => setExportMenuOpen(false),
2290
- children: exportFormats.map((f) => /* @__PURE__ */ jsx(
2291
- "button",
2292
- {
2293
- type: "button",
2294
- className: "royui-dt-io__menu-item",
2295
- onClick: () => {
2296
- exportRows(f);
2297
- setExportMenuOpen(false);
2298
- },
2299
- children: f.toUpperCase()
2300
- },
2301
- f
2302
- ))
2303
- }
2304
- )
2305
- ] }),
2306
- dataIO?.import?.enabled && /* @__PURE__ */ jsxs(Fragment, { children: [
2307
- /* @__PURE__ */ jsx(
2308
- "button",
2309
- {
2310
- type: "button",
2311
- className: "royui-dt-io__btn",
2312
- onClick: () => fileInput.current?.click(),
2313
- children: ioFlash && (ioFlash.startsWith("Import") || ioFlash.startsWith("Couldn't")) ? ioFlash : "Import"
2314
- }
2315
- ),
2316
- /* @__PURE__ */ jsx(
2317
- "input",
2318
- {
2319
- ref: fileInput,
2320
- type: "file",
2321
- accept: dataIO.import.accept ?? ".csv,.json",
2322
- style: { display: "none" },
2323
- onChange: (e) => {
2324
- const f = e.target.files?.[0];
2325
- if (f) onPickFile(f);
2326
- e.target.value = "";
2327
- }
2328
- }
2329
- )
2330
- ] })
2331
- ] })
2332
- ] }),
2333
- /* @__PURE__ */ jsxs(
2334
- Table,
2335
- {
2336
- visibleRows,
2337
- rowHeight,
2338
- stickyHeader,
2339
- density,
2340
- loading,
2341
- empty,
2342
- isEmpty: pageRows.length === 0,
2343
- fitColumns,
2344
- headerFont,
2345
- rowHeaderFont,
2346
- cellFont,
2347
- children: [
2348
- /* @__PURE__ */ jsx("colgroup", { children: visibleColumns.map((c) => {
2349
- const w = fitColumns ? void 0 : layout.sizes[c.key];
2350
- return /* @__PURE__ */ jsx(
2351
- "col",
2352
- {
2353
- style: w ? { width: w } : void 0,
2354
- className: dragKey === c.key ? "royui-dt__col--dragging" : void 0
2355
- },
2356
- c.key
2357
- );
2358
- }) }),
2359
- /* @__PURE__ */ jsx(TableHeader, { children: /* @__PURE__ */ jsxs(TableRow, { children: [
2360
- visibleColumns.map((c, idx) => {
2361
- const isDragging = dragKey === c.key;
2362
- const showDropBefore = dropIndex === idx;
2363
- const sortDir = sort && sort.key === c.key && sort.dir ? sort.dir : null;
2364
- const canReorder = reorderable && c.reorderable !== false && !c.pinned;
2365
- const canResize = resizable && c.resizable !== false;
2366
- return /* @__PURE__ */ jsxs(
2367
- TableHead,
2368
- {
2369
- align: c.align ?? (c.type === "number" ? "right" : "left"),
2370
- className: [
2371
- "royui-dt__th",
2372
- canReorder && "royui-dt__th--reorderable",
2373
- canResize && "royui-dt__th--resizable",
2374
- isDragging && "royui-dt__th--dragging",
2375
- showDropBefore && "royui-dt__th--drop-before"
2376
- ].filter(Boolean).join(" "),
2377
- draggable: canReorder,
2378
- onDragStart: (e) => onDragStart(e, c.key),
2379
- onDragOver: (e) => onDragOver(e, idx),
2380
- onDrop,
2381
- onDragEnd,
2382
- title: canReorder && canResize ? "Drag to reorder \xB7 drag the right edge to resize" : canReorder ? "Drag to reorder" : canResize ? "Drag the right edge to resize" : void 0,
2383
- children: [
2384
- /* @__PURE__ */ jsxs(
2385
- "span",
2386
- {
2387
- className: "royui-dt__th-inner",
2388
- onClick: () => cycleSort(c.key),
2389
- role: "button",
2390
- tabIndex: 0,
2391
- onKeyDown: (e) => {
2392
- if (e.key === "Enter" || e.key === " ") {
2393
- e.preventDefault();
2394
- cycleSort(c.key);
2395
- }
2396
- },
2397
- children: [
2398
- /* @__PURE__ */ jsx("span", { className: "royui-dt__th-label", children: c.header }),
2399
- sortDir && /* @__PURE__ */ jsx(
2400
- "span",
2401
- {
2402
- className: `royui-dt__sort-indicator royui-dt__sort-indicator--${sortDir}`,
2403
- "aria-hidden": true
2404
- }
2405
- )
2406
- ]
2407
- }
2408
- ),
2409
- canResize && /* @__PURE__ */ jsx(
2410
- "span",
2411
- {
2412
- className: "royui-dt__resize",
2413
- onPointerDown: (e) => beginResize(e, c.key),
2414
- onDoubleClick: () => doubleClickReset(c.key),
2415
- "aria-hidden": true,
2416
- children: /* @__PURE__ */ jsx("span", { className: "royui-dt__resize-bar", "aria-hidden": true })
2417
- }
2418
- )
2419
- ]
2420
- },
2421
- c.key
2422
- );
2423
- }),
2424
- dropIndex === visibleColumns.length && /* @__PURE__ */ jsx(TableHead, { className: "royui-dt__th--drop-end", "aria-hidden": true })
2425
- ] }) }),
2426
- /* @__PURE__ */ jsx(TableBody, { children: pageRows.map((row, i) => {
2427
- const id = getRowId ? getRowId(row, i) : row?.["id"] != null ? String(row["id"]) : i;
2428
- return /* @__PURE__ */ jsx(TableRow, { children: visibleColumns.map((c) => {
2429
- const value = c.accessor(row);
2430
- const display = c.cell ? c.cell(value, row) : renderCellValue(value, c.type);
2431
- const cellStyle = fontStyleFor(c.font);
2432
- const isNum = c.type === "number";
2433
- return /* @__PURE__ */ jsx(
2434
- TableCell,
2435
- {
2436
- isRowHeader: c.isRowHeader,
2437
- align: c.align ?? (isNum ? "right" : "left"),
2438
- className: isNum ? "royui-table__td--num" : void 0,
2439
- style: cellStyle,
2440
- children: display
2441
- },
2442
- c.key
2443
- );
2444
- }) }, id);
2445
- }) })
2446
- ]
2447
- }
2448
- ),
2449
- pagination !== false && pageCount > 1 && /* @__PURE__ */ jsx("div", { className: "royui-dt__pagination", children: /* @__PURE__ */ jsx(
2450
- Pagination,
2451
- {
2452
- page: currentPage,
2453
- pageCount,
2454
- onPageChange: setPage,
2455
- siblingCount: pagination?.siblingCount ?? 1,
2456
- showSummary: pagination?.showSummary ?? true,
2457
- summaryRender: (p, pc) => `${(p - 1) * pageSize + 1}\u2013${Math.min(p * pageSize, sorted.length)} of ${sorted.length}`
2458
- }
2459
- ) })
2460
- ] });
2461
- }
2462
-
2463
- export { AnalogClock, ColumnMenu, DEFAULT_PRESETS, DataTable, DateRangePicker, DigitalClock, GradientButton, MadeBy, Pagination, Popover, Spinner, Table, TableBody, TableCell, TableHead, TableHeader, TableRow, TableSearch, TextMorph, TimePicker, TreeNav, TreeNavItem, addDays, addMonths, downloadString, formatMonthYear, formatRange, formatShort, formatTime, fromCsv, fromJson, isBetween, isSameDay, startOfDay, toCsv, toJson };
2
+ export { TextMorph } from './chunk-PGV55XSZ.js';
3
+ export { TreeNav, TreeNavItem } from './chunk-M6HB6BMA.js';
4
+ export { Button } from './chunk-4SGMAZBG.js';
5
+ export { ColumnMenu, DataTable, downloadString, fromCsv, fromJson, toCsv, toJson } from './chunk-HUCK7AM7.js';
6
+ export { Spinner, Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from './chunk-XERZVDIT.js';
7
+ export { TableSearch } from './chunk-KSHKVSNK.js';
8
+ export { AnalogClock, DigitalClock, TimePicker, formatTime } from './chunk-75IGGPXL.js';
9
+ export { DEFAULT_PRESETS, DateRangePicker, addDays, addMonths, formatMonthYear, formatRange, formatShort, isBetween, isSameDay, startOfDay } from './chunk-SFENGB5N.js';
10
+ export { GradientButton } from './chunk-RLBVY3DG.js';
11
+ export { MadeBy } from './chunk-MDPMEW4K.js';
12
+ export { Pagination } from './chunk-5CIBIH7R.js';
13
+ export { Popover } from './chunk-C5X3TE5U.js';
2464
14
  //# sourceMappingURL=index.js.map
2465
15
  //# sourceMappingURL=index.js.map