@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.js CHANGED
@@ -22,6 +22,7 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Button: () => Button,
24
24
  Card: () => Card,
25
+ DataTable: () => DataTable,
25
26
  DatePicker: () => DatePicker,
26
27
  EmptyState: () => EmptyState,
27
28
  FormButtonGroup: () => FormButtonGroup,
@@ -37,6 +38,7 @@ __export(index_exports, {
37
38
  Table: () => Table,
38
39
  Tabs: () => Tabs,
39
40
  Timer: () => Timer,
41
+ createFilterOptions: () => createFilterOptions,
40
42
  formatTime: () => formatTime
41
43
  });
42
44
  module.exports = __toCommonJS(index_exports);
@@ -429,6 +431,9 @@ function Table({
429
431
  ] }) });
430
432
  }
431
433
 
434
+ // src/components/DataTable.tsx
435
+ var import_react7 = require("react");
436
+
432
437
  // src/components/Select.tsx
433
438
  var import_react6 = require("react");
434
439
  var import_jsx_runtime14 = require("react/jsx-runtime");
@@ -612,9 +617,245 @@ function Select({
612
617
  ] });
613
618
  }
614
619
 
615
- // src/components/Tabs.tsx
616
- var import_react7 = require("react");
620
+ // src/components/DataTable.tsx
617
621
  var import_jsx_runtime15 = require("react/jsx-runtime");
622
+ function ColumnFilter({ column, value, onChange }) {
623
+ const filterType = column.filterType ?? "text";
624
+ if (filterType === "none") {
625
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "h-9" });
626
+ }
627
+ if (filterType === "select" && column.filterOptions) {
628
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
629
+ Select,
630
+ {
631
+ options: [{ value: "", label: "Alla" }, ...column.filterOptions],
632
+ value: value || "",
633
+ onChange: (val) => onChange(val),
634
+ placeholder: column.filterPlaceholder || "Alla",
635
+ className: "w-full text-sm"
636
+ }
637
+ );
638
+ }
639
+ if (filterType === "multiselect" && column.filterOptions) {
640
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
641
+ Select,
642
+ {
643
+ options: column.filterOptions,
644
+ value: value || [],
645
+ onChange: (val) => onChange(val),
646
+ placeholder: column.filterPlaceholder || "Alla",
647
+ multiple: true,
648
+ className: "w-full text-sm"
649
+ }
650
+ );
651
+ }
652
+ if (filterType === "boolean") {
653
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
654
+ Select,
655
+ {
656
+ options: [
657
+ { value: "", label: "Alla" },
658
+ { value: "true", label: "Ja" },
659
+ { value: "false", label: "Nej" }
660
+ ],
661
+ value: value || "",
662
+ onChange: (val) => onChange(val),
663
+ className: "w-full text-sm"
664
+ }
665
+ );
666
+ }
667
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
668
+ Input,
669
+ {
670
+ type: "text",
671
+ value: value || "",
672
+ onChange: (e) => onChange(e.target.value),
673
+ placeholder: column.filterPlaceholder || `Filtrera ${column.header.toLowerCase()}...`,
674
+ className: "w-full text-sm h-9"
675
+ }
676
+ );
677
+ }
678
+ function DataTable({
679
+ data,
680
+ columns,
681
+ getRowKey,
682
+ onRowClick,
683
+ loading,
684
+ emptyMessage = "Ingen data att visa.",
685
+ className,
686
+ showFilters = true,
687
+ initialSortKey,
688
+ initialSortDirection = "asc",
689
+ onFilteredDataChange
690
+ }) {
691
+ const [filters, setFilters] = (0, import_react7.useState)({});
692
+ const [sortKey, setSortKey] = (0, import_react7.useState)(initialSortKey || null);
693
+ const [sortDirection, setSortDirection] = (0, import_react7.useState)(initialSortDirection);
694
+ const handleFilterChange = (0, import_react7.useCallback)((columnKey, value) => {
695
+ setFilters((prev) => {
696
+ const next = { ...prev };
697
+ if (value === "" || Array.isArray(value) && value.length === 0) {
698
+ delete next[columnKey];
699
+ } else {
700
+ next[columnKey] = value;
701
+ }
702
+ return next;
703
+ });
704
+ }, []);
705
+ const clearFilters = (0, import_react7.useCallback)(() => {
706
+ setFilters({});
707
+ }, []);
708
+ const filteredData = (0, import_react7.useMemo)(() => {
709
+ let result = [...data];
710
+ for (const [columnKey, filterValue] of Object.entries(filters)) {
711
+ if (!filterValue || Array.isArray(filterValue) && filterValue.length === 0) continue;
712
+ const column = columns.find((c) => c.key === columnKey);
713
+ if (!column) continue;
714
+ const getFilterableValue = column.filterValue || ((item) => {
715
+ return item[columnKey];
716
+ });
717
+ result = result.filter((item) => {
718
+ const itemValue = getFilterableValue(item);
719
+ if (itemValue === null || itemValue === void 0) {
720
+ return filterValue === "";
721
+ }
722
+ const filterType = column.filterType ?? "text";
723
+ if (filterType === "boolean") {
724
+ const boolFilterValue = filterValue === "true";
725
+ return itemValue === boolFilterValue;
726
+ }
727
+ if (filterType === "multiselect" && Array.isArray(filterValue)) {
728
+ return filterValue.includes(String(itemValue));
729
+ }
730
+ if (filterType === "select") {
731
+ return String(itemValue).toLowerCase() === String(filterValue).toLowerCase();
732
+ }
733
+ return String(itemValue).toLowerCase().includes(String(filterValue).toLowerCase());
734
+ });
735
+ }
736
+ return result;
737
+ }, [data, filters, columns]);
738
+ const sortedData = (0, import_react7.useMemo)(() => {
739
+ if (!sortKey) return filteredData;
740
+ const column = columns.find((c) => c.key === sortKey);
741
+ if (!column) return filteredData;
742
+ const sorted = [...filteredData].sort((a, b) => {
743
+ if (column.sortFn) {
744
+ return column.sortFn(a, b);
745
+ }
746
+ const getValueForSort = column.filterValue || ((item) => {
747
+ return item[sortKey];
748
+ });
749
+ const aVal = getValueForSort(a);
750
+ const bVal = getValueForSort(b);
751
+ if (aVal === null || aVal === void 0) return 1;
752
+ if (bVal === null || bVal === void 0) return -1;
753
+ if (typeof aVal === "string" && typeof bVal === "string") {
754
+ return aVal.localeCompare(bVal, "sv");
755
+ }
756
+ if (aVal < bVal) return -1;
757
+ if (aVal > bVal) return 1;
758
+ return 0;
759
+ });
760
+ return sortDirection === "desc" ? sorted.reverse() : sorted;
761
+ }, [filteredData, sortKey, sortDirection, columns]);
762
+ (0, import_react7.useMemo)(() => {
763
+ onFilteredDataChange?.(sortedData);
764
+ }, [sortedData, onFilteredDataChange]);
765
+ const handleSort = (0, import_react7.useCallback)((columnKey) => {
766
+ if (sortKey === columnKey) {
767
+ setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
768
+ } else {
769
+ setSortKey(columnKey);
770
+ setSortDirection("asc");
771
+ }
772
+ }, [sortKey]);
773
+ const tableColumns = (0, import_react7.useMemo)(() => {
774
+ return columns.map((column) => {
775
+ const isSortable = column.sortable !== false && column.filterType !== "none";
776
+ const isCurrentSort = sortKey === column.key;
777
+ return {
778
+ key: column.key,
779
+ header: isSortable ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
780
+ "button",
781
+ {
782
+ onClick: () => handleSort(column.key),
783
+ className: "flex items-center gap-1 hover:text-gray-900 transition-colors w-full text-left",
784
+ children: [
785
+ column.header,
786
+ isCurrentSort ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-primary-600", children: sortDirection === "asc" ? "\u2191" : "\u2193" }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { className: "text-gray-400 opacity-50", children: "\u2195" })
787
+ ]
788
+ }
789
+ ) : column.header,
790
+ render: column.render,
791
+ width: column.width,
792
+ align: column.align,
793
+ sortable: false
794
+ // We handle sorting ourselves
795
+ };
796
+ });
797
+ }, [columns, sortKey, sortDirection, handleSort]);
798
+ const hasActiveFilters = Object.keys(filters).length > 0;
799
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className, children: [
800
+ showFilters && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "mb-4", children: [
801
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "flex flex-wrap items-center gap-2 mb-2", children: [
802
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "text-sm text-gray-500", children: [
803
+ "Visar ",
804
+ sortedData.length,
805
+ " av ",
806
+ data.length
807
+ ] }),
808
+ hasActiveFilters && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
809
+ "button",
810
+ {
811
+ onClick: clearFilters,
812
+ className: "text-sm text-primary-600 hover:underline",
813
+ children: "Rensa filter"
814
+ }
815
+ )
816
+ ] }),
817
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("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__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "min-w-0", children: [
818
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("label", { className: "text-xs text-gray-500 mb-1 block truncate", children: column.header }),
819
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
820
+ ColumnFilter,
821
+ {
822
+ column,
823
+ value: filters[column.key] || "",
824
+ onChange: (value) => handleFilterChange(column.key, value)
825
+ }
826
+ )
827
+ ] }, column.key)) })
828
+ ] }),
829
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
830
+ Table,
831
+ {
832
+ data: sortedData,
833
+ columns: tableColumns,
834
+ getRowKey,
835
+ onRowClick,
836
+ loading,
837
+ emptyMessage
838
+ }
839
+ )
840
+ ] });
841
+ }
842
+ function createFilterOptions(data, getValue, labelMap) {
843
+ const uniqueValues = /* @__PURE__ */ new Set();
844
+ for (const item of data) {
845
+ const value = getValue(item);
846
+ if (value !== null && value !== void 0 && value !== "") {
847
+ uniqueValues.add(value);
848
+ }
849
+ }
850
+ return Array.from(uniqueValues).sort((a, b) => a.localeCompare(b, "sv")).map((value) => ({
851
+ value,
852
+ label: labelMap?.[value] || value
853
+ }));
854
+ }
855
+
856
+ // src/components/Tabs.tsx
857
+ var import_react8 = require("react");
858
+ var import_jsx_runtime16 = require("react/jsx-runtime");
618
859
  function Tabs({
619
860
  tabs,
620
861
  activeTab: controlledActiveTab,
@@ -625,7 +866,7 @@ function Tabs({
625
866
  className = ""
626
867
  }) {
627
868
  const isControlled = controlledActiveTab !== void 0;
628
- const [internalActiveTab, setInternalActiveTab] = (0, import_react7.useState)(
869
+ const [internalActiveTab, setInternalActiveTab] = (0, import_react8.useState)(
629
870
  defaultTab || tabs.find((t) => !t.disabled)?.id || tabs[0]?.id
630
871
  );
631
872
  const activeTab = isControlled ? controlledActiveTab : internalActiveTab;
@@ -693,11 +934,11 @@ function Tabs({
693
934
  }
694
935
  };
695
936
  const styles = variantStyles[variant];
696
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className, children: [
697
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: `flex ${styles.container}`, role: "tablist", children: tabs.map((tab, index) => {
937
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className, children: [
938
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: `flex ${styles.container}`, role: "tablist", children: tabs.map((tab, index) => {
698
939
  const isActive = tab.id === activeTab;
699
940
  const isDisabled = tab.disabled ?? false;
700
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
941
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
701
942
  "button",
702
943
  {
703
944
  type: "button",
@@ -709,7 +950,7 @@ function Tabs({
709
950
  className: styles.tab(isActive, isDisabled),
710
951
  onClick: () => handleTabClick(tab),
711
952
  onKeyDown: (e) => handleKeyDown(e, index),
712
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "flex items-center gap-2", children: [
953
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "flex items-center gap-2", children: [
713
954
  tab.icon,
714
955
  tab.label
715
956
  ] })
@@ -717,13 +958,13 @@ function Tabs({
717
958
  tab.id
718
959
  );
719
960
  }) }),
720
- renderContent && activeContent && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "pt-4", role: "tabpanel", children: activeContent })
961
+ renderContent && activeContent && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "pt-4", role: "tabpanel", children: activeContent })
721
962
  ] });
722
963
  }
723
964
 
724
965
  // src/components/DatePicker.tsx
725
- var import_react8 = require("react");
726
- var import_jsx_runtime16 = require("react/jsx-runtime");
966
+ var import_react9 = require("react");
967
+ var import_jsx_runtime17 = require("react/jsx-runtime");
727
968
  var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
728
969
  var MONTHS = [
729
970
  "January",
@@ -826,12 +1067,12 @@ function DatePicker({
826
1067
  disabled = false,
827
1068
  className = ""
828
1069
  }) {
829
- const [isOpen, setIsOpen] = (0, import_react8.useState)(false);
830
- const [viewDate, setViewDate] = (0, import_react8.useState)(/* @__PURE__ */ new Date());
831
- const [hoverDate, setHoverDate] = (0, import_react8.useState)(null);
832
- const containerRef = (0, import_react8.useRef)(null);
833
- const [selectingEnd, setSelectingEnd] = (0, import_react8.useState)(false);
834
- (0, import_react8.useEffect)(() => {
1070
+ const [isOpen, setIsOpen] = (0, import_react9.useState)(false);
1071
+ const [viewDate, setViewDate] = (0, import_react9.useState)(/* @__PURE__ */ new Date());
1072
+ const [hoverDate, setHoverDate] = (0, import_react9.useState)(null);
1073
+ const containerRef = (0, import_react9.useRef)(null);
1074
+ const [selectingEnd, setSelectingEnd] = (0, import_react9.useState)(false);
1075
+ (0, import_react9.useEffect)(() => {
835
1076
  const handleClickOutside = (e) => {
836
1077
  if (containerRef.current && !containerRef.current.contains(e.target)) {
837
1078
  setIsOpen(false);
@@ -841,7 +1082,7 @@ function DatePicker({
841
1082
  document.addEventListener("mousedown", handleClickOutside);
842
1083
  return () => document.removeEventListener("mousedown", handleClickOutside);
843
1084
  }, []);
844
- const displayText = (0, import_react8.useMemo)(() => {
1085
+ const displayText = (0, import_react9.useMemo)(() => {
845
1086
  if (!value) return "";
846
1087
  if (range) {
847
1088
  const rangeValue = value;
@@ -858,7 +1099,7 @@ function DatePicker({
858
1099
  }
859
1100
  return formatDate(value);
860
1101
  }, [value, range]);
861
- const calendarDays = (0, import_react8.useMemo)(() => {
1102
+ const calendarDays = (0, import_react9.useMemo)(() => {
862
1103
  const year = viewDate.getFullYear();
863
1104
  const month = viewDate.getMonth();
864
1105
  const firstDay = new Date(year, month, 1);
@@ -941,9 +1182,9 @@ function DatePicker({
941
1182
  };
942
1183
  const today = /* @__PURE__ */ new Date();
943
1184
  today.setHours(0, 0, 0, 0);
944
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { ref: containerRef, className: `relative ${className}`, children: [
945
- label && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: label }),
946
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1185
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { ref: containerRef, className: `relative ${className}`, children: [
1186
+ label && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("label", { className: "block text-sm font-medium text-gray-700 mb-2", children: label }),
1187
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
947
1188
  "div",
948
1189
  {
949
1190
  className: `
@@ -953,15 +1194,15 @@ function DatePicker({
953
1194
  transition-all
954
1195
  `,
955
1196
  onClick: () => !disabled && setIsOpen(!isOpen),
956
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between", children: [
957
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: displayText ? "text-gray-800" : "text-gray-400", children: displayText || placeholder }),
958
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("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" }) })
1197
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between", children: [
1198
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: displayText ? "text-gray-800" : "text-gray-400", children: displayText || placeholder }),
1199
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: "w-5 h-5 text-gray-400", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("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" }) })
959
1200
  ] })
960
1201
  }
961
1202
  ),
962
- error && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "mt-1 text-xs text-red-600", children: error }),
963
- isOpen && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "absolute z-50 mt-1 bg-white border border-gray-200 rounded-xl shadow-lg p-4", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: range ? "flex gap-4" : "", children: [
964
- range && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "border-r border-gray-100 pr-4 space-y-1", children: PRESET_RANGES.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1203
+ error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "mt-1 text-xs text-red-600", children: error }),
1204
+ isOpen && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "absolute z-50 mt-1 bg-white border border-gray-200 rounded-xl shadow-lg p-4", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: range ? "flex gap-4" : "", children: [
1205
+ range && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "border-r border-gray-100 pr-4 space-y-1", children: PRESET_RANGES.map((preset) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
965
1206
  "button",
966
1207
  {
967
1208
  type: "button",
@@ -971,42 +1212,42 @@ function DatePicker({
971
1212
  },
972
1213
  preset.label
973
1214
  )) }),
974
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
975
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
976
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1215
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
1216
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center justify-between mb-4", children: [
1217
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
977
1218
  "button",
978
1219
  {
979
1220
  type: "button",
980
1221
  className: "p-1 hover:bg-gray-100 rounded",
981
1222
  onClick: goToPrevMonth,
982
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
1223
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M15 19l-7-7 7-7" }) })
983
1224
  }
984
1225
  ),
985
- /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "text-sm font-semibold text-gray-800", children: [
1226
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "text-sm font-semibold text-gray-800", children: [
986
1227
  MONTHS[viewDate.getMonth()],
987
1228
  " ",
988
1229
  viewDate.getFullYear()
989
1230
  ] }),
990
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1231
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
991
1232
  "button",
992
1233
  {
993
1234
  type: "button",
994
1235
  className: "p-1 hover:bg-gray-100 rounded",
995
1236
  onClick: goToNextMonth,
996
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
1237
+ children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: "w-5 h-5 text-gray-600", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M9 5l7 7-7 7" }) })
997
1238
  }
998
1239
  )
999
1240
  ] }),
1000
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-7 gap-1 mb-2", children: WEEKDAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "text-center text-xs font-medium text-gray-500 py-1", children: day }, day)) }),
1001
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
1241
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "grid grid-cols-7 gap-1 mb-2", children: WEEKDAYS.map((day) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "text-center text-xs font-medium text-gray-500 py-1", children: day }, day)) }),
1242
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "grid grid-cols-7 gap-1", children: calendarDays.map((date, index) => {
1002
1243
  if (!date) {
1003
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "w-9 h-9" }, `empty-${index}`);
1244
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "w-9 h-9" }, `empty-${index}`);
1004
1245
  }
1005
1246
  const isDisabled = isDateDisabled(date);
1006
1247
  const isSelected = isDateSelected(date);
1007
1248
  const inRange = isDateInRange(date);
1008
1249
  const isToday = isSameDay(date, today);
1009
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1250
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1010
1251
  "button",
1011
1252
  {
1012
1253
  type: "button",
@@ -1032,8 +1273,8 @@ function DatePicker({
1032
1273
  }
1033
1274
 
1034
1275
  // src/components/Timer.tsx
1035
- var import_react9 = require("react");
1036
- var import_jsx_runtime17 = require("react/jsx-runtime");
1276
+ var import_react10 = require("react");
1277
+ var import_jsx_runtime18 = require("react/jsx-runtime");
1037
1278
  function formatTime(totalSeconds) {
1038
1279
  const hours = Math.floor(totalSeconds / 3600);
1039
1280
  const minutes = Math.floor(totalSeconds % 3600 / 60);
@@ -1057,20 +1298,20 @@ function Timer({
1057
1298
  elapsedSeconds: controlledElapsedSeconds
1058
1299
  }) {
1059
1300
  const isControlled = controlledIsRunning !== void 0;
1060
- const [internalIsRunning, setInternalIsRunning] = (0, import_react9.useState)(false);
1061
- const [internalElapsedSeconds, setInternalElapsedSeconds] = (0, import_react9.useState)(initialSeconds);
1301
+ const [internalIsRunning, setInternalIsRunning] = (0, import_react10.useState)(false);
1302
+ const [internalElapsedSeconds, setInternalElapsedSeconds] = (0, import_react10.useState)(initialSeconds);
1062
1303
  const isRunning = isControlled ? controlledIsRunning : internalIsRunning;
1063
1304
  const elapsedSeconds = isControlled ? controlledElapsedSeconds ?? 0 : internalElapsedSeconds;
1064
- const intervalRef = (0, import_react9.useRef)(null);
1065
- const startTimeRef = (0, import_react9.useRef)(null);
1066
- (0, import_react9.useEffect)(() => {
1305
+ const intervalRef = (0, import_react10.useRef)(null);
1306
+ const startTimeRef = (0, import_react10.useRef)(null);
1307
+ (0, import_react10.useEffect)(() => {
1067
1308
  return () => {
1068
1309
  if (intervalRef.current) {
1069
1310
  clearInterval(intervalRef.current);
1070
1311
  }
1071
1312
  };
1072
1313
  }, []);
1073
- (0, import_react9.useEffect)(() => {
1314
+ (0, import_react10.useEffect)(() => {
1074
1315
  if (isControlled) return;
1075
1316
  if (isRunning) {
1076
1317
  intervalRef.current = setInterval(() => {
@@ -1093,7 +1334,7 @@ function Timer({
1093
1334
  }
1094
1335
  };
1095
1336
  }, [isRunning, isControlled, onTick]);
1096
- const handleStart = (0, import_react9.useCallback)(() => {
1337
+ const handleStart = (0, import_react10.useCallback)(() => {
1097
1338
  const now = /* @__PURE__ */ new Date();
1098
1339
  startTimeRef.current = now;
1099
1340
  if (!isControlled) {
@@ -1101,13 +1342,13 @@ function Timer({
1101
1342
  }
1102
1343
  onStart?.(now);
1103
1344
  }, [isControlled, onStart]);
1104
- const handleStop = (0, import_react9.useCallback)(() => {
1345
+ const handleStop = (0, import_react10.useCallback)(() => {
1105
1346
  if (!isControlled) {
1106
1347
  setInternalIsRunning(false);
1107
1348
  }
1108
1349
  onStop?.(elapsedSeconds);
1109
1350
  }, [isControlled, elapsedSeconds, onStop]);
1110
- const handleReset = (0, import_react9.useCallback)(() => {
1351
+ const handleReset = (0, import_react10.useCallback)(() => {
1111
1352
  if (!isControlled) {
1112
1353
  setInternalIsRunning(false);
1113
1354
  setInternalElapsedSeconds(0);
@@ -1115,7 +1356,7 @@ function Timer({
1115
1356
  startTimeRef.current = null;
1116
1357
  onReset?.();
1117
1358
  }, [isControlled, onReset]);
1118
- const handleToggle = (0, import_react9.useCallback)(() => {
1359
+ const handleToggle = (0, import_react10.useCallback)(() => {
1119
1360
  if (isRunning) {
1120
1361
  handleStop();
1121
1362
  } else {
@@ -1143,10 +1384,10 @@ function Timer({
1143
1384
  }
1144
1385
  };
1145
1386
  const styles = sizeClasses3[size];
1146
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: `flex items-center ${styles.container} ${className}`, children: [
1147
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: `font-mono font-bold text-gray-800 ${styles.time} tabular-nums`, children: formatTime(elapsedSeconds) }),
1148
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "flex items-center gap-2", children: [
1149
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1387
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: `flex items-center ${styles.container} ${className}`, children: [
1388
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: `font-mono font-bold text-gray-800 ${styles.time} tabular-nums`, children: formatTime(elapsedSeconds) }),
1389
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "flex items-center gap-2", children: [
1390
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1150
1391
  "button",
1151
1392
  {
1152
1393
  type: "button",
@@ -1160,14 +1401,14 @@ function Timer({
1160
1401
  title: isRunning ? "Pause" : "Start",
1161
1402
  children: isRunning ? (
1162
1403
  // Pause icon
1163
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) })
1404
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M6 4h4v16H6V4zm8 0h4v16h-4V4z" }) })
1164
1405
  ) : (
1165
1406
  // Play icon
1166
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M8 5v14l11-7z" }) })
1407
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M8 5v14l11-7z" }) })
1167
1408
  )
1168
1409
  }
1169
1410
  ),
1170
- elapsedSeconds > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1411
+ elapsedSeconds > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1171
1412
  "button",
1172
1413
  {
1173
1414
  type: "button",
@@ -1178,10 +1419,10 @@ function Timer({
1178
1419
  transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500
1179
1420
  `,
1180
1421
  title: "Stop",
1181
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("path", { d: "M6 6h12v12H6z" }) })
1422
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: styles.icon, fill: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("path", { d: "M6 6h12v12H6z" }) })
1182
1423
  }
1183
1424
  ),
1184
- showReset && elapsedSeconds > 0 && !isRunning && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1425
+ showReset && elapsedSeconds > 0 && !isRunning && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
1185
1426
  "button",
1186
1427
  {
1187
1428
  type: "button",
@@ -1192,7 +1433,7 @@ function Timer({
1192
1433
  transition-colors focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-gray-400
1193
1434
  `,
1194
1435
  title: "Reset",
1195
- children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("svg", { className: styles.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("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" }) })
1436
+ children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("svg", { className: styles.icon, fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("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" }) })
1196
1437
  }
1197
1438
  )
1198
1439
  ] })
@@ -1202,6 +1443,7 @@ function Timer({
1202
1443
  0 && (module.exports = {
1203
1444
  Button,
1204
1445
  Card,
1446
+ DataTable,
1205
1447
  DatePicker,
1206
1448
  EmptyState,
1207
1449
  FormButtonGroup,
@@ -1217,6 +1459,7 @@ function Timer({
1217
1459
  Table,
1218
1460
  Tabs,
1219
1461
  Timer,
1462
+ createFilterOptions,
1220
1463
  formatTime
1221
1464
  });
1222
1465
  //# sourceMappingURL=index.js.map