@kreativa/ui 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -386,6 +386,9 @@ function Table({
386
386
  ] }) });
387
387
  }
388
388
 
389
+ // src/components/DataTable.tsx
390
+ import { useState as useState3, useMemo as useMemo3, useCallback } from "react";
391
+
389
392
  // src/components/Select.tsx
390
393
  import { useState as useState2, useRef, useEffect as useEffect2, useMemo as useMemo2 } from "react";
391
394
  import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
@@ -569,9 +572,245 @@ function Select({
569
572
  ] });
570
573
  }
571
574
 
572
- // src/components/Tabs.tsx
573
- import { useState as useState3 } from "react";
575
+ // src/components/DataTable.tsx
574
576
  import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
577
+ function ColumnFilter({ column, value, onChange }) {
578
+ const filterType = column.filterType ?? "text";
579
+ if (filterType === "none") {
580
+ return /* @__PURE__ */ jsx15("div", { className: "h-9" });
581
+ }
582
+ if (filterType === "select" && column.filterOptions) {
583
+ return /* @__PURE__ */ jsx15(
584
+ Select,
585
+ {
586
+ options: [{ value: "", label: "Alla" }, ...column.filterOptions],
587
+ value: value || "",
588
+ onChange: (val) => onChange(val),
589
+ placeholder: column.filterPlaceholder || "Alla",
590
+ className: "w-full text-sm"
591
+ }
592
+ );
593
+ }
594
+ if (filterType === "multiselect" && column.filterOptions) {
595
+ return /* @__PURE__ */ jsx15(
596
+ Select,
597
+ {
598
+ options: column.filterOptions,
599
+ value: value || [],
600
+ onChange: (val) => onChange(val),
601
+ placeholder: column.filterPlaceholder || "Alla",
602
+ multiple: true,
603
+ className: "w-full text-sm"
604
+ }
605
+ );
606
+ }
607
+ if (filterType === "boolean") {
608
+ return /* @__PURE__ */ jsx15(
609
+ Select,
610
+ {
611
+ options: [
612
+ { value: "", label: "Alla" },
613
+ { value: "true", label: "Ja" },
614
+ { value: "false", label: "Nej" }
615
+ ],
616
+ value: value || "",
617
+ onChange: (val) => onChange(val),
618
+ className: "w-full text-sm"
619
+ }
620
+ );
621
+ }
622
+ return /* @__PURE__ */ jsx15(
623
+ Input,
624
+ {
625
+ type: "text",
626
+ value: value || "",
627
+ onChange: (e) => onChange(e.target.value),
628
+ placeholder: column.filterPlaceholder || `Filtrera ${column.header.toLowerCase()}...`,
629
+ className: "w-full text-sm h-9"
630
+ }
631
+ );
632
+ }
633
+ function DataTable({
634
+ data,
635
+ columns,
636
+ getRowKey,
637
+ onRowClick,
638
+ loading,
639
+ emptyMessage = "Ingen data att visa.",
640
+ className,
641
+ showFilters = true,
642
+ initialSortKey,
643
+ initialSortDirection = "asc",
644
+ onFilteredDataChange
645
+ }) {
646
+ const [filters, setFilters] = useState3({});
647
+ const [sortKey, setSortKey] = useState3(initialSortKey || null);
648
+ const [sortDirection, setSortDirection] = useState3(initialSortDirection);
649
+ const handleFilterChange = useCallback((columnKey, value) => {
650
+ setFilters((prev) => {
651
+ const next = { ...prev };
652
+ if (value === "" || Array.isArray(value) && value.length === 0) {
653
+ delete next[columnKey];
654
+ } else {
655
+ next[columnKey] = value;
656
+ }
657
+ return next;
658
+ });
659
+ }, []);
660
+ const clearFilters = useCallback(() => {
661
+ setFilters({});
662
+ }, []);
663
+ const filteredData = useMemo3(() => {
664
+ let result = [...data];
665
+ for (const [columnKey, filterValue] of Object.entries(filters)) {
666
+ if (!filterValue || Array.isArray(filterValue) && filterValue.length === 0) continue;
667
+ const column = columns.find((c) => c.key === columnKey);
668
+ if (!column) continue;
669
+ const getFilterableValue = column.filterValue || ((item) => {
670
+ return item[columnKey];
671
+ });
672
+ result = result.filter((item) => {
673
+ const itemValue = getFilterableValue(item);
674
+ if (itemValue === null || itemValue === void 0) {
675
+ return filterValue === "";
676
+ }
677
+ const filterType = column.filterType ?? "text";
678
+ if (filterType === "boolean") {
679
+ const boolFilterValue = filterValue === "true";
680
+ return itemValue === boolFilterValue;
681
+ }
682
+ if (filterType === "multiselect" && Array.isArray(filterValue)) {
683
+ return filterValue.includes(String(itemValue));
684
+ }
685
+ if (filterType === "select") {
686
+ return String(itemValue).toLowerCase() === String(filterValue).toLowerCase();
687
+ }
688
+ return String(itemValue).toLowerCase().includes(String(filterValue).toLowerCase());
689
+ });
690
+ }
691
+ return result;
692
+ }, [data, filters, columns]);
693
+ const sortedData = useMemo3(() => {
694
+ if (!sortKey) return filteredData;
695
+ const column = columns.find((c) => c.key === sortKey);
696
+ if (!column) return filteredData;
697
+ const sorted = [...filteredData].sort((a, b) => {
698
+ if (column.sortFn) {
699
+ return column.sortFn(a, b);
700
+ }
701
+ const getValueForSort = column.filterValue || ((item) => {
702
+ return item[sortKey];
703
+ });
704
+ const aVal = getValueForSort(a);
705
+ const bVal = getValueForSort(b);
706
+ if (aVal === null || aVal === void 0) return 1;
707
+ if (bVal === null || bVal === void 0) return -1;
708
+ if (typeof aVal === "string" && typeof bVal === "string") {
709
+ return aVal.localeCompare(bVal, "sv");
710
+ }
711
+ if (aVal < bVal) return -1;
712
+ if (aVal > bVal) return 1;
713
+ return 0;
714
+ });
715
+ return sortDirection === "desc" ? sorted.reverse() : sorted;
716
+ }, [filteredData, sortKey, sortDirection, columns]);
717
+ useMemo3(() => {
718
+ onFilteredDataChange?.(sortedData);
719
+ }, [sortedData, onFilteredDataChange]);
720
+ const handleSort = useCallback((columnKey) => {
721
+ if (sortKey === columnKey) {
722
+ setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
723
+ } else {
724
+ setSortKey(columnKey);
725
+ setSortDirection("asc");
726
+ }
727
+ }, [sortKey]);
728
+ const tableColumns = useMemo3(() => {
729
+ return columns.map((column) => {
730
+ const isSortable = column.sortable !== false && column.filterType !== "none";
731
+ const isCurrentSort = sortKey === column.key;
732
+ return {
733
+ key: column.key,
734
+ header: isSortable ? /* @__PURE__ */ jsxs11(
735
+ "button",
736
+ {
737
+ onClick: () => handleSort(column.key),
738
+ className: "flex items-center gap-1 hover:text-gray-900 transition-colors w-full text-left",
739
+ children: [
740
+ column.header,
741
+ isCurrentSort ? /* @__PURE__ */ jsx15("span", { className: "text-primary-600", children: sortDirection === "asc" ? "\u2191" : "\u2193" }) : /* @__PURE__ */ jsx15("span", { className: "text-gray-400 opacity-50", children: "\u2195" })
742
+ ]
743
+ }
744
+ ) : column.header,
745
+ render: column.render,
746
+ width: column.width,
747
+ align: column.align,
748
+ sortable: false
749
+ // We handle sorting ourselves
750
+ };
751
+ });
752
+ }, [columns, sortKey, sortDirection, handleSort]);
753
+ const hasActiveFilters = Object.keys(filters).length > 0;
754
+ return /* @__PURE__ */ jsxs11("div", { className, children: [
755
+ showFilters && /* @__PURE__ */ jsxs11("div", { className: "mb-4", children: [
756
+ /* @__PURE__ */ jsxs11("div", { className: "flex flex-wrap items-center gap-2 mb-2", children: [
757
+ /* @__PURE__ */ jsxs11("span", { className: "text-sm text-gray-500", children: [
758
+ "Visar ",
759
+ sortedData.length,
760
+ " av ",
761
+ data.length
762
+ ] }),
763
+ hasActiveFilters && /* @__PURE__ */ jsx15(
764
+ "button",
765
+ {
766
+ onClick: clearFilters,
767
+ className: "text-sm text-primary-600 hover:underline",
768
+ children: "Rensa filter"
769
+ }
770
+ )
771
+ ] }),
772
+ /* @__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: [
773
+ /* @__PURE__ */ jsx15("label", { className: "text-xs text-gray-500 mb-1 block truncate", children: column.header }),
774
+ /* @__PURE__ */ jsx15(
775
+ ColumnFilter,
776
+ {
777
+ column,
778
+ value: filters[column.key] || "",
779
+ onChange: (value) => handleFilterChange(column.key, value)
780
+ }
781
+ )
782
+ ] }, column.key)) })
783
+ ] }),
784
+ /* @__PURE__ */ jsx15(
785
+ Table,
786
+ {
787
+ data: sortedData,
788
+ columns: tableColumns,
789
+ getRowKey,
790
+ onRowClick,
791
+ loading,
792
+ emptyMessage
793
+ }
794
+ )
795
+ ] });
796
+ }
797
+ function createFilterOptions(data, getValue, labelMap) {
798
+ const uniqueValues = /* @__PURE__ */ new Set();
799
+ for (const item of data) {
800
+ const value = getValue(item);
801
+ if (value !== null && value !== void 0 && value !== "") {
802
+ uniqueValues.add(value);
803
+ }
804
+ }
805
+ return Array.from(uniqueValues).sort((a, b) => a.localeCompare(b, "sv")).map((value) => ({
806
+ value,
807
+ label: labelMap?.[value] || value
808
+ }));
809
+ }
810
+
811
+ // src/components/Tabs.tsx
812
+ import { useState as useState4 } from "react";
813
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
575
814
  function Tabs({
576
815
  tabs,
577
816
  activeTab: controlledActiveTab,
@@ -582,7 +821,7 @@ function Tabs({
582
821
  className = ""
583
822
  }) {
584
823
  const isControlled = controlledActiveTab !== void 0;
585
- const [internalActiveTab, setInternalActiveTab] = useState3(
824
+ const [internalActiveTab, setInternalActiveTab] = useState4(
586
825
  defaultTab || tabs.find((t) => !t.disabled)?.id || tabs[0]?.id
587
826
  );
588
827
  const activeTab = isControlled ? controlledActiveTab : internalActiveTab;
@@ -650,11 +889,11 @@ function Tabs({
650
889
  }
651
890
  };
652
891
  const styles = variantStyles[variant];
653
- return /* @__PURE__ */ jsxs11("div", { className, children: [
654
- /* @__PURE__ */ jsx15("div", { className: `flex ${styles.container}`, role: "tablist", children: tabs.map((tab, index) => {
892
+ return /* @__PURE__ */ jsxs12("div", { className, children: [
893
+ /* @__PURE__ */ jsx16("div", { className: `flex ${styles.container}`, role: "tablist", children: tabs.map((tab, index) => {
655
894
  const isActive = tab.id === activeTab;
656
895
  const isDisabled = tab.disabled ?? false;
657
- return /* @__PURE__ */ jsx15(
896
+ return /* @__PURE__ */ jsx16(
658
897
  "button",
659
898
  {
660
899
  type: "button",
@@ -666,7 +905,7 @@ function Tabs({
666
905
  className: styles.tab(isActive, isDisabled),
667
906
  onClick: () => handleTabClick(tab),
668
907
  onKeyDown: (e) => handleKeyDown(e, index),
669
- children: /* @__PURE__ */ jsxs11("span", { className: "flex items-center gap-2", children: [
908
+ children: /* @__PURE__ */ jsxs12("span", { className: "flex items-center gap-2", children: [
670
909
  tab.icon,
671
910
  tab.label
672
911
  ] })
@@ -674,13 +913,13 @@ function Tabs({
674
913
  tab.id
675
914
  );
676
915
  }) }),
677
- renderContent && activeContent && /* @__PURE__ */ jsx15("div", { className: "pt-4", role: "tabpanel", children: activeContent })
916
+ renderContent && activeContent && /* @__PURE__ */ jsx16("div", { className: "pt-4", role: "tabpanel", children: activeContent })
678
917
  ] });
679
918
  }
680
919
 
681
920
  // src/components/DatePicker.tsx
682
- import { useState as useState4, useRef as useRef2, useEffect as useEffect3, useMemo as useMemo3 } from "react";
683
- import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
921
+ import { useState as useState5, useRef as useRef2, useEffect as useEffect3, useMemo as useMemo4 } from "react";
922
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
684
923
  var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
685
924
  var MONTHS = [
686
925
  "January",
@@ -783,11 +1022,11 @@ function DatePicker({
783
1022
  disabled = false,
784
1023
  className = ""
785
1024
  }) {
786
- const [isOpen, setIsOpen] = useState4(false);
787
- const [viewDate, setViewDate] = useState4(/* @__PURE__ */ new Date());
788
- const [hoverDate, setHoverDate] = useState4(null);
1025
+ const [isOpen, setIsOpen] = useState5(false);
1026
+ const [viewDate, setViewDate] = useState5(/* @__PURE__ */ new Date());
1027
+ const [hoverDate, setHoverDate] = useState5(null);
789
1028
  const containerRef = useRef2(null);
790
- const [selectingEnd, setSelectingEnd] = useState4(false);
1029
+ const [selectingEnd, setSelectingEnd] = useState5(false);
791
1030
  useEffect3(() => {
792
1031
  const handleClickOutside = (e) => {
793
1032
  if (containerRef.current && !containerRef.current.contains(e.target)) {
@@ -798,7 +1037,7 @@ function DatePicker({
798
1037
  document.addEventListener("mousedown", handleClickOutside);
799
1038
  return () => document.removeEventListener("mousedown", handleClickOutside);
800
1039
  }, []);
801
- const displayText = useMemo3(() => {
1040
+ const displayText = useMemo4(() => {
802
1041
  if (!value) return "";
803
1042
  if (range) {
804
1043
  const rangeValue = value;
@@ -815,7 +1054,7 @@ function DatePicker({
815
1054
  }
816
1055
  return formatDate(value);
817
1056
  }, [value, range]);
818
- const calendarDays = useMemo3(() => {
1057
+ const calendarDays = useMemo4(() => {
819
1058
  const year = viewDate.getFullYear();
820
1059
  const month = viewDate.getMonth();
821
1060
  const firstDay = new Date(year, month, 1);
@@ -898,9 +1137,9 @@ function DatePicker({
898
1137
  };
899
1138
  const today = /* @__PURE__ */ new Date();
900
1139
  today.setHours(0, 0, 0, 0);
901
- return /* @__PURE__ */ jsxs12("div", { ref: containerRef, className: `relative ${className}`, children: [
902
- label && /* @__PURE__ */ jsx16("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: label }),
903
- /* @__PURE__ */ jsx16(
1140
+ return /* @__PURE__ */ jsxs13("div", { ref: containerRef, className: `relative ${className}`, children: [
1141
+ label && /* @__PURE__ */ jsx17("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: label }),
1142
+ /* @__PURE__ */ jsx17(
904
1143
  "div",
905
1144
  {
906
1145
  className: `
@@ -910,15 +1149,15 @@ function DatePicker({
910
1149
  transition-all
911
1150
  `,
912
1151
  onClick: () => !disabled && setIsOpen(!isOpen),
913
- children: /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between", children: [
914
- /* @__PURE__ */ jsx16("span", { className: displayText ? "text-gray-800" : "text-gray-400", children: displayText || placeholder }),
915
- /* @__PURE__ */ jsx16("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx16("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" }) })
1152
+ children: /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between", children: [
1153
+ /* @__PURE__ */ jsx17("span", { className: displayText ? "text-gray-800" : "text-gray-400", children: displayText || placeholder }),
1154
+ /* @__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
1155
  ] })
917
1156
  }
918
1157
  ),
919
- error && /* @__PURE__ */ jsx16("p", { className: "mt-1 text-xs text-red-600", children: error }),
920
- isOpen && /* @__PURE__ */ jsx16("div", { className: "absolute z-50 mt-1 bg-white border border-gray-200 rounded-xl shadow-lg p-4", children: /* @__PURE__ */ jsxs12("div", { className: range ? "flex gap-4" : "", children: [
921
- range && /* @__PURE__ */ jsx16("div", { className: "border-r border-gray-100 pr-4 space-y-1", children: PRESET_RANGES.map((preset) => /* @__PURE__ */ jsx16(
1158
+ error && /* @__PURE__ */ jsx17("p", { className: "mt-1 text-xs text-red-600", children: error }),
1159
+ 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: [
1160
+ range && /* @__PURE__ */ jsx17("div", { className: "border-r border-gray-100 pr-4 space-y-1", children: PRESET_RANGES.map((preset) => /* @__PURE__ */ jsx17(
922
1161
  "button",
923
1162
  {
924
1163
  type: "button",
@@ -928,42 +1167,42 @@ function DatePicker({
928
1167
  },
929
1168
  preset.label
930
1169
  )) }),
931
- /* @__PURE__ */ jsxs12("div", { children: [
932
- /* @__PURE__ */ jsxs12("div", { className: "flex items-center justify-between mb-4", children: [
933
- /* @__PURE__ */ jsx16(
1170
+ /* @__PURE__ */ jsxs13("div", { children: [
1171
+ /* @__PURE__ */ jsxs13("div", { className: "flex items-center justify-between mb-4", children: [
1172
+ /* @__PURE__ */ jsx17(
934
1173
  "button",
935
1174
  {
936
1175
  type: "button",
937
1176
  className: "p-1 hover:bg-gray-100 rounded",
938
1177
  onClick: goToPrevMonth,
939
- children: /* @__PURE__ */ jsx16("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx16("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
1178
+ 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
1179
  }
941
1180
  ),
942
- /* @__PURE__ */ jsxs12("span", { className: "text-sm font-semibold text-gray-800", children: [
1181
+ /* @__PURE__ */ jsxs13("span", { className: "text-sm font-semibold text-gray-800", children: [
943
1182
  MONTHS[viewDate.getMonth()],
944
1183
  " ",
945
1184
  viewDate.getFullYear()
946
1185
  ] }),
947
- /* @__PURE__ */ jsx16(
1186
+ /* @__PURE__ */ jsx17(
948
1187
  "button",
949
1188
  {
950
1189
  type: "button",
951
1190
  className: "p-1 hover:bg-gray-100 rounded",
952
1191
  onClick: goToNextMonth,
953
- children: /* @__PURE__ */ jsx16("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx16("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
1192
+ 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
1193
  }
955
1194
  )
956
1195
  ] }),
957
- /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-7 gap-1 mb-2", children: WEEKDAYS.map((day) => /* @__PURE__ */ jsx16("div", { className: "text-center text-xs font-medium text-gray-500 py-1", children: day }, day)) }),
958
- /* @__PURE__ */ jsx16("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
1196
+ /* @__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)) }),
1197
+ /* @__PURE__ */ jsx17("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
959
1198
  if (!date) {
960
- return /* @__PURE__ */ jsx16("div", { className: "w-9 h-9" }, `empty-${index}`);
1199
+ return /* @__PURE__ */ jsx17("div", { className: "w-9 h-9" }, `empty-${index}`);
961
1200
  }
962
1201
  const isDisabled = isDateDisabled(date);
963
1202
  const isSelected = isDateSelected(date);
964
1203
  const inRange = isDateInRange(date);
965
1204
  const isToday = isSameDay(date, today);
966
- return /* @__PURE__ */ jsx16(
1205
+ return /* @__PURE__ */ jsx17(
967
1206
  "button",
968
1207
  {
969
1208
  type: "button",
@@ -989,8 +1228,8 @@ function DatePicker({
989
1228
  }
990
1229
 
991
1230
  // src/components/Timer.tsx
992
- import { useState as useState5, useEffect as useEffect4, useCallback, useRef as useRef3 } from "react";
993
- import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1231
+ import { useState as useState6, useEffect as useEffect4, useCallback as useCallback2, useRef as useRef3 } from "react";
1232
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
994
1233
  function formatTime(totalSeconds) {
995
1234
  const hours = Math.floor(totalSeconds / 3600);
996
1235
  const minutes = Math.floor(totalSeconds % 3600 / 60);
@@ -1014,8 +1253,8 @@ function Timer({
1014
1253
  elapsedSeconds: controlledElapsedSeconds
1015
1254
  }) {
1016
1255
  const isControlled = controlledIsRunning !== void 0;
1017
- const [internalIsRunning, setInternalIsRunning] = useState5(false);
1018
- const [internalElapsedSeconds, setInternalElapsedSeconds] = useState5(initialSeconds);
1256
+ const [internalIsRunning, setInternalIsRunning] = useState6(false);
1257
+ const [internalElapsedSeconds, setInternalElapsedSeconds] = useState6(initialSeconds);
1019
1258
  const isRunning = isControlled ? controlledIsRunning : internalIsRunning;
1020
1259
  const elapsedSeconds = isControlled ? controlledElapsedSeconds ?? 0 : internalElapsedSeconds;
1021
1260
  const intervalRef = useRef3(null);
@@ -1050,7 +1289,7 @@ function Timer({
1050
1289
  }
1051
1290
  };
1052
1291
  }, [isRunning, isControlled, onTick]);
1053
- const handleStart = useCallback(() => {
1292
+ const handleStart = useCallback2(() => {
1054
1293
  const now = /* @__PURE__ */ new Date();
1055
1294
  startTimeRef.current = now;
1056
1295
  if (!isControlled) {
@@ -1058,13 +1297,13 @@ function Timer({
1058
1297
  }
1059
1298
  onStart?.(now);
1060
1299
  }, [isControlled, onStart]);
1061
- const handleStop = useCallback(() => {
1300
+ const handleStop = useCallback2(() => {
1062
1301
  if (!isControlled) {
1063
1302
  setInternalIsRunning(false);
1064
1303
  }
1065
1304
  onStop?.(elapsedSeconds);
1066
1305
  }, [isControlled, elapsedSeconds, onStop]);
1067
- const handleReset = useCallback(() => {
1306
+ const handleReset = useCallback2(() => {
1068
1307
  if (!isControlled) {
1069
1308
  setInternalIsRunning(false);
1070
1309
  setInternalElapsedSeconds(0);
@@ -1072,7 +1311,7 @@ function Timer({
1072
1311
  startTimeRef.current = null;
1073
1312
  onReset?.();
1074
1313
  }, [isControlled, onReset]);
1075
- const handleToggle = useCallback(() => {
1314
+ const handleToggle = useCallback2(() => {
1076
1315
  if (isRunning) {
1077
1316
  handleStop();
1078
1317
  } else {
@@ -1100,10 +1339,10 @@ function Timer({
1100
1339
  }
1101
1340
  };
1102
1341
  const styles = sizeClasses3[size];
1103
- return /* @__PURE__ */ jsxs13("div", { className: `flex items-center ${styles.container} ${className}`, children: [
1104
- /* @__PURE__ */ jsx17("div", { className: `font-mono font-bold text-gray-800 ${styles.time} tabular-nums`, children: formatTime(elapsedSeconds) }),
1105
- /* @__PURE__ */ jsxs13("div", { className: "flex items-center gap-2", children: [
1106
- /* @__PURE__ */ jsx17(
1342
+ return /* @__PURE__ */ jsxs14("div", { className: `flex items-center ${styles.container} ${className}`, children: [
1343
+ /* @__PURE__ */ jsx18("div", { className: `font-mono font-bold text-gray-800 ${styles.time} tabular-nums`, children: formatTime(elapsedSeconds) }),
1344
+ /* @__PURE__ */ jsxs14("div", { className: "flex items-center gap-2", children: [
1345
+ /* @__PURE__ */ jsx18(
1107
1346
  "button",
1108
1347
  {
1109
1348
  type: "button",
@@ -1117,14 +1356,14 @@ function Timer({
1117
1356
  title: isRunning ? "Pause" : "Start",
1118
1357
  children: isRunning ? (
1119
1358
  // Pause icon
1120
- /* @__PURE__ */ jsx17("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx17("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) })
1359
+ /* @__PURE__ */ jsx18("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) })
1121
1360
  ) : (
1122
1361
  // Play icon
1123
- /* @__PURE__ */ jsx17("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx17("path", { d: "M8 5v14l11-7z" }) })
1362
+ /* @__PURE__ */ jsx18("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { d: "M8 5v14l11-7z" }) })
1124
1363
  )
1125
1364
  }
1126
1365
  ),
1127
- elapsedSeconds > 0 && /* @__PURE__ */ jsx17(
1366
+ elapsedSeconds > 0 && /* @__PURE__ */ jsx18(
1128
1367
  "button",
1129
1368
  {
1130
1369
  type: "button",
@@ -1135,10 +1374,10 @@ function Timer({
1135
1374
  transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500
1136
1375
  `,
1137
1376
  title: "Stop",
1138
- children: /* @__PURE__ */ jsx17("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx17("path", { d: "M6 6h12v12H6z" }) })
1377
+ children: /* @__PURE__ */ jsx18("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx18("path", { d: "M6 6h12v12H6z" }) })
1139
1378
  }
1140
1379
  ),
1141
- showReset && elapsedSeconds > 0 && !isRunning && /* @__PURE__ */ jsx17(
1380
+ showReset && elapsedSeconds > 0 && !isRunning && /* @__PURE__ */ jsx18(
1142
1381
  "button",
1143
1382
  {
1144
1383
  type: "button",
@@ -1149,7 +1388,7 @@ function Timer({
1149
1388
  transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400
1150
1389
  `,
1151
1390
  title: "Reset",
1152
- children: /* @__PURE__ */ jsx17("svg", { className: styles.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ jsx17("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" }) })
1391
+ 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
1392
  }
1154
1393
  )
1155
1394
  ] })
@@ -1158,6 +1397,7 @@ function Timer({
1158
1397
  export {
1159
1398
  Button,
1160
1399
  Card,
1400
+ DataTable,
1161
1401
  DatePicker,
1162
1402
  EmptyState,
1163
1403
  FormButtonGroup,
@@ -1173,6 +1413,7 @@ export {
1173
1413
  Table,
1174
1414
  Tabs,
1175
1415
  Timer,
1416
+ createFilterOptions,
1176
1417
  formatTime
1177
1418
  };
1178
1419
  //# sourceMappingURL=index.mjs.map