@kreativa/ui 0.1.1 → 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 +20 -6
- package/dist/index.d.ts +20 -6
- package/dist/index.js +114 -39
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +131 -56
- 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,70 +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
|
|
|
389
464
|
// src/components/DataTable.tsx
|
|
390
|
-
import { useState as useState3, useMemo as useMemo3, useCallback } from "react";
|
|
465
|
+
import { useState as useState3, useMemo as useMemo3, useCallback as useCallback2 } from "react";
|
|
391
466
|
|
|
392
467
|
// src/components/Select.tsx
|
|
393
|
-
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";
|
|
394
469
|
import { jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
395
470
|
function Select({
|
|
396
471
|
options,
|
|
@@ -407,8 +482,8 @@ function Select({
|
|
|
407
482
|
const [isOpen, setIsOpen] = useState2(false);
|
|
408
483
|
const [searchTerm, setSearchTerm] = useState2("");
|
|
409
484
|
const [highlightedIndex, setHighlightedIndex] = useState2(0);
|
|
410
|
-
const containerRef =
|
|
411
|
-
const inputRef =
|
|
485
|
+
const containerRef = useRef2(null);
|
|
486
|
+
const inputRef = useRef2(null);
|
|
412
487
|
const filteredOptions = useMemo2(() => {
|
|
413
488
|
if (!searchTerm) return options;
|
|
414
489
|
const term = searchTerm.toLowerCase();
|
|
@@ -646,7 +721,7 @@ function DataTable({
|
|
|
646
721
|
const [filters, setFilters] = useState3({});
|
|
647
722
|
const [sortKey, setSortKey] = useState3(initialSortKey || null);
|
|
648
723
|
const [sortDirection, setSortDirection] = useState3(initialSortDirection);
|
|
649
|
-
const handleFilterChange =
|
|
724
|
+
const handleFilterChange = useCallback2((columnKey, value) => {
|
|
650
725
|
setFilters((prev) => {
|
|
651
726
|
const next = { ...prev };
|
|
652
727
|
if (value === "" || Array.isArray(value) && value.length === 0) {
|
|
@@ -657,7 +732,7 @@ function DataTable({
|
|
|
657
732
|
return next;
|
|
658
733
|
});
|
|
659
734
|
}, []);
|
|
660
|
-
const clearFilters =
|
|
735
|
+
const clearFilters = useCallback2(() => {
|
|
661
736
|
setFilters({});
|
|
662
737
|
}, []);
|
|
663
738
|
const filteredData = useMemo3(() => {
|
|
@@ -717,7 +792,7 @@ function DataTable({
|
|
|
717
792
|
useMemo3(() => {
|
|
718
793
|
onFilteredDataChange?.(sortedData);
|
|
719
794
|
}, [sortedData, onFilteredDataChange]);
|
|
720
|
-
const handleSort =
|
|
795
|
+
const handleSort = useCallback2((columnKey) => {
|
|
721
796
|
if (sortKey === columnKey) {
|
|
722
797
|
setSortDirection((prev) => prev === "asc" ? "desc" : "asc");
|
|
723
798
|
} else {
|
|
@@ -918,7 +993,7 @@ function Tabs({
|
|
|
918
993
|
}
|
|
919
994
|
|
|
920
995
|
// src/components/DatePicker.tsx
|
|
921
|
-
import { useState as useState5, useRef as
|
|
996
|
+
import { useState as useState5, useRef as useRef3, useEffect as useEffect3, useMemo as useMemo4 } from "react";
|
|
922
997
|
import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
923
998
|
var WEEKDAYS = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
|
|
924
999
|
var MONTHS = [
|
|
@@ -1025,7 +1100,7 @@ function DatePicker({
|
|
|
1025
1100
|
const [isOpen, setIsOpen] = useState5(false);
|
|
1026
1101
|
const [viewDate, setViewDate] = useState5(/* @__PURE__ */ new Date());
|
|
1027
1102
|
const [hoverDate, setHoverDate] = useState5(null);
|
|
1028
|
-
const containerRef =
|
|
1103
|
+
const containerRef = useRef3(null);
|
|
1029
1104
|
const [selectingEnd, setSelectingEnd] = useState5(false);
|
|
1030
1105
|
useEffect3(() => {
|
|
1031
1106
|
const handleClickOutside = (e) => {
|
|
@@ -1228,7 +1303,7 @@ function DatePicker({
|
|
|
1228
1303
|
}
|
|
1229
1304
|
|
|
1230
1305
|
// src/components/Timer.tsx
|
|
1231
|
-
import { useState as useState6, useEffect as useEffect4, useCallback as
|
|
1306
|
+
import { useState as useState6, useEffect as useEffect4, useCallback as useCallback3, useRef as useRef4 } from "react";
|
|
1232
1307
|
import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1233
1308
|
function formatTime(totalSeconds) {
|
|
1234
1309
|
const hours = Math.floor(totalSeconds / 3600);
|
|
@@ -1257,8 +1332,8 @@ function Timer({
|
|
|
1257
1332
|
const [internalElapsedSeconds, setInternalElapsedSeconds] = useState6(initialSeconds);
|
|
1258
1333
|
const isRunning = isControlled ? controlledIsRunning : internalIsRunning;
|
|
1259
1334
|
const elapsedSeconds = isControlled ? controlledElapsedSeconds ?? 0 : internalElapsedSeconds;
|
|
1260
|
-
const intervalRef =
|
|
1261
|
-
const startTimeRef =
|
|
1335
|
+
const intervalRef = useRef4(null);
|
|
1336
|
+
const startTimeRef = useRef4(null);
|
|
1262
1337
|
useEffect4(() => {
|
|
1263
1338
|
return () => {
|
|
1264
1339
|
if (intervalRef.current) {
|
|
@@ -1289,7 +1364,7 @@ function Timer({
|
|
|
1289
1364
|
}
|
|
1290
1365
|
};
|
|
1291
1366
|
}, [isRunning, isControlled, onTick]);
|
|
1292
|
-
const handleStart =
|
|
1367
|
+
const handleStart = useCallback3(() => {
|
|
1293
1368
|
const now = /* @__PURE__ */ new Date();
|
|
1294
1369
|
startTimeRef.current = now;
|
|
1295
1370
|
if (!isControlled) {
|
|
@@ -1297,13 +1372,13 @@ function Timer({
|
|
|
1297
1372
|
}
|
|
1298
1373
|
onStart?.(now);
|
|
1299
1374
|
}, [isControlled, onStart]);
|
|
1300
|
-
const handleStop =
|
|
1375
|
+
const handleStop = useCallback3(() => {
|
|
1301
1376
|
if (!isControlled) {
|
|
1302
1377
|
setInternalIsRunning(false);
|
|
1303
1378
|
}
|
|
1304
1379
|
onStop?.(elapsedSeconds);
|
|
1305
1380
|
}, [isControlled, elapsedSeconds, onStop]);
|
|
1306
|
-
const handleReset =
|
|
1381
|
+
const handleReset = useCallback3(() => {
|
|
1307
1382
|
if (!isControlled) {
|
|
1308
1383
|
setInternalIsRunning(false);
|
|
1309
1384
|
setInternalElapsedSeconds(0);
|
|
@@ -1311,7 +1386,7 @@ function Timer({
|
|
|
1311
1386
|
startTimeRef.current = null;
|
|
1312
1387
|
onReset?.();
|
|
1313
1388
|
}, [isControlled, onReset]);
|
|
1314
|
-
const handleToggle =
|
|
1389
|
+
const handleToggle = useCallback3(() => {
|
|
1315
1390
|
if (isRunning) {
|
|
1316
1391
|
handleStop();
|
|
1317
1392
|
} else {
|