@kreativa/ui 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +112 -6
- package/dist/index.d.ts +112 -6
- package/dist/index.js +417 -99
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +416 -100
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -286,7 +286,7 @@ function FormButtonGroup({
|
|
|
286
286
|
}
|
|
287
287
|
|
|
288
288
|
// src/components/Table.tsx
|
|
289
|
-
import { useState, useMemo } from "react";
|
|
289
|
+
import { useState, useMemo, useRef, useCallback } from "react";
|
|
290
290
|
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
291
291
|
function Table({
|
|
292
292
|
data,
|
|
@@ -295,10 +295,15 @@ function Table({
|
|
|
295
295
|
onRowClick,
|
|
296
296
|
loading = false,
|
|
297
297
|
emptyMessage = "No data available",
|
|
298
|
-
className = ""
|
|
298
|
+
className = "",
|
|
299
|
+
resizable = false,
|
|
300
|
+
fixedLayout = false
|
|
299
301
|
}) {
|
|
300
302
|
const [sortKey, setSortKey] = useState(null);
|
|
301
303
|
const [sortDirection, setSortDirection] = useState(null);
|
|
304
|
+
const [columnWidths, setColumnWidths] = useState({});
|
|
305
|
+
const tableRef = useRef(null);
|
|
306
|
+
const resizingRef = useRef(null);
|
|
302
307
|
const handleHeaderClick = (column) => {
|
|
303
308
|
if (!column.sortable) return;
|
|
304
309
|
if (sortKey === column.key) {
|
|
@@ -327,67 +332,140 @@ function Table({
|
|
|
327
332
|
});
|
|
328
333
|
return sortDirection === "desc" ? sorted.reverse() : sorted;
|
|
329
334
|
}, [data, columns, sortKey, sortDirection]);
|
|
335
|
+
const handleResizeStart = useCallback(
|
|
336
|
+
(e, columnKey) => {
|
|
337
|
+
e.preventDefault();
|
|
338
|
+
e.stopPropagation();
|
|
339
|
+
const headerCell = e.currentTarget.parentElement;
|
|
340
|
+
if (!headerCell) return;
|
|
341
|
+
const startWidth = headerCell.getBoundingClientRect().width;
|
|
342
|
+
resizingRef.current = {
|
|
343
|
+
columnKey,
|
|
344
|
+
startX: e.clientX,
|
|
345
|
+
startWidth
|
|
346
|
+
};
|
|
347
|
+
document.addEventListener("mousemove", handleResizeMove);
|
|
348
|
+
document.addEventListener("mouseup", handleResizeEnd);
|
|
349
|
+
document.body.style.cursor = "col-resize";
|
|
350
|
+
document.body.style.userSelect = "none";
|
|
351
|
+
},
|
|
352
|
+
[]
|
|
353
|
+
);
|
|
354
|
+
const handleResizeMove = useCallback((e) => {
|
|
355
|
+
if (!resizingRef.current) return;
|
|
356
|
+
const { columnKey, startX, startWidth } = resizingRef.current;
|
|
357
|
+
const column = columns.find((c) => c.key === columnKey);
|
|
358
|
+
const minWidth = column?.minWidth ?? 50;
|
|
359
|
+
const newWidth = Math.max(minWidth, startWidth + (e.clientX - startX));
|
|
360
|
+
setColumnWidths((prev) => ({
|
|
361
|
+
...prev,
|
|
362
|
+
[columnKey]: newWidth
|
|
363
|
+
}));
|
|
364
|
+
}, [columns]);
|
|
365
|
+
const handleResizeEnd = useCallback(() => {
|
|
366
|
+
resizingRef.current = null;
|
|
367
|
+
document.removeEventListener("mousemove", handleResizeMove);
|
|
368
|
+
document.removeEventListener("mouseup", handleResizeEnd);
|
|
369
|
+
document.body.style.cursor = "";
|
|
370
|
+
document.body.style.userSelect = "";
|
|
371
|
+
}, [handleResizeMove]);
|
|
330
372
|
const getSortIcon = (column) => {
|
|
331
373
|
if (!column.sortable) return null;
|
|
332
374
|
if (sortKey !== column.key) {
|
|
333
|
-
return /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" }) });
|
|
375
|
+
return /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4 text-gray-400 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M7 16V4m0 0L3 8m4-4l4 4m6 0v12m0 0l4-4m-4 4l-4-4" }) });
|
|
334
376
|
}
|
|
335
377
|
if (sortDirection === "asc") {
|
|
336
|
-
return /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4 text-primary-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) });
|
|
378
|
+
return /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4 text-primary-600 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M5 15l7-7 7 7" }) });
|
|
337
379
|
}
|
|
338
|
-
return /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4 text-primary-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) });
|
|
380
|
+
return /* @__PURE__ */ jsx13("svg", { className: "w-4 h-4 text-primary-600 shrink-0", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx13("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) });
|
|
339
381
|
};
|
|
340
382
|
const alignmentClasses = {
|
|
341
383
|
left: "text-left",
|
|
342
384
|
center: "text-center",
|
|
343
385
|
right: "text-right"
|
|
344
386
|
};
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
387
|
+
const getColumnStyle = (column) => {
|
|
388
|
+
if (columnWidths[column.key]) {
|
|
389
|
+
return { width: columnWidths[column.key], minWidth: columnWidths[column.key] };
|
|
390
|
+
}
|
|
391
|
+
if (column.width) {
|
|
392
|
+
return { width: column.width, minWidth: column.minWidth ?? 50 };
|
|
393
|
+
}
|
|
394
|
+
return { minWidth: column.minWidth ?? 50 };
|
|
395
|
+
};
|
|
396
|
+
return /* @__PURE__ */ jsx13("div", { className: `overflow-x-auto ${className}`, children: /* @__PURE__ */ jsxs9(
|
|
397
|
+
"table",
|
|
398
|
+
{
|
|
399
|
+
ref: tableRef,
|
|
400
|
+
className: "w-full border-collapse",
|
|
401
|
+
style: { tableLayout: fixedLayout || resizable ? "fixed" : "auto" },
|
|
402
|
+
children: [
|
|
403
|
+
/* @__PURE__ */ jsx13("thead", { children: /* @__PURE__ */ jsx13("tr", { className: "bg-gray-50 border-b border-gray-200", children: columns.map((column, index) => /* @__PURE__ */ jsxs9(
|
|
404
|
+
"th",
|
|
405
|
+
{
|
|
406
|
+
className: `
|
|
407
|
+
px-4 py-3 text-sm font-semibold text-gray-700 relative
|
|
351
408
|
${alignmentClasses[column.align ?? "left"]}
|
|
352
409
|
${column.sortable ? "cursor-pointer select-none hover:bg-gray-100" : ""}
|
|
353
410
|
`,
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
411
|
+
style: getColumnStyle(column),
|
|
412
|
+
onClick: () => handleHeaderClick(column),
|
|
413
|
+
children: [
|
|
414
|
+
/* @__PURE__ */ jsxs9(
|
|
415
|
+
"div",
|
|
416
|
+
{
|
|
417
|
+
className: `flex items-center gap-1 overflow-hidden ${column.align === "right" ? "justify-end" : column.align === "center" ? "justify-center" : ""}`,
|
|
418
|
+
children: [
|
|
419
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate", children: column.header }),
|
|
420
|
+
getSortIcon(column)
|
|
421
|
+
]
|
|
422
|
+
}
|
|
423
|
+
),
|
|
424
|
+
resizable && index < columns.length - 1 && /* @__PURE__ */ jsx13(
|
|
425
|
+
"div",
|
|
426
|
+
{
|
|
427
|
+
className: "absolute top-0 right-0 w-1 h-full cursor-col-resize bg-transparent hover:bg-primary-300 transition-colors",
|
|
428
|
+
onMouseDown: (e) => handleResizeStart(e, column.key),
|
|
429
|
+
onClick: (e) => e.stopPropagation()
|
|
430
|
+
}
|
|
431
|
+
)
|
|
432
|
+
]
|
|
433
|
+
},
|
|
434
|
+
column.key
|
|
435
|
+
)) }) }),
|
|
436
|
+
/* @__PURE__ */ jsx13("tbody", { children: loading ? /* @__PURE__ */ jsx13("tr", { children: /* @__PURE__ */ jsx13("td", { colSpan: columns.length, className: "px-4 py-8 text-center text-gray-500", children: /* @__PURE__ */ jsxs9("div", { className: "flex items-center justify-center gap-2", children: [
|
|
437
|
+
/* @__PURE__ */ jsx13("div", { className: "w-5 h-5 border-2 border-primary-200 border-t-primary-600 rounded-full animate-spin" }),
|
|
438
|
+
/* @__PURE__ */ jsx13("span", { children: "Loading..." })
|
|
439
|
+
] }) }) }) : sortedData.length === 0 ? /* @__PURE__ */ jsx13("tr", { children: /* @__PURE__ */ jsx13("td", { colSpan: columns.length, className: "px-4 py-8 text-center text-gray-500", children: emptyMessage }) }) : sortedData.map((item) => /* @__PURE__ */ jsx13(
|
|
440
|
+
"tr",
|
|
441
|
+
{
|
|
442
|
+
className: `
|
|
370
443
|
border-b border-gray-100 hover:bg-gray-50 transition-colors
|
|
371
444
|
${onRowClick ? "cursor-pointer" : ""}
|
|
372
445
|
`,
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
446
|
+
onClick: () => onRowClick?.(item),
|
|
447
|
+
children: columns.map((column) => /* @__PURE__ */ jsx13(
|
|
448
|
+
"td",
|
|
449
|
+
{
|
|
450
|
+
className: `px-4 py-3 text-sm text-gray-800 overflow-hidden ${alignmentClasses[column.align ?? "left"]}`,
|
|
451
|
+
style: getColumnStyle(column),
|
|
452
|
+
children: /* @__PURE__ */ jsx13("div", { className: "truncate", children: column.render(item) })
|
|
453
|
+
},
|
|
454
|
+
column.key
|
|
455
|
+
))
|
|
380
456
|
},
|
|
381
|
-
|
|
382
|
-
))
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
] }) });
|
|
457
|
+
getRowKey(item)
|
|
458
|
+
)) })
|
|
459
|
+
]
|
|
460
|
+
}
|
|
461
|
+
) });
|
|
387
462
|
}
|
|
388
463
|
|
|
464
|
+
// src/components/DataTable.tsx
|
|
465
|
+
import { useState as useState3, useMemo as useMemo3, useCallback as useCallback2 } from "react";
|
|
466
|
+
|
|
389
467
|
// src/components/Select.tsx
|
|
390
|
-
import { useState as useState2, useRef, useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
468
|
+
import { useState as useState2, useRef as useRef2, useEffect as useEffect2, useMemo as useMemo2 } from "react";
|
|
391
469
|
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
392
470
|
function Select({
|
|
393
471
|
options,
|
|
@@ -404,8 +482,8 @@ function Select({
|
|
|
404
482
|
const [isOpen, setIsOpen] = useState2(false);
|
|
405
483
|
const [searchTerm, setSearchTerm] = useState2("");
|
|
406
484
|
const [highlightedIndex, setHighlightedIndex] = useState2(0);
|
|
407
|
-
const containerRef =
|
|
408
|
-
const inputRef =
|
|
485
|
+
const containerRef = useRef2(null);
|
|
486
|
+
const inputRef = useRef2(null);
|
|
409
487
|
const filteredOptions = useMemo2(() => {
|
|
410
488
|
if (!searchTerm) return options;
|
|
411
489
|
const term = searchTerm.toLowerCase();
|
|
@@ -569,9 +647,245 @@ function Select({
|
|
|
569
647
|
] });
|
|
570
648
|
}
|
|
571
649
|
|
|
572
|
-
// src/components/
|
|
573
|
-
import { useState as useState3 } from "react";
|
|
650
|
+
// src/components/DataTable.tsx
|
|
574
651
|
import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
652
|
+
function ColumnFilter({ column, value, onChange }) {
|
|
653
|
+
const filterType = column.filterType ?? "text";
|
|
654
|
+
if (filterType === "none") {
|
|
655
|
+
return /* @__PURE__ */ jsx15("div", { className: "h-9" });
|
|
656
|
+
}
|
|
657
|
+
if (filterType === "select" && column.filterOptions) {
|
|
658
|
+
return /* @__PURE__ */ jsx15(
|
|
659
|
+
Select,
|
|
660
|
+
{
|
|
661
|
+
options: [{ value: "", label: "Alla" }, ...column.filterOptions],
|
|
662
|
+
value: value || "",
|
|
663
|
+
onChange: (val) => onChange(val),
|
|
664
|
+
placeholder: column.filterPlaceholder || "Alla",
|
|
665
|
+
className: "w-full text-sm"
|
|
666
|
+
}
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
if (filterType === "multiselect" && column.filterOptions) {
|
|
670
|
+
return /* @__PURE__ */ jsx15(
|
|
671
|
+
Select,
|
|
672
|
+
{
|
|
673
|
+
options: column.filterOptions,
|
|
674
|
+
value: value || [],
|
|
675
|
+
onChange: (val) => onChange(val),
|
|
676
|
+
placeholder: column.filterPlaceholder || "Alla",
|
|
677
|
+
multiple: true,
|
|
678
|
+
className: "w-full text-sm"
|
|
679
|
+
}
|
|
680
|
+
);
|
|
681
|
+
}
|
|
682
|
+
if (filterType === "boolean") {
|
|
683
|
+
return /* @__PURE__ */ jsx15(
|
|
684
|
+
Select,
|
|
685
|
+
{
|
|
686
|
+
options: [
|
|
687
|
+
{ value: "", label: "Alla" },
|
|
688
|
+
{ value: "true", label: "Ja" },
|
|
689
|
+
{ value: "false", label: "Nej" }
|
|
690
|
+
],
|
|
691
|
+
value: value || "",
|
|
692
|
+
onChange: (val) => onChange(val),
|
|
693
|
+
className: "w-full text-sm"
|
|
694
|
+
}
|
|
695
|
+
);
|
|
696
|
+
}
|
|
697
|
+
return /* @__PURE__ */ jsx15(
|
|
698
|
+
Input,
|
|
699
|
+
{
|
|
700
|
+
type: "text",
|
|
701
|
+
value: value || "",
|
|
702
|
+
onChange: (e) => onChange(e.target.value),
|
|
703
|
+
placeholder: column.filterPlaceholder || `Filtrera ${column.header.toLowerCase()}...`,
|
|
704
|
+
className: "w-full text-sm h-9"
|
|
705
|
+
}
|
|
706
|
+
);
|
|
707
|
+
}
|
|
708
|
+
function DataTable({
|
|
709
|
+
data,
|
|
710
|
+
columns,
|
|
711
|
+
getRowKey,
|
|
712
|
+
onRowClick,
|
|
713
|
+
loading,
|
|
714
|
+
emptyMessage = "Ingen data att visa.",
|
|
715
|
+
className,
|
|
716
|
+
showFilters = true,
|
|
717
|
+
initialSortKey,
|
|
718
|
+
initialSortDirection = "asc",
|
|
719
|
+
onFilteredDataChange
|
|
720
|
+
}) {
|
|
721
|
+
const [filters, setFilters] = useState3({});
|
|
722
|
+
const [sortKey, setSortKey] = useState3(initialSortKey || null);
|
|
723
|
+
const [sortDirection, setSortDirection] = useState3(initialSortDirection);
|
|
724
|
+
const handleFilterChange = useCallback2((columnKey, value) => {
|
|
725
|
+
setFilters((prev) => {
|
|
726
|
+
const next = { ...prev };
|
|
727
|
+
if (value === "" || Array.isArray(value) && value.length === 0) {
|
|
728
|
+
delete next[columnKey];
|
|
729
|
+
} else {
|
|
730
|
+
next[columnKey] = value;
|
|
731
|
+
}
|
|
732
|
+
return next;
|
|
733
|
+
});
|
|
734
|
+
}, []);
|
|
735
|
+
const clearFilters = useCallback2(() => {
|
|
736
|
+
setFilters({});
|
|
737
|
+
}, []);
|
|
738
|
+
const filteredData = useMemo3(() => {
|
|
739
|
+
let result = [...data];
|
|
740
|
+
for (const [columnKey, filterValue] of Object.entries(filters)) {
|
|
741
|
+
if (!filterValue || Array.isArray(filterValue) && filterValue.length === 0) continue;
|
|
742
|
+
const column = columns.find((c) => c.key === columnKey);
|
|
743
|
+
if (!column) continue;
|
|
744
|
+
const getFilterableValue = column.filterValue || ((item) => {
|
|
745
|
+
return item[columnKey];
|
|
746
|
+
});
|
|
747
|
+
result = result.filter((item) => {
|
|
748
|
+
const itemValue = getFilterableValue(item);
|
|
749
|
+
if (itemValue === null || itemValue === void 0) {
|
|
750
|
+
return filterValue === "";
|
|
751
|
+
}
|
|
752
|
+
const filterType = column.filterType ?? "text";
|
|
753
|
+
if (filterType === "boolean") {
|
|
754
|
+
const boolFilterValue = filterValue === "true";
|
|
755
|
+
return itemValue === boolFilterValue;
|
|
756
|
+
}
|
|
757
|
+
if (filterType === "multiselect" && Array.isArray(filterValue)) {
|
|
758
|
+
return filterValue.includes(String(itemValue));
|
|
759
|
+
}
|
|
760
|
+
if (filterType === "select") {
|
|
761
|
+
return String(itemValue).toLowerCase() === String(filterValue).toLowerCase();
|
|
762
|
+
}
|
|
763
|
+
return String(itemValue).toLowerCase().includes(String(filterValue).toLowerCase());
|
|
764
|
+
});
|
|
765
|
+
}
|
|
766
|
+
return result;
|
|
767
|
+
}, [data, filters, columns]);
|
|
768
|
+
const sortedData = useMemo3(() => {
|
|
769
|
+
if (!sortKey) return filteredData;
|
|
770
|
+
const column = columns.find((c) => c.key === sortKey);
|
|
771
|
+
if (!column) return filteredData;
|
|
772
|
+
const sorted = [...filteredData].sort((a, b) => {
|
|
773
|
+
if (column.sortFn) {
|
|
774
|
+
return column.sortFn(a, b);
|
|
775
|
+
}
|
|
776
|
+
const getValueForSort = column.filterValue || ((item) => {
|
|
777
|
+
return item[sortKey];
|
|
778
|
+
});
|
|
779
|
+
const aVal = getValueForSort(a);
|
|
780
|
+
const bVal = getValueForSort(b);
|
|
781
|
+
if (aVal === null || aVal === void 0) return 1;
|
|
782
|
+
if (bVal === null || bVal === void 0) return -1;
|
|
783
|
+
if (typeof aVal === "string" && typeof bVal === "string") {
|
|
784
|
+
return aVal.localeCompare(bVal, "sv");
|
|
785
|
+
}
|
|
786
|
+
if (aVal < bVal) return -1;
|
|
787
|
+
if (aVal > bVal) return 1;
|
|
788
|
+
return 0;
|
|
789
|
+
});
|
|
790
|
+
return sortDirection === "desc" ? sorted.reverse() : sorted;
|
|
791
|
+
}, [filteredData, sortKey, sortDirection, columns]);
|
|
792
|
+
useMemo3(() => {
|
|
793
|
+
onFilteredDataChange?.(sortedData);
|
|
794
|
+
}, [sortedData, onFilteredDataChange]);
|
|
795
|
+
const handleSort = useCallback2((columnKey) => {
|
|
796
|
+
if (sortKey === columnKey) {
|
|
797
|
+
setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
|
|
798
|
+
} else {
|
|
799
|
+
setSortKey(columnKey);
|
|
800
|
+
setSortDirection("asc");
|
|
801
|
+
}
|
|
802
|
+
}, [sortKey]);
|
|
803
|
+
const tableColumns = useMemo3(() => {
|
|
804
|
+
return columns.map((column) => {
|
|
805
|
+
const isSortable = column.sortable !== false && column.filterType !== "none";
|
|
806
|
+
const isCurrentSort = sortKey === column.key;
|
|
807
|
+
return {
|
|
808
|
+
key: column.key,
|
|
809
|
+
header: isSortable ? /* @__PURE__ */ jsxs11(
|
|
810
|
+
"button",
|
|
811
|
+
{
|
|
812
|
+
onClick: () => handleSort(column.key),
|
|
813
|
+
className: "flex items-center gap-1 hover:text-gray-900 transition-colors w-full text-left",
|
|
814
|
+
children: [
|
|
815
|
+
column.header,
|
|
816
|
+
isCurrentSort ? /* @__PURE__ */ jsx15("span", { className: "text-primary-600", children: sortDirection === "asc" ? "\u2191" : "\u2193" }) : /* @__PURE__ */ jsx15("span", { className: "text-gray-400 opacity-50", children: "\u2195" })
|
|
817
|
+
]
|
|
818
|
+
}
|
|
819
|
+
) : column.header,
|
|
820
|
+
render: column.render,
|
|
821
|
+
width: column.width,
|
|
822
|
+
align: column.align,
|
|
823
|
+
sortable: false
|
|
824
|
+
// We handle sorting ourselves
|
|
825
|
+
};
|
|
826
|
+
});
|
|
827
|
+
}, [columns, sortKey, sortDirection, handleSort]);
|
|
828
|
+
const hasActiveFilters = Object.keys(filters).length > 0;
|
|
829
|
+
return /* @__PURE__ */ jsxs11("div", { className, children: [
|
|
830
|
+
showFilters && /* @__PURE__ */ jsxs11("div", { className: "mb-4", children: [
|
|
831
|
+
/* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-2 mb-2", children: [
|
|
832
|
+
/* @__PURE__ */ jsxs11("span", { className: "text-sm text-gray-500", children: [
|
|
833
|
+
"Visar ",
|
|
834
|
+
sortedData.length,
|
|
835
|
+
" av ",
|
|
836
|
+
data.length
|
|
837
|
+
] }),
|
|
838
|
+
hasActiveFilters && /* @__PURE__ */ jsx15(
|
|
839
|
+
"button",
|
|
840
|
+
{
|
|
841
|
+
onClick: clearFilters,
|
|
842
|
+
className: "text-sm text-primary-600 hover:underline",
|
|
843
|
+
children: "Rensa filter"
|
|
844
|
+
}
|
|
845
|
+
)
|
|
846
|
+
] }),
|
|
847
|
+
/* @__PURE__ */ jsx15("div", { className: "grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 xl:grid-cols-6 gap-3 p-3 bg-gray-50 border border-gray-200 rounded-lg", children: columns.filter((col) => col.filterType !== "none").map((column) => /* @__PURE__ */ jsxs11("div", { className: "min-w-0", children: [
|
|
848
|
+
/* @__PURE__ */ jsx15("label", { className: "text-xs text-gray-500 mb-1 block truncate", children: column.header }),
|
|
849
|
+
/* @__PURE__ */ jsx15(
|
|
850
|
+
ColumnFilter,
|
|
851
|
+
{
|
|
852
|
+
column,
|
|
853
|
+
value: filters[column.key] || "",
|
|
854
|
+
onChange: (value) => handleFilterChange(column.key, value)
|
|
855
|
+
}
|
|
856
|
+
)
|
|
857
|
+
] }, column.key)) })
|
|
858
|
+
] }),
|
|
859
|
+
/* @__PURE__ */ jsx15(
|
|
860
|
+
Table,
|
|
861
|
+
{
|
|
862
|
+
data: sortedData,
|
|
863
|
+
columns: tableColumns,
|
|
864
|
+
getRowKey,
|
|
865
|
+
onRowClick,
|
|
866
|
+
loading,
|
|
867
|
+
emptyMessage
|
|
868
|
+
}
|
|
869
|
+
)
|
|
870
|
+
] });
|
|
871
|
+
}
|
|
872
|
+
function createFilterOptions(data, getValue, labelMap) {
|
|
873
|
+
const uniqueValues = /* @__PURE__ */ new Set();
|
|
874
|
+
for (const item of data) {
|
|
875
|
+
const value = getValue(item);
|
|
876
|
+
if (value !== null && value !== void 0 && value !== "") {
|
|
877
|
+
uniqueValues.add(value);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return Array.from(uniqueValues).sort((a, b) => a.localeCompare(b, "sv")).map((value) => ({
|
|
881
|
+
value,
|
|
882
|
+
label: labelMap?.[value] || value
|
|
883
|
+
}));
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
// src/components/Tabs.tsx
|
|
887
|
+
import { useState as useState4 } from "react";
|
|
888
|
+
import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
575
889
|
function Tabs({
|
|
576
890
|
tabs,
|
|
577
891
|
activeTab: controlledActiveTab,
|
|
@@ -582,7 +896,7 @@ function Tabs({
|
|
|
582
896
|
className = ""
|
|
583
897
|
}) {
|
|
584
898
|
const isControlled = controlledActiveTab !== void 0;
|
|
585
|
-
const [internalActiveTab, setInternalActiveTab] =
|
|
899
|
+
const [internalActiveTab, setInternalActiveTab] = useState4(
|
|
586
900
|
defaultTab || tabs.find((t) => !t.disabled)?.id || tabs[0]?.id
|
|
587
901
|
);
|
|
588
902
|
const activeTab = isControlled ? controlledActiveTab : internalActiveTab;
|
|
@@ -650,11 +964,11 @@ function Tabs({
|
|
|
650
964
|
}
|
|
651
965
|
};
|
|
652
966
|
const styles = variantStyles[variant];
|
|
653
|
-
return /* @__PURE__ */
|
|
654
|
-
/* @__PURE__ */
|
|
967
|
+
return /* @__PURE__ */ jsxs12("div", { className, children: [
|
|
968
|
+
/* @__PURE__ */ jsx16("div", { className: `flex ${styles.container}`, role: "tablist", children: tabs.map((tab, index) => {
|
|
655
969
|
const isActive = tab.id === activeTab;
|
|
656
970
|
const isDisabled = tab.disabled ?? false;
|
|
657
|
-
return /* @__PURE__ */
|
|
971
|
+
return /* @__PURE__ */ jsx16(
|
|
658
972
|
"button",
|
|
659
973
|
{
|
|
660
974
|
type: "button",
|
|
@@ -666,7 +980,7 @@ function Tabs({
|
|
|
666
980
|
className: styles.tab(isActive, isDisabled),
|
|
667
981
|
onClick: () => handleTabClick(tab),
|
|
668
982
|
onKeyDown: (e) => handleKeyDown(e, index),
|
|
669
|
-
children: /* @__PURE__ */
|
|
983
|
+
children: /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-2", children: [
|
|
670
984
|
tab.icon,
|
|
671
985
|
tab.label
|
|
672
986
|
] })
|
|
@@ -674,13 +988,13 @@ function Tabs({
|
|
|
674
988
|
tab.id
|
|
675
989
|
);
|
|
676
990
|
}) }),
|
|
677
|
-
renderContent && activeContent && /* @__PURE__ */
|
|
991
|
+
renderContent && activeContent && /* @__PURE__ */ jsx16("div", { className: "pt-4", role: "tabpanel", children: activeContent })
|
|
678
992
|
] });
|
|
679
993
|
}
|
|
680
994
|
|
|
681
995
|
// src/components/DatePicker.tsx
|
|
682
|
-
import { useState as
|
|
683
|
-
import { jsx as
|
|
996
|
+
import { useState as useState5, useRef as useRef3, useEffect as useEffect3, useMemo as useMemo4 } from "react";
|
|
997
|
+
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
684
998
|
var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
685
999
|
var MONTHS = [
|
|
686
1000
|
"January",
|
|
@@ -783,11 +1097,11 @@ function DatePicker({
|
|
|
783
1097
|
disabled = false,
|
|
784
1098
|
className = ""
|
|
785
1099
|
}) {
|
|
786
|
-
const [isOpen, setIsOpen] =
|
|
787
|
-
const [viewDate, setViewDate] =
|
|
788
|
-
const [hoverDate, setHoverDate] =
|
|
789
|
-
const containerRef =
|
|
790
|
-
const [selectingEnd, setSelectingEnd] =
|
|
1100
|
+
const [isOpen, setIsOpen] = useState5(false);
|
|
1101
|
+
const [viewDate, setViewDate] = useState5(/* @__PURE__ */ new Date());
|
|
1102
|
+
const [hoverDate, setHoverDate] = useState5(null);
|
|
1103
|
+
const containerRef = useRef3(null);
|
|
1104
|
+
const [selectingEnd, setSelectingEnd] = useState5(false);
|
|
791
1105
|
useEffect3(() => {
|
|
792
1106
|
const handleClickOutside = (e) => {
|
|
793
1107
|
if (containerRef.current && !containerRef.current.contains(e.target)) {
|
|
@@ -798,7 +1112,7 @@ function DatePicker({
|
|
|
798
1112
|
document.addEventListener("mousedown", handleClickOutside);
|
|
799
1113
|
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
800
1114
|
}, []);
|
|
801
|
-
const displayText =
|
|
1115
|
+
const displayText = useMemo4(() => {
|
|
802
1116
|
if (!value) return "";
|
|
803
1117
|
if (range) {
|
|
804
1118
|
const rangeValue = value;
|
|
@@ -815,7 +1129,7 @@ function DatePicker({
|
|
|
815
1129
|
}
|
|
816
1130
|
return formatDate(value);
|
|
817
1131
|
}, [value, range]);
|
|
818
|
-
const calendarDays =
|
|
1132
|
+
const calendarDays = useMemo4(() => {
|
|
819
1133
|
const year = viewDate.getFullYear();
|
|
820
1134
|
const month = viewDate.getMonth();
|
|
821
1135
|
const firstDay = new Date(year, month, 1);
|
|
@@ -898,9 +1212,9 @@ function DatePicker({
|
|
|
898
1212
|
};
|
|
899
1213
|
const today = /* @__PURE__ */ new Date();
|
|
900
1214
|
today.setHours(0, 0, 0, 0);
|
|
901
|
-
return /* @__PURE__ */
|
|
902
|
-
label && /* @__PURE__ */
|
|
903
|
-
/* @__PURE__ */
|
|
1215
|
+
return /* @__PURE__ */ jsxs13("div", { ref: containerRef, className: `relative ${className}`, children: [
|
|
1216
|
+
label && /* @__PURE__ */ jsx17("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: label }),
|
|
1217
|
+
/* @__PURE__ */ jsx17(
|
|
904
1218
|
"div",
|
|
905
1219
|
{
|
|
906
1220
|
className: `
|
|
@@ -910,15 +1224,15 @@ function DatePicker({
|
|
|
910
1224
|
transition-all
|
|
911
1225
|
`,
|
|
912
1226
|
onClick: () => !disabled && setIsOpen(!isOpen),
|
|
913
|
-
children: /* @__PURE__ */
|
|
914
|
-
/* @__PURE__ */
|
|
915
|
-
/* @__PURE__ */
|
|
1227
|
+
children: /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
|
|
1228
|
+
/* @__PURE__ */ jsx17("span", { className: displayText ? "text-gray-800" : "text-gray-400", children: displayText || placeholder }),
|
|
1229
|
+
/* @__PURE__ */ jsx17("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx17("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z" }) })
|
|
916
1230
|
] })
|
|
917
1231
|
}
|
|
918
1232
|
),
|
|
919
|
-
error && /* @__PURE__ */
|
|
920
|
-
isOpen && /* @__PURE__ */
|
|
921
|
-
range && /* @__PURE__ */
|
|
1233
|
+
error && /* @__PURE__ */ jsx17("p", { className: "mt-1 text-xs text-red-600", children: error }),
|
|
1234
|
+
isOpen && /* @__PURE__ */ jsx17("div", { className: "absolute z-50 mt-1 bg-white border border-gray-200 rounded-xl shadow-lg p-4", children: /* @__PURE__ */ jsxs13("div", { className: range ? "flex gap-4" : "", children: [
|
|
1235
|
+
range && /* @__PURE__ */ jsx17("div", { className: "border-r border-gray-100 pr-4 space-y-1", children: PRESET_RANGES.map((preset) => /* @__PURE__ */ jsx17(
|
|
922
1236
|
"button",
|
|
923
1237
|
{
|
|
924
1238
|
type: "button",
|
|
@@ -928,42 +1242,42 @@ function DatePicker({
|
|
|
928
1242
|
},
|
|
929
1243
|
preset.label
|
|
930
1244
|
)) }),
|
|
931
|
-
/* @__PURE__ */
|
|
932
|
-
/* @__PURE__ */
|
|
933
|
-
/* @__PURE__ */
|
|
1245
|
+
/* @__PURE__ */ jsxs13("div", { children: [
|
|
1246
|
+
/* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between mb-4", children: [
|
|
1247
|
+
/* @__PURE__ */ jsx17(
|
|
934
1248
|
"button",
|
|
935
1249
|
{
|
|
936
1250
|
type: "button",
|
|
937
1251
|
className: "p-1 hover:bg-gray-100 rounded",
|
|
938
1252
|
onClick: goToPrevMonth,
|
|
939
|
-
children: /* @__PURE__ */
|
|
1253
|
+
children: /* @__PURE__ */ jsx17("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx17("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
|
|
940
1254
|
}
|
|
941
1255
|
),
|
|
942
|
-
/* @__PURE__ */
|
|
1256
|
+
/* @__PURE__ */ jsxs13("span", { className: "text-sm font-semibold text-gray-800", children: [
|
|
943
1257
|
MONTHS[viewDate.getMonth()],
|
|
944
1258
|
" ",
|
|
945
1259
|
viewDate.getFullYear()
|
|
946
1260
|
] }),
|
|
947
|
-
/* @__PURE__ */
|
|
1261
|
+
/* @__PURE__ */ jsx17(
|
|
948
1262
|
"button",
|
|
949
1263
|
{
|
|
950
1264
|
type: "button",
|
|
951
1265
|
className: "p-1 hover:bg-gray-100 rounded",
|
|
952
1266
|
onClick: goToNextMonth,
|
|
953
|
-
children: /* @__PURE__ */
|
|
1267
|
+
children: /* @__PURE__ */ jsx17("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx17("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
|
|
954
1268
|
}
|
|
955
1269
|
)
|
|
956
1270
|
] }),
|
|
957
|
-
/* @__PURE__ */
|
|
958
|
-
/* @__PURE__ */
|
|
1271
|
+
/* @__PURE__ */ jsx17("div", { className: "grid grid-cols-7 gap-1 mb-2", children: WEEKDAYS.map((day) => /* @__PURE__ */ jsx17("div", { className: "text-center text-xs font-medium text-gray-500 py-1", children: day }, day)) }),
|
|
1272
|
+
/* @__PURE__ */ jsx17("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
|
|
959
1273
|
if (!date) {
|
|
960
|
-
return /* @__PURE__ */
|
|
1274
|
+
return /* @__PURE__ */ jsx17("div", { className: "w-9 h-9" }, `empty-${index}`);
|
|
961
1275
|
}
|
|
962
1276
|
const isDisabled = isDateDisabled(date);
|
|
963
1277
|
const isSelected = isDateSelected(date);
|
|
964
1278
|
const inRange = isDateInRange(date);
|
|
965
1279
|
const isToday = isSameDay(date, today);
|
|
966
|
-
return /* @__PURE__ */
|
|
1280
|
+
return /* @__PURE__ */ jsx17(
|
|
967
1281
|
"button",
|
|
968
1282
|
{
|
|
969
1283
|
type: "button",
|
|
@@ -989,8 +1303,8 @@ function DatePicker({
|
|
|
989
1303
|
}
|
|
990
1304
|
|
|
991
1305
|
// src/components/Timer.tsx
|
|
992
|
-
import { useState as
|
|
993
|
-
import { jsx as
|
|
1306
|
+
import { useState as useState6, useEffect as useEffect4, useCallback as useCallback3, useRef as useRef4 } from "react";
|
|
1307
|
+
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
994
1308
|
function formatTime(totalSeconds) {
|
|
995
1309
|
const hours = Math.floor(totalSeconds / 3600);
|
|
996
1310
|
const minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
@@ -1014,12 +1328,12 @@ function Timer({
|
|
|
1014
1328
|
elapsedSeconds: controlledElapsedSeconds
|
|
1015
1329
|
}) {
|
|
1016
1330
|
const isControlled = controlledIsRunning !== void 0;
|
|
1017
|
-
const [internalIsRunning, setInternalIsRunning] =
|
|
1018
|
-
const [internalElapsedSeconds, setInternalElapsedSeconds] =
|
|
1331
|
+
const [internalIsRunning, setInternalIsRunning] = useState6(false);
|
|
1332
|
+
const [internalElapsedSeconds, setInternalElapsedSeconds] = useState6(initialSeconds);
|
|
1019
1333
|
const isRunning = isControlled ? controlledIsRunning : internalIsRunning;
|
|
1020
1334
|
const elapsedSeconds = isControlled ? controlledElapsedSeconds ?? 0 : internalElapsedSeconds;
|
|
1021
|
-
const intervalRef =
|
|
1022
|
-
const startTimeRef =
|
|
1335
|
+
const intervalRef = useRef4(null);
|
|
1336
|
+
const startTimeRef = useRef4(null);
|
|
1023
1337
|
useEffect4(() => {
|
|
1024
1338
|
return () => {
|
|
1025
1339
|
if (intervalRef.current) {
|
|
@@ -1050,7 +1364,7 @@ function Timer({
|
|
|
1050
1364
|
}
|
|
1051
1365
|
};
|
|
1052
1366
|
}, [isRunning, isControlled, onTick]);
|
|
1053
|
-
const handleStart =
|
|
1367
|
+
const handleStart = useCallback3(() => {
|
|
1054
1368
|
const now = /* @__PURE__ */ new Date();
|
|
1055
1369
|
startTimeRef.current = now;
|
|
1056
1370
|
if (!isControlled) {
|
|
@@ -1058,13 +1372,13 @@ function Timer({
|
|
|
1058
1372
|
}
|
|
1059
1373
|
onStart?.(now);
|
|
1060
1374
|
}, [isControlled, onStart]);
|
|
1061
|
-
const handleStop =
|
|
1375
|
+
const handleStop = useCallback3(() => {
|
|
1062
1376
|
if (!isControlled) {
|
|
1063
1377
|
setInternalIsRunning(false);
|
|
1064
1378
|
}
|
|
1065
1379
|
onStop?.(elapsedSeconds);
|
|
1066
1380
|
}, [isControlled, elapsedSeconds, onStop]);
|
|
1067
|
-
const handleReset =
|
|
1381
|
+
const handleReset = useCallback3(() => {
|
|
1068
1382
|
if (!isControlled) {
|
|
1069
1383
|
setInternalIsRunning(false);
|
|
1070
1384
|
setInternalElapsedSeconds(0);
|
|
@@ -1072,7 +1386,7 @@ function Timer({
|
|
|
1072
1386
|
startTimeRef.current = null;
|
|
1073
1387
|
onReset?.();
|
|
1074
1388
|
}, [isControlled, onReset]);
|
|
1075
|
-
const handleToggle =
|
|
1389
|
+
const handleToggle = useCallback3(() => {
|
|
1076
1390
|
if (isRunning) {
|
|
1077
1391
|
handleStop();
|
|
1078
1392
|
} else {
|
|
@@ -1100,10 +1414,10 @@ function Timer({
|
|
|
1100
1414
|
}
|
|
1101
1415
|
};
|
|
1102
1416
|
const styles = sizeClasses3[size];
|
|
1103
|
-
return /* @__PURE__ */
|
|
1104
|
-
/* @__PURE__ */
|
|
1105
|
-
/* @__PURE__ */
|
|
1106
|
-
/* @__PURE__ */
|
|
1417
|
+
return /* @__PURE__ */ jsxs14("div", { className: `flex items-center ${styles.container} ${className}`, children: [
|
|
1418
|
+
/* @__PURE__ */ jsx18("div", { className: `font-mono font-bold text-gray-800 ${styles.time} tabular-nums`, children: formatTime(elapsedSeconds) }),
|
|
1419
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
|
|
1420
|
+
/* @__PURE__ */ jsx18(
|
|
1107
1421
|
"button",
|
|
1108
1422
|
{
|
|
1109
1423
|
type: "button",
|
|
@@ -1117,14 +1431,14 @@ function Timer({
|
|
|
1117
1431
|
title: isRunning ? "Pause" : "Start",
|
|
1118
1432
|
children: isRunning ? (
|
|
1119
1433
|
// Pause icon
|
|
1120
|
-
/* @__PURE__ */
|
|
1434
|
+
/* @__PURE__ */ jsx18("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) })
|
|
1121
1435
|
) : (
|
|
1122
1436
|
// Play icon
|
|
1123
|
-
/* @__PURE__ */
|
|
1437
|
+
/* @__PURE__ */ jsx18("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { d: "M8 5v14l11-7z" }) })
|
|
1124
1438
|
)
|
|
1125
1439
|
}
|
|
1126
1440
|
),
|
|
1127
|
-
elapsedSeconds > 0 && /* @__PURE__ */
|
|
1441
|
+
elapsedSeconds > 0 && /* @__PURE__ */ jsx18(
|
|
1128
1442
|
"button",
|
|
1129
1443
|
{
|
|
1130
1444
|
type: "button",
|
|
@@ -1135,10 +1449,10 @@ function Timer({
|
|
|
1135
1449
|
transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500
|
|
1136
1450
|
`,
|
|
1137
1451
|
title: "Stop",
|
|
1138
|
-
children: /* @__PURE__ */
|
|
1452
|
+
children: /* @__PURE__ */ jsx18("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { d: "M6 6h12v12H6z" }) })
|
|
1139
1453
|
}
|
|
1140
1454
|
),
|
|
1141
|
-
showReset && elapsedSeconds > 0 && !isRunning && /* @__PURE__ */
|
|
1455
|
+
showReset && elapsedSeconds > 0 && !isRunning && /* @__PURE__ */ jsx18(
|
|
1142
1456
|
"button",
|
|
1143
1457
|
{
|
|
1144
1458
|
type: "button",
|
|
@@ -1149,7 +1463,7 @@ function Timer({
|
|
|
1149
1463
|
transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400
|
|
1150
1464
|
`,
|
|
1151
1465
|
title: "Reset",
|
|
1152
|
-
children: /* @__PURE__ */
|
|
1466
|
+
children: /* @__PURE__ */ jsx18("svg", { className: styles.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15" }) })
|
|
1153
1467
|
}
|
|
1154
1468
|
)
|
|
1155
1469
|
] })
|
|
@@ -1158,6 +1472,7 @@ function Timer({
|
|
|
1158
1472
|
export {
|
|
1159
1473
|
Button,
|
|
1160
1474
|
Card,
|
|
1475
|
+
DataTable,
|
|
1161
1476
|
DatePicker,
|
|
1162
1477
|
EmptyState,
|
|
1163
1478
|
FormButtonGroup,
|
|
@@ -1173,6 +1488,7 @@ export {
|
|
|
1173
1488
|
Table,
|
|
1174
1489
|
Tabs,
|
|
1175
1490
|
Timer,
|
|
1491
|
+
createFilterOptions,
|
|
1176
1492
|
formatTime
|
|
1177
1493
|
};
|
|
1178
1494
|
//# sourceMappingURL=index.mjs.map
|