@pk-design/react-tailwind 1.3.0 → 1.4.0

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.
@@ -430,9 +430,7 @@ const TableRowLoader = ({ colSize, rowSize }) => (jsx(Fragment, { children: Arra
430
430
  /* ----------------------------------------------
431
431
  * Table
432
432
  * ---------------------------------------------- */
433
- const Table = ({ children, layout = 'auto', className = '' }) => {
434
- return (jsx("table", { className: buildClassName('border-collapse w-full divide-y divide-gray-200 dark:divide-gray-700', TABLE_LAYOUT[layout], className), children: children }));
435
- };
433
+ const Table = ({ children, layout = 'auto', className = '', caption, }) => (jsxs("table", { className: buildClassName('border-collapse w-full divide-y divide-gray-200 dark:divide-gray-700', TABLE_LAYOUT[layout], className), children: [caption && (jsx("caption", { className: "mb-2 text-sm text-left text-gray-500 dark:text-gray-400", children: caption })), children] }));
436
434
  /* ----------------------------------------------
437
435
  * Head
438
436
  * ---------------------------------------------- */
@@ -440,7 +438,7 @@ const TableHead = ({ children, className = '' }) => (jsx("thead", { className: b
440
438
  /* ----------------------------------------------
441
439
  * Body
442
440
  * ---------------------------------------------- */
443
- const TableBody = ({ children, loading, colSize, rowSize = 5, className, }) => (jsx("tbody", { className: buildClassName('text-sm text-gray-700 dark:text-white divide-y divide-gray-200 dark:divide-gray-700', className), children: loading ? jsx(TableRowLoader, { colSize: colSize, rowSize: rowSize }) : children }));
441
+ const TableBody = ({ children, loading, colSize = 1, rowSize = 5, className, }) => (jsx("tbody", { className: buildClassName('text-sm text-gray-700 dark:text-white divide-y divide-gray-200 dark:divide-gray-700', className), children: loading ? jsx(TableRowLoader, { colSize: colSize, rowSize: rowSize }) : children }));
444
442
  /* ----------------------------------------------
445
443
  * Foot
446
444
  * ---------------------------------------------- */
@@ -453,7 +451,7 @@ const TableRow = ({ children, hoverable = false, className, ...props }) => (jsx(
453
451
  * Cells
454
452
  * ---------------------------------------------- */
455
453
  const TableCell = ({ children, align = 'left', className, ...props }) => (jsx("td", { ...props, className: buildClassName('px-3 py-3 first:pl-4 last:pr-4 bg-white dark:bg-gray-900 group-hover:bg-gray-50 group-hover:dark:bg-gray-800', TEXT_ALIGN[align], className), children: jsx("div", { className: "leading-normal", children: children }) }));
456
- const TableHeaderCell = ({ children, align = 'left', className, ...props }) => (jsx("th", { ...props, className: buildClassName('px-3 py-3 first:pl-4 last:pr-4 tracking-wider whitespace-nowrap text-gray-800 dark:text-gray-300', TEXT_ALIGN[align], className), children: jsx(BodyText, { as: "span", className: "leading-none", children: children }) }));
454
+ const TableHeaderCell = ({ children, align = 'left', className, ...props }) => (jsx("th", { ...props, className: buildClassName('px-3 py-3 first:pl-4 last:pr-4 tracking-wider whitespace-nowrap text-gray-800 dark:text-gray-300', TEXT_ALIGN[align], className), children: children }));
457
455
  /* ----------------------------------------------
458
456
  * Empty Row
459
457
  * ---------------------------------------------- */
@@ -703,9 +701,11 @@ const SortIconMap = {
703
701
  };
704
702
  const getSortIcon = (sort) => sort ? (SortIconMap[sort]) : (jsx(SvgArrowUpDown, { className: "size-4 text-gray-400 shrink-0 group-hover:text-gray-800 dark:group-hover:text-white" }));
705
703
 
706
- /**
707
- * Smart auto-sort helper (optional usage)
708
- */
704
+ const DENSITY_CELL_CLASS$2 = {
705
+ compact: 'px-2 py-1.5',
706
+ default: '',
707
+ spacious: 'px-4 py-4',
708
+ };
709
709
  const autoSortItems = (items, column, sort) => {
710
710
  const path = column.name;
711
711
  return [...items].sort((a, b) => {
@@ -721,7 +721,6 @@ const autoSortItems = (items, column, sort) => {
721
721
  const dB = new Date(valueB).getTime();
722
722
  return sort === 'asc' || sort === '1' ? dA - dB : dB - dA;
723
723
  }
724
- // String fallback
725
724
  const sA = String(valueA).toLowerCase();
726
725
  const sB = String(valueB).toLowerCase();
727
726
  if (sA < sB)
@@ -731,7 +730,7 @@ const autoSortItems = (items, column, sort) => {
731
730
  return 0;
732
731
  });
733
732
  };
734
- const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination = null, setPagination = () => { }, emptyMessage = 'No data found', containerClass = '', wrapperClass = '', layout = 'auto', }) => {
733
+ function DataTable({ items, columns, sorting = {}, onSort, loading, pagination, setPagination = () => { }, emptyMessage = 'No data found', containerClass = '', wrapperClass = '', tableClass = '', headClass = '', footerRow, rowKey = 'id', onRowClick, rowClass, density = 'default', striped = false, layout = 'auto', }) {
735
734
  const internalSorting = useRef({});
736
735
  const [sortedItems, setSortedItems] = useState(items);
737
736
  useEffect(() => {
@@ -746,17 +745,38 @@ const DataTable = ({ items, columns, sorting = {}, onSort, loading, pagination =
746
745
  return;
747
746
  onSort ? onSort(column) : doAutoSort(column);
748
747
  };
749
- return (jsxs("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: [jsx("div", { className: buildClassName('overflow-x-auto overflow-y-hidden rounded-lg border border-gray-200 dark:border-gray-800', wrapperClass, pagination && 'rounded-b-none border-b-0'), children: jsxs(Table, { className: "relative w-full max-w-full h-fit", layout: layout, children: [jsx(TableHead, { children: columns.map((column) => (jsx(TableHeaderCell, { align: column.headerAlign, style: { width: column.width || 'auto' }, className: buildClassName('bg-gray-50 dark:bg-gray-800', column.sticky === 'left' &&
748
+ const getKey = (item, idx) => {
749
+ var _a;
750
+ if (typeof rowKey === 'function')
751
+ return rowKey(item);
752
+ return (_a = item[rowKey]) !== null && _a !== void 0 ? _a : idx;
753
+ };
754
+ const getRowClass = (item, idx) => {
755
+ if (!rowClass)
756
+ return '';
757
+ if (typeof rowClass === 'function')
758
+ return rowClass(item, idx);
759
+ return rowClass;
760
+ };
761
+ const getCellClass = (column, item) => {
762
+ if (!column.cellClass)
763
+ return '';
764
+ if (typeof column.cellClass === 'function')
765
+ return column.cellClass(item);
766
+ return column.cellClass;
767
+ };
768
+ const densityCellClass = DENSITY_CELL_CLASS$2[density];
769
+ return (jsxs("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: [jsx("div", { className: buildClassName('overflow-x-auto overflow-y-hidden rounded-lg border border-gray-200 dark:border-gray-800', wrapperClass, pagination && 'rounded-b-none border-b-0'), children: jsxs(Table, { className: buildClassName('relative w-full max-w-full h-fit', tableClass), layout: layout, children: [jsx(TableHead, { className: headClass, children: columns.map((column) => (jsx(TableHeaderCell, { align: column.headerAlign, style: { width: column.width || 'auto' }, className: buildClassName('bg-gray-50 dark:bg-gray-800', densityCellClass, column.sticky === 'left' &&
750
770
  'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
751
- 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: jsxs(TextContent, { role: column.sortable ? 'button' : undefined, className: buildClassName('group', column.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(column), children: [jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && sortedItems.length === 0 ? (jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (sortedItems.map((item) => (jsx(TableRow, { className: "group", children: columns.map((column) => {
771
+ 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', column.headerClass), children: jsxs(TextContent, { role: column.sortable ? 'button' : undefined, className: buildClassName('group', column.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(column), children: [jsx(TextContent, { className: "shrink-0", children: column.label }), column.sortable ? getSortIcon(sorting[column.name]) : null] }) }, column.name))) }), jsx(TableBody, { loading: loading, colSize: columns.length, rowSize: (pagination === null || pagination === void 0 ? void 0 : pagination.limit) || 5, children: !loading && sortedItems.length === 0 ? (jsx(EmptyTableRow, { colSpan: columns.length, children: emptyMessage })) : (sortedItems.map((item, idx) => (jsx(TableRow, { className: buildClassName('group', onRowClick && 'cursor-pointer', striped && idx % 2 === 1 && 'bg-gray-50 dark:bg-gray-800/40', getRowClass(item, idx)), onClick: onRowClick ? () => onRowClick(item, idx) : undefined, children: columns.map((column) => {
752
772
  var _a;
753
- return (jsx(TableCell, { align: column.align, className: buildClassName(column.sticky === 'left' &&
773
+ return (jsx(TableCell, { align: column.align, className: buildClassName(densityCellClass, striped && idx % 2 === 1 && 'bg-gray-50 dark:bg-gray-800/40', column.sticky === 'left' &&
754
774
  'sticky left-0 z-10 shadow-[2px_0_6px_rgba(0,0,0,0.06)]', column.sticky === 'right' &&
755
- 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]'), children: column.render
775
+ 'sticky right-0 z-10 shadow-[-2px_0_6px_rgba(0,0,0,0.06)]', getCellClass(column, item)), children: column.render
756
776
  ? column.render(item)
757
777
  : ((_a = get(item, column.name)) !== null && _a !== void 0 ? _a : 'Not set') }, column.name));
758
- }) }, item.id)))) })] }) }), pagination && (jsx(Pagination, { ...pagination, className: "rounded-b-lg border border-t-0 border-gray-200 dark:border-gray-800", onChange: setPagination }))] }));
759
- };
778
+ }) }, getKey(item, idx))))) }), footerRow && jsx(TableFoot, { children: footerRow })] }) }), pagination && (jsx(Pagination, { ...pagination, className: "rounded-b-lg border border-t-0 border-gray-200 dark:border-gray-800", onChange: setPagination }))] }));
779
+ }
760
780
  DataTable.displayName = 'DataTable';
761
781
 
762
782
  const Title = ({ children, className }) => (jsx("h1", { className: buildClassName('text-3xl font-bold', className), children: children }));
@@ -1428,33 +1448,61 @@ const ToastProvider = ({ children, placement = 'top-center' }) => {
1428
1448
  return (jsxs(ToastContext.Provider, { value: { showToast, closeToast }, children: [children, jsx("div", { className: buildClassName('fixed z-50 flex flex-col gap-3 pointer-events-none', placementClass[placement]), children: toasts.map((toast, index) => (jsx("div", { className: "pointer-events-auto", onMouseEnter: () => toast.pauseOnHover && clearTimer(toast.id), onMouseLeave: () => toast.pauseOnHover && scheduleClose(toast), children: jsx(Toast, { ...toast, isTop: placement.startsWith('top'), onClose: () => closeToast(toast.id) }) }, toast.id))) })] }));
1429
1449
  };
1430
1450
 
1431
- const VirtualizedRow = ({ index, style, data }) => {
1432
- const { items, columns, gridTemplate } = data;
1451
+ const DENSITY_CELL_CLASS$1 = {
1452
+ compact: 'px-2 py-1.5',
1453
+ default: 'px-3 py-3',
1454
+ spacious: 'px-4 py-4',
1455
+ };
1456
+ const VirtualizedRow = ({ index, style, data, }) => {
1457
+ const { items, columns, gridTemplate, onRowClick, rowClass, density = 'default', striped } = data;
1433
1458
  const item = items[index];
1434
- return (jsx("div", { role: "row", className: "grid border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 group", style: {
1459
+ const isStriped = striped && index % 2 === 1;
1460
+ const resolvedRowClass = !rowClass
1461
+ ? ''
1462
+ : typeof rowClass === 'function'
1463
+ ? rowClass(item, index)
1464
+ : rowClass;
1465
+ const getCellClass = (col) => {
1466
+ if (!col.cellClass)
1467
+ return '';
1468
+ if (typeof col.cellClass === 'function')
1469
+ return col.cellClass(item);
1470
+ return col.cellClass;
1471
+ };
1472
+ const densityCellClass = DENSITY_CELL_CLASS$1[density];
1473
+ return (jsx("div", { role: "row", className: buildClassName('grid border-b border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 group', onRowClick && 'cursor-pointer', isStriped && 'bg-gray-50 dark:bg-gray-800/40', resolvedRowClass), style: {
1435
1474
  ...style,
1436
1475
  display: 'grid',
1437
1476
  gridTemplateColumns: gridTemplate,
1438
1477
  minWidth: 'fit-content',
1439
- }, children: columns.map((col) => {
1478
+ }, onClick: onRowClick ? () => onRowClick(item, index) : undefined, children: columns.map((col) => {
1440
1479
  var _a;
1441
1480
  const content = col.render ? col.render(item) : ((_a = get(item, col.name)) !== null && _a !== void 0 ? _a : 'Not set');
1442
- return (jsx("div", { role: "cell", className: buildClassName('px-3 py-3 whitespace-nowrap border-r last:border-r-0 border-gray-200 dark:border-gray-700', col.align === 'center' && 'text-center', col.align === 'right' && 'text-right', col.sticky === 'left' &&
1481
+ return (jsx("div", { role: "cell", className: buildClassName('whitespace-nowrap border-r last:border-r-0 border-gray-200 dark:border-gray-700', densityCellClass, col.align === 'center' && 'text-center', col.align === 'right' && 'text-right', col.sticky === 'left' &&
1443
1482
  'sticky left-0 z-10 bg-white dark:bg-gray-900 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
1444
- 'sticky right-0 z-10 bg-white dark:bg-gray-900 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]'), children: content }, col.name));
1483
+ 'sticky right-0 z-10 bg-white dark:bg-gray-900 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]', isStriped && 'bg-gray-50 dark:bg-gray-800/40', getCellClass(col)), children: content }, col.name));
1445
1484
  }) }));
1446
1485
  };
1447
1486
 
1448
- /* -------------------------------------------------------
1449
- * Convert column definitions into CSS grid template
1450
- * ------------------------------------------------------- */
1451
- const useGridTemplate = (columns) => useMemo(() => columns.map((col) => (col.width ? `${col.width}px` : '1fr')).join(' '), [columns]);
1452
- const VirtualizedDataTable = ({ items, columns, sorting = {}, onSort, loading = false, emptyMessage = 'No data available', containerClass = '', wrapperClass = '', rowHeight = 48, maxHeight = 400, }) => {
1487
+ const DENSITY_CELL_CLASS = {
1488
+ compact: 'px-2 py-1.5',
1489
+ default: 'px-3 py-3',
1490
+ spacious: 'px-4 py-4',
1491
+ };
1492
+ const columnWidth = (col) => {
1493
+ if (!col.width)
1494
+ return '1fr';
1495
+ if (typeof col.width === 'number')
1496
+ return `${col.width}px`;
1497
+ return col.width;
1498
+ };
1499
+ function VirtualizedDataTable({ items, columns, sorting = {}, onSort, loading = false, emptyMessage = 'No data available', containerClass = '', wrapperClass = '', onRowClick, rowClass, density = 'default', striped = false, rowHeight = 48, maxHeight = 400, overscanCount = 3, }) {
1453
1500
  const scrollRef = useRef(null);
1454
1501
  const outerRef = useRef(null);
1455
1502
  const headerRef = useRef(null);
1456
- const gridTemplate = useGridTemplate(columns);
1457
- /** Sync horizontal scroll of the virtualized body → header */
1503
+ const gridTemplate = useMemo(() => columns.map((col) => columnWidth(col)).join(' '), [columns]);
1504
+ const densityCellClass = DENSITY_CELL_CLASS[density];
1505
+ const skeletonRows = Math.max(1, Math.floor(maxHeight / rowHeight));
1458
1506
  useEffect(() => {
1459
1507
  const el = outerRef.current;
1460
1508
  if (!el)
@@ -1470,35 +1518,31 @@ const VirtualizedDataTable = ({ items, columns, sorting = {}, onSort, loading =
1470
1518
  if (column.sortable)
1471
1519
  onSort === null || onSort === void 0 ? void 0 : onSort(column);
1472
1520
  }, [onSort]);
1521
+ const itemData = useMemo(() => ({ items, columns, gridTemplate, onRowClick, rowClass, density, striped }), [items, columns, gridTemplate, onRowClick, rowClass, density, striped]);
1473
1522
  /* -------------------------------------------------------
1474
- * RENDER: Header row (real DOM for accessibility)
1523
+ * Header
1475
1524
  * ------------------------------------------------------- */
1476
- const Header = (jsx("div", { ref: headerRef, className: "overflow-hidden w-full", children: jsx("div", { className: "grid bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", style: {
1477
- gridTemplateColumns: gridTemplate,
1478
- minWidth: 'fit-content',
1479
- }, children: columns.map((col) => (jsx("div", { role: "columnheader", className: buildClassName('px-3 py-3 font-semibold text-sm whitespace-nowrap flex items-center', 'border-r last:border-r-0 border-gray-200 dark:border-gray-700', col.sticky === 'left' &&
1525
+ const Header = (jsx("div", { ref: headerRef, className: "overflow-hidden w-full", children: jsx("div", { className: "grid bg-gray-50 dark:bg-gray-800 border-b border-gray-200 dark:border-gray-700", style: { gridTemplateColumns: gridTemplate, minWidth: 'fit-content' }, children: columns.map((col) => (jsx("div", { role: "columnheader", className: buildClassName('font-semibold text-sm whitespace-nowrap flex items-center', densityCellClass, 'border-r last:border-r-0 border-gray-200 dark:border-gray-700', col.sticky === 'left' &&
1480
1526
  'sticky left-0 z-20 bg-gray-50 dark:bg-gray-800 shadow-[2px_0_4px_rgba(0,0,0,0.05)]', col.sticky === 'right' &&
1481
- 'sticky right-0 z-20 bg-gray-50 dark:bg-gray-800 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]'), children: jsxs(TextContent, { role: col.sortable ? 'button' : undefined, className: buildClassName(col.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(col), children: [col.label, col.sortable ? getSortIcon(sorting[col.name]) : null] }) }, col.name))) }) }));
1527
+ 'sticky right-0 z-20 bg-gray-50 dark:bg-gray-800 shadow-[-2px_0_4px_rgba(0,0,0,0.05)]', col.headerClass), children: jsxs(TextContent, { role: col.sortable ? 'button' : undefined, className: buildClassName(col.sortable && 'inline-flex items-center gap-2 cursor-pointer select-none'), onClick: () => handleSort(col), children: [col.label, col.sortable ? getSortIcon(sorting[col.name]) : null] }) }, col.name))) }) }));
1528
+ const wrapperCls = buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass);
1482
1529
  /* -------------------------------------------------------
1483
- * LOADING STATE (non-virtualized placeholder)
1530
+ * Loading state
1484
1531
  * ------------------------------------------------------- */
1485
1532
  if (loading) {
1486
- return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsx("div", { style: { height: maxHeight }, className: "flex flex-col", children: [...Array(6)].map((_, idx) => (jsx("div", { "data-testid": "skeleton-row", className: "grid animate-pulse bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800", style: {
1487
- gridTemplateColumns: gridTemplate,
1488
- height: rowHeight,
1489
- }, children: columns.map((col) => (jsx("div", { className: "px-3 py-3", children: jsx("div", { className: "h-4 w-3/4 bg-gray-300 dark:bg-gray-700 rounded" }) }, col.name))) }, idx))) })] }) }));
1533
+ return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: wrapperCls, children: [Header, jsx("div", { style: { height: maxHeight }, className: "flex flex-col", children: Array.from({ length: skeletonRows }).map((_, idx) => (jsx("div", { "data-testid": "skeleton-row", className: "grid animate-pulse bg-white dark:bg-gray-900 border-b border-gray-100 dark:border-gray-800", style: { gridTemplateColumns: gridTemplate, height: rowHeight }, children: columns.map((col) => (jsx("div", { className: densityCellClass, children: jsx("div", { className: "h-4 w-3/4 bg-gray-300 dark:bg-gray-700 rounded" }) }, col.name))) }, idx))) })] }) }));
1490
1534
  }
1491
1535
  /* -------------------------------------------------------
1492
- * EMPTY STATE (non-virtualized → single row)
1536
+ * Empty state
1493
1537
  * ------------------------------------------------------- */
1494
- if (!loading && items.length === 0) {
1495
- return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsx("div", { className: "flex items-center justify-center text-gray-500 dark:text-gray-300", style: { height: maxHeight }, children: emptyMessage })] }) }));
1538
+ if (items.length === 0) {
1539
+ return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: wrapperCls, children: [Header, jsx("div", { className: "flex items-center justify-center text-gray-500 dark:text-gray-300", style: { height: maxHeight }, children: emptyMessage })] }) }));
1496
1540
  }
1497
1541
  /* -------------------------------------------------------
1498
- * MAIN (virtualized body)
1542
+ * Virtualized body
1499
1543
  * ------------------------------------------------------- */
1500
- return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: buildClassName('rounded-lg border border-gray-200 dark:border-gray-800 overflow-hidden', wrapperClass), children: [Header, jsx(FixedSizeList, { ref: scrollRef, outerRef: outerRef, height: maxHeight, width: "100%", itemCount: items.length, itemSize: rowHeight, itemData: { items, columns, gridTemplate }, children: VirtualizedRow })] }) }));
1501
- };
1544
+ return (jsx("div", { className: buildClassName('w-full rounded-lg relative', containerClass), children: jsxs("div", { className: wrapperCls, children: [Header, jsx(FixedSizeList, { ref: scrollRef, outerRef: outerRef, height: maxHeight, width: "100%", itemCount: items.length, itemSize: rowHeight, itemData: itemData, overscanCount: overscanCount, children: VirtualizedRow })] }) }));
1545
+ }
1502
1546
 
1503
1547
  const useIsMobile = () => {
1504
1548
  const [isMobile, setIsMobile] = useState(false);