tw-react-components 0.0.135 → 0.0.137

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/index.esm.js CHANGED
@@ -1,10 +1,11 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
+ import * as React from 'react';
2
3
  import { forwardRef, useMemo, useState, useEffect, useId, useCallback, useRef, createContext, useContext } from 'react';
3
4
  import { clsx } from 'clsx';
4
5
  import { twMerge } from 'tailwind-merge';
5
6
  import dayjs from 'dayjs';
6
7
  import advancedFormat from 'dayjs/plugin/advancedFormat';
7
- import { HelpCircle, XIcon, AtSignIcon, EyeIcon, EyeOffIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronDownIcon, CalendarIcon, ClockIcon, CheckIcon, CircleIcon, ChevronsLeftIcon, ChevronsRightIcon, ChevronsDownUpIcon, ChevronsUpDownIcon, ArrowUpDownIcon, SortAscIcon, SortDescIcon, MinusIcon, PlusIcon, MenuIcon, MoonIcon, SunIcon } from 'lucide-react';
8
+ import { HelpCircle, XIcon, AtSignIcon, EyeIcon, EyeOffIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronDownIcon, CalendarIcon, ClockIcon, CheckIcon, CircleIcon, CloudUploadIcon, ChevronsLeftIcon, ChevronsRightIcon, ChevronsDownUpIcon, ChevronsUpDownIcon, ArrowUpDownIcon, SortAscIcon, SortDescIcon, MinusIcon, PlusIcon, X, PanelLeft, MoonIcon, SunIcon } from 'lucide-react';
8
9
  import localeData from 'dayjs/plugin/localeData';
9
10
  import * as TooltipPrimitive from '@radix-ui/react-tooltip';
10
11
  import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
@@ -14,8 +15,10 @@ import { useSensors, useSensor, PointerSensor, KeyboardSensor, DndContext, close
14
15
  import { restrictToFirstScrollableAncestor } from '@dnd-kit/modifiers';
15
16
  import { sortableKeyboardCoordinates, SortableContext, verticalListSortingStrategy, useSortable } from '@dnd-kit/sortable';
16
17
  import { CSS } from '@dnd-kit/utilities';
17
- import * as Accordion from '@radix-ui/react-accordion';
18
18
  import { Link, useLocation } from 'react-router-dom';
19
+ import { Slot } from '@radix-ui/react-slot';
20
+ import { cva } from 'class-variance-authority';
21
+ import * as SeparatorPrimitive from '@radix-ui/react-separator';
19
22
  import * as PopoverPrimitive from '@radix-ui/react-popover';
20
23
  import * as SwitchPrimitives from '@radix-ui/react-switch';
21
24
  import * as TabsPrimitive from '@radix-ui/react-tabs';
@@ -616,6 +619,21 @@ function useDays(locale = 'en') {
616
619
  }, [locale]);
617
620
  }
618
621
 
622
+ const MOBILE_BREAKPOINT = 768;
623
+ function useIsMobile() {
624
+ const [isMobile, setIsMobile] = useState(undefined);
625
+ useEffect(() => {
626
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
627
+ const onChange = () => {
628
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
629
+ };
630
+ mql.addEventListener('change', onChange);
631
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
632
+ return () => mql.removeEventListener('change', onChange);
633
+ }, []);
634
+ return !!isMobile;
635
+ }
636
+
619
637
  function useLongPress(callback, ms = 100) {
620
638
  const [startLongPress, setStartLongPress] = useState(false);
621
639
  useEffect(() => {
@@ -745,7 +763,7 @@ const Label = ({ children, className, description, required, hasErrors, htmlFor,
745
763
  return !children ? null : (jsxs("label", { className: cn('flex items-center gap-1 font-medium', {
746
764
  'text-slate-700 dark:text-slate-100': !hasErrors,
747
765
  'text-red-600 dark:text-red-500': hasErrors,
748
- }, className), htmlFor: htmlFor, children: [jsxs("span", { children: [children, " ", required && jsx("span", { className: "text-red-600", children: "*" })] }), description && (jsx(Tooltip, { content: jsx("div", { className: "max-w-xs", children: description }), placement: "right", children: jsx(HelpCircle, { className: "h-5 w-5" }) }))] }));
766
+ }, className), htmlFor: htmlFor, children: [children, description && (jsx(Tooltip, { content: jsx("div", { className: "max-w-xs", children: description }), placement: "top", asChild: true, children: jsx(HelpCircle, { className: "h-4 w-4" }) })), required && jsx("span", { className: "text-red-600", children: "*" })] }));
749
767
  };
750
768
 
751
769
  const inputClasses = {
@@ -837,7 +855,12 @@ const CheckboxInput = forwardRef((props, ref) => (jsx(BasicInput, Object.assign(
837
855
 
838
856
  const EmailInput = forwardRef((props, ref) => (jsx(BasicInput, Object.assign({ type: "email" }, props, { suffixIcon: AtSignIcon, ref: ref }))));
839
857
 
840
- const NumberInput = forwardRef((props, ref) => (jsx(BasicInput, Object.assign({ type: "number" }, props, { ref: ref }))));
858
+ const NumberInput = forwardRef((_a, ref) => {
859
+ var { unit } = _a, props = __rest(_a, ["unit"]);
860
+ return (jsx(BasicInput, Object.assign({ type: "number" }, props, { suffixIcon: unit
861
+ ? ({ className }) => (jsx("div", { className: cn(className, 'flex w-min items-center'), onClick: props.onSuffixIconClick, children: unit }))
862
+ : props.suffixIcon, ref: ref })));
863
+ });
841
864
 
842
865
  const PasswordInput = forwardRef((props, ref) => {
843
866
  const [type, setType] = useState('password');
@@ -1092,7 +1115,7 @@ const DateTimeInput = forwardRef((_a, ref) => {
1092
1115
  setIsOpen(false);
1093
1116
  }
1094
1117
  };
1095
- return (jsxs("div", { className: cn('relative w-full', className), ref: ref, children: [jsx(BasicInput, Object.assign({}, props, { type: "text", readOnly: true, value: displayDate !== null && displayDate !== void 0 ? displayDate : '', hasErrors: hasErrors, onClick: handleOnClick, onKeyUp: handleOnKeyUp, clearable: clearable && !!displayDate, onClear: clearDate, suffixIcon: (type === null || type === void 0 ? void 0 : type.includes('date')) ? CalendarIcon : ClockIcon })), isOpen && (jsxs("div", { className: "absolute z-20 mt-2 flex origin-top-left flex-col rounded-md border bg-white shadow duration-200 dark:border-slate-700 dark:bg-slate-900 dark:text-white", tabIndex: 0, onBlur: handleOnBlur, ref: calendarRef, children: [(type === null || type === void 0 ? void 0 : type.includes('date')) && (jsx(DateSelector, { date: date, value: value, minDate: minDate, maxDate: maxDate, locale: displayLocale, calendarView: calendarView, setCalendarView: setCalendarView, setNewDate: setNewDate })), calendarView === 'days' && (jsxs("div", { className: "flex select-none items-center justify-end gap-2 px-3 py-2", children: [(type === null || type === void 0 ? void 0 : type.includes('time')) && (jsx(TimeSelector, { date: date, step: step, minDate: minDate, maxDate: maxDate, setNewDate: setNewDate })), jsx("div", { className: "cursor-pointer rounded-lg border border-transparent p-1 text-sm font-bold uppercase text-blue-600 transition duration-100 ease-in-out hover:bg-slate-100 dark:text-blue-500 dark:hover:bg-slate-700", onClick: () => setIsOpen(false), children: "OK" })] }))] }))] }));
1118
+ return (jsxs("div", { className: cn('relative w-full', className), ref: ref, children: [jsx(BasicInput, Object.assign({}, props, { type: "text", readOnly: true, value: displayDate !== null && displayDate !== void 0 ? displayDate : '', hasErrors: hasErrors, onClick: handleOnClick, onKeyUp: handleOnKeyUp, clearable: clearable && !!displayDate, onClear: clearDate, suffixIcon: (type === null || type === void 0 ? void 0 : type.includes('date')) ? CalendarIcon : ClockIcon, onSuffixIconClick: handleOnClick })), isOpen && (jsxs("div", { className: "absolute z-20 mt-2 flex origin-top-left flex-col rounded-md border bg-white shadow duration-200 dark:border-slate-700 dark:bg-slate-900 dark:text-white", tabIndex: 0, onBlur: handleOnBlur, ref: calendarRef, children: [(type === null || type === void 0 ? void 0 : type.includes('date')) && (jsx(DateSelector, { date: date, value: value, minDate: minDate, maxDate: maxDate, locale: displayLocale, calendarView: calendarView, setCalendarView: setCalendarView, setNewDate: setNewDate })), calendarView === 'days' && (jsxs("div", { className: "flex select-none items-center justify-end gap-2 px-3 py-2", children: [(type === null || type === void 0 ? void 0 : type.includes('time')) && (jsx(TimeSelector, { date: date, step: step, minDate: minDate, maxDate: maxDate, setNewDate: setNewDate })), jsx("div", { className: "cursor-pointer rounded-lg border border-transparent p-1 text-sm font-bold uppercase text-blue-600 transition duration-100 ease-in-out hover:bg-slate-100 dark:text-blue-500 dark:hover:bg-slate-700", onClick: () => setIsOpen(false), children: "OK" })] }))] }))] }));
1096
1119
  });
1097
1120
 
1098
1121
  const ListContent = forwardRef((_a, ref) => {
@@ -1273,16 +1296,31 @@ const SelectInput = forwardRef((_a, ref) => {
1273
1296
  handleOnSelect(option.id);
1274
1297
  }, children: jsx("span", { children: renderItem(option, !!selectedMap[option.id]) }) }));
1275
1298
  }, [ItemComponent, handleOnSelect, multiple, renderItem, selectedMap]);
1276
- return (jsxs(DropdownMenu, { open: open, onOpenChange: setOpen, children: [jsx(DropdownMenu.Trigger, { className: cn('w-full', className), children: jsx(TextInput, Object.assign({ className: "[&>div>*]:cursor-pointer", inputClassName: "text-left" }, props, { value: text !== null && text !== void 0 ? text : '', clearable: clearable && !!selectedItems.length, onClear: handleOnClear, suffixIcon: ChevronDownIcon, ref: ref, readOnly: true })) }), jsxs(DropdownMenu.Content, { className: "flex max-h-80 w-[calc(var(--radix-popper-anchor-width))] flex-col overflow-hidden", children: [search && (jsxs(Fragment, { children: [jsx(TextInput, { value: searchValue, placeholder: "Search...", size: props.size, onChange: handleOnSearchValueChange, clearable: !!searchValue.length, onClear: clearSearchValue }), jsx(DropdownMenu.Separator, { className: "w-full" })] })), filteredItems.length === 0 &&
1299
+ return (jsxs(DropdownMenu, { open: open, onOpenChange: setOpen, children: [jsx(DropdownMenu.Trigger, { className: cn('w-full', className), children: jsx(TextInput, Object.assign({ className: "[&>div>*]:cursor-pointer", inputClassName: "text-left" }, props, { value: text !== null && text !== void 0 ? text : '', clearable: clearable && !!selectedItems.length, onClear: handleOnClear, suffixIcon: ChevronDownIcon, onSuffixIconClick: () => setOpen((open) => !open), ref: ref, readOnly: true })) }), jsxs(DropdownMenu.Content, { className: "flex max-h-80 w-[calc(var(--radix-popper-anchor-width))] flex-col overflow-hidden", children: [search && (jsxs(Fragment, { children: [jsx(TextInput, { value: searchValue, placeholder: "Search...", size: props.size, onChange: handleOnSearchValueChange, clearable: !!searchValue.length, onClear: clearSearchValue }), jsx(DropdownMenu.Separator, { className: "w-full" })] })), filteredItems.length === 0 &&
1277
1300
  (allowAddition && searchValue ? (jsxs("button", { className: "rounded bg-slate-100 text-center hover:bg-slate-200 dark:bg-slate-900/30 dark:hover:bg-slate-700/30", onClick: handleOnAddItemClicked, children: ["Add '", searchValue, "'"] })) : (jsx("div", { className: "text-center text-slate-500", children: "No items." }))), jsx(GroupComponent, { className: "flex flex-col gap-1 overflow-auto", value: !multiple && selectedItems.length ? String(selectedItems[0].id) : undefined, children: filteredItems.map((item, index) => item.group ? (jsxs(Flex, { className: "gap-1", direction: "column", fullWidth: true, children: [jsx(DropdownMenu.Label, { className: "sticky top-0 z-[51] w-full rounded-md border bg-white py-1 dark:bg-slate-900", children: item.label }), item.items.map((subItem) => (jsx(RenderOption, Object.assign({}, subItem), subItem.id))), index < filteredItems.length - 1 && (jsx("div", { className: "mb-1 h-px w-full bg-slate-200 dark:bg-slate-700" }))] }, item.id)) : (jsx(RenderOption, Object.assign({}, item), item.id))) })] })] }));
1278
1301
  });
1279
1302
 
1303
+ const FileInput = forwardRef((_a, ref) => {
1304
+ var { className, value, onChange, onFileChange, accept } = _a, props = __rest(_a, ["className", "value", "onChange", "onFileChange", "accept"]);
1305
+ const fileInputRef = useRef(null);
1306
+ const handleFileChange = (_a) => __awaiter(void 0, [_a], void 0, function* ({ target: { files } }) {
1307
+ console.log(files);
1308
+ if (files && files.length > 0) {
1309
+ const file = files[0];
1310
+ console.log(file, file.name, onChange, onFileChange);
1311
+ onChange === null || onChange === void 0 ? void 0 : onChange(file.name);
1312
+ onFileChange === null || onFileChange === void 0 ? void 0 : onFileChange(file);
1313
+ }
1314
+ });
1315
+ return (jsxs(Fragment, { children: [jsx(TextInput, Object.assign({ className: cn('[&>div>*]:cursor-pointer', className), inputClassName: "text-left" }, props, { value: value !== null && value !== void 0 ? value : '', onClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, suffixIcon: CloudUploadIcon, onSuffixIconClick: () => { var _a; return (_a = fileInputRef.current) === null || _a === void 0 ? void 0 : _a.click(); }, ref: ref, readOnly: true })), jsx("input", { ref: (ref) => (fileInputRef.current = ref), type: "file", hidden: true, accept: accept, onChange: handleFileChange })] }));
1316
+ });
1317
+
1280
1318
  const FormGroup = ({ className, label, children }) => (jsxs(Flex, { className: cn('relative !gap-4 rounded-lg border p-4 dark:border-slate-700', className), direction: "column", fullWidth: true, children: [jsx("div", { className: "absolute right-0 top-0 rounded-bl-lg rounded-tr-lg bg-slate-500 px-2 py-1 font-medium text-white dark:bg-slate-900 dark:text-white", children: label }), children] }));
1281
1319
 
1282
1320
  function withForm(Component) {
1283
1321
  return forwardRef((props, ref) => {
1284
1322
  const _a = props, { name, pattern, validate } = _a, restProps = __rest(_a, ["name", "pattern", "validate"]);
1285
- const { control } = useFormContext();
1323
+ const { control, formState } = useFormContext();
1286
1324
  return (jsx(Controller, { name: name, control: control, rules: {
1287
1325
  required: restProps.required,
1288
1326
  min: restProps.min,
@@ -1293,7 +1331,8 @@ function withForm(Component) {
1293
1331
  validate,
1294
1332
  }, render: ({ field, fieldState }) => {
1295
1333
  var _a, _b;
1296
- return (jsx(Component, Object.assign({}, restProps, field, { value: (_a = field.value) !== null && _a !== void 0 ? _a : '', disabled: (_b = field.disabled) !== null && _b !== void 0 ? _b : restProps.disabled, hasErrors: fieldState.error, ref: mergeRefs([ref, field.ref]) })));
1334
+ return (jsx(Component, Object.assign({}, restProps, field, { value: (_a = field.value) !== null && _a !== void 0 ? _a : '', disabled: ((_b = field.disabled) !== null && _b !== void 0 ? _b : restProps.disabled) ||
1335
+ formState.isSubmitting, hasErrors: fieldState.error, ref: mergeRefs([ref, field.ref]) })));
1297
1336
  } }));
1298
1337
  });
1299
1338
  }
@@ -1306,6 +1345,7 @@ const FormInputs = {
1306
1345
  Checkbox: withForm(CheckboxInput),
1307
1346
  DateTime: withForm(DateTimeInput),
1308
1347
  Select: withForm(SelectInput),
1348
+ File: withForm(FileInput),
1309
1349
  };
1310
1350
 
1311
1351
  const HintRoot = forwardRef(({ children }, ref) => (jsx(Block, { className: "relative", ref: ref, children: children })));
@@ -1503,7 +1543,7 @@ function DataTable({ className, columns, rows, sorting, pagination, actions = []
1503
1543
  : undefined, children: [column.header, sorting &&
1504
1544
  !column.noSorting &&
1505
1545
  (((_b = sorting.sorting) === null || _b === void 0 ? void 0 : _b.field) !== column.field ? (jsx(ArrowUpDownIcon, { className: "absolute top-1/2 float-right ml-1 hidden h-4 w-4 -translate-y-1/2 group-hover:inline-block" })) : ((_c = sorting.sorting) === null || _c === void 0 ? void 0 : _c.direction) === 'asc' ? (jsx(SortAscIcon, { className: "absolute top-1/2 float-right ml-1 inline-block h-4 w-4 -translate-y-1/2" })) : (jsx(SortDescIcon, { className: "absolute top-1/2 float-right ml-1 inline-block h-4 w-4 -translate-y-1/2" })))] }, columnIndex));
1506
- }), actions.length > 0 && jsx(Table.HeadCell, { align: "center", children: "Actions" })] }) }), jsxs(Table.Body, { className: "relative", children: [isLoading && (jsx(Table.Row, { children: jsx(Table.Cell, { className: cn('z-10 h-full w-full p-0', {
1546
+ }), actions.filter((action) => !action.hide).length > 0 && (jsx(Table.HeadCell, { align: "center", children: "Actions" }))] }) }), jsxs(Table.Body, { className: "relative", children: [isLoading && (jsx(Table.Row, { children: jsx(Table.Cell, { className: cn('z-10 h-full w-full p-0', {
1507
1547
  absolute: rows.length,
1508
1548
  }), colSpan: columnsLength, children: jsx(Spinner, { className: "bg-white/50 py-4 dark:bg-slate-700/50" }) }) })), !isLoading && !rows.length && (jsx(Table.Row, { children: jsx(Table.Cell, { colSpan: columnsLength, children: jsx(Flex, { className: "text-slate-500", justify: "center", children: noDataMessage !== null && noDataMessage !== void 0 ? noDataMessage : 'No data' }) }) })), rows.map((item, rowIndex) => [
1509
1549
  jsxs(Table.Row, { className: cn({
@@ -1511,7 +1551,7 @@ function DataTable({ className, columns, rows, sorting, pagination, actions = []
1511
1551
  }, rowClassName === null || rowClassName === void 0 ? void 0 : rowClassName(item, rowIndex)), onClick: handleRowClicked(item, rowIndex), children: [rowExtraContent && (jsx(Table.Cell, { className: "w-min", align: "center", children: jsx(ExpandButton, { folded: !expandedRows[rowExtraContent.idGetter(item)], foldComponent: MinusIcon, unfoldComponent: PlusIcon, onClick: handleExpandRow(rowExtraContent.idGetter(item)) }) })), _columns.map((column, columnIndex) => {
1512
1552
  var _a, _b, _c;
1513
1553
  return (jsx(Table.Cell, { className: column.className, align: (_a = column.align) !== null && _a !== void 0 ? _a : 'left', children: (_c = (_b = column.render) === null || _b === void 0 ? void 0 : _b.call(column, item, rowIndex)) !== null && _c !== void 0 ? _c : defaultRender(item, column.field) }, columnIndex));
1514
- }), actions.length > 0 && (jsx(Table.Cell, { className: "py-3", children: jsx(Flex, { align: "center", justify: "center", children: actions
1554
+ }), actions.filter((action) => !action.hide).length > 0 && (jsx(Table.Cell, { className: "py-3", children: jsx(Flex, { align: "center", justify: "center", children: actions
1515
1555
  .filter((action) => { var _a; return typeof action.hide === 'boolean' ? !action.hide : !((_a = action.hide) === null || _a === void 0 ? void 0 : _a.call(action, item)); })
1516
1556
  .map((action, actionIndex) => {
1517
1557
  var _a;
@@ -1634,107 +1674,356 @@ const PdfViewerDialog = ({ open, title, url, data, onClose }) => {
1634
1674
  return !(url || data) ? null : (jsx(Dialog, { open: open, onOpenChange: (value) => !value && onClose(), children: jsxs(Dialog.Content, { className: "h-[90dvh] max-w-[90dvw]", children: [jsx(Dialog.Header, { children: title }), (url || data) && (jsx("embed", { className: "rounded-lg", src: url !== null && url !== void 0 ? url : `data:application/pdf;base64,${data}`, type: "application/pdf", width: "100%", height: "100%" }))] }) }));
1635
1675
  };
1636
1676
 
1637
- const LayoutContext = createContext(undefined);
1638
- const LayoutContextProvider = ({ children }) => {
1639
- const [theme, setTheme] = useState(getValueFromLocalStorage(THEME_KEY, 'light'));
1640
- const [sidebarOpen, _setSidebarOpen] = useState(getValueFromLocalStorage(SIDEBAR_KEY, true));
1641
- useEffect(() => {
1642
- if (theme) {
1643
- if (theme === 'dark') {
1644
- document.documentElement.classList.add('dark');
1645
- }
1646
- else {
1647
- document.documentElement.classList.remove('dark');
1648
- }
1649
- }
1650
- }, [theme]);
1651
- const toggleTheme = () => {
1652
- setTheme((theme) => {
1653
- const newValue = theme === 'dark' ? 'light' : 'dark';
1654
- window.localStorage.setItem(THEME_KEY, newValue);
1655
- return newValue;
1656
- });
1657
- };
1658
- const setSidebarOpen = (open) => _setSidebarOpen(() => {
1659
- window.localStorage.setItem(SIDEBAR_KEY, String(open));
1660
- return open;
1661
- });
1662
- return (jsx(LayoutContext.Provider, { value: { theme, toggleTheme, sidebarOpen, setSidebarOpen }, children: children }));
1677
+ const Separator = forwardRef((_a, ref) => {
1678
+ var { className, orientation = 'horizontal', decorative = true } = _a, props = __rest(_a, ["className", "orientation", "decorative"]);
1679
+ return (jsx(SeparatorPrimitive.Root, Object.assign({ ref: ref, decorative: decorative, orientation: orientation, className: cn('bg-border shrink-0', orientation === 'horizontal' ? 'h-[1px] w-full' : 'h-full w-[1px]', className) }, props)));
1680
+ });
1681
+ Separator.displayName = SeparatorPrimitive.Root.displayName;
1682
+
1683
+ const $Sheet = DialogPrimitive.Root;
1684
+ const SheetTrigger = DialogPrimitive.Trigger;
1685
+ const SheetClose = DialogPrimitive.Close;
1686
+ const SheetPortal = DialogPrimitive.Portal;
1687
+ const SheetOverlay = React.forwardRef((_a, ref) => {
1688
+ var { className } = _a, props = __rest(_a, ["className"]);
1689
+ return (jsx(DialogPrimitive.Overlay, Object.assign({ className: cn('data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80', className) }, props, { ref: ref })));
1690
+ });
1691
+ SheetOverlay.displayName = DialogPrimitive.Overlay.displayName;
1692
+ const sheetVariants = cva('fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500', {
1693
+ variants: {
1694
+ side: {
1695
+ top: 'inset-x-0 top-0 border-b data-[state=closed]:slide-out-to-top data-[state=open]:slide-in-from-top',
1696
+ bottom: 'inset-x-0 bottom-0 border-t data-[state=closed]:slide-out-to-bottom data-[state=open]:slide-in-from-bottom',
1697
+ left: 'inset-y-0 left-0 h-full w-3/4 border-r data-[state=closed]:slide-out-to-left data-[state=open]:slide-in-from-left sm:max-w-sm',
1698
+ right: 'inset-y-0 right-0 h-full w-3/4 border-l data-[state=closed]:slide-out-to-right data-[state=open]:slide-in-from-right sm:max-w-sm',
1699
+ },
1700
+ },
1701
+ defaultVariants: {
1702
+ side: 'right',
1703
+ },
1704
+ });
1705
+ const SheetContent = React.forwardRef((_a, ref) => {
1706
+ var { side = 'right', className, children } = _a, props = __rest(_a, ["side", "className", "children"]);
1707
+ return (jsxs(SheetPortal, { children: [jsx(SheetOverlay, {}), jsxs(DialogPrimitive.Content, Object.assign({ ref: ref, className: cn(sheetVariants({ side }), className) }, props, { children: [children, jsxs(DialogPrimitive.Close, { className: "ring-offset-background focus:ring-ring data-[state=open]:bg-secondary absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none", children: [jsx(X, { className: "h-4 w-4" }), jsx("span", { className: "sr-only", children: "Close" })] })] }))] }));
1708
+ });
1709
+ SheetContent.displayName = DialogPrimitive.Content.displayName;
1710
+ const SheetHeader = (_a) => {
1711
+ var { className } = _a, props = __rest(_a, ["className"]);
1712
+ return (jsx("div", Object.assign({ className: cn('flex flex-col space-y-2 text-center sm:text-left', className) }, props)));
1663
1713
  };
1664
- function useLayoutContext() {
1665
- const context = useContext(LayoutContext);
1714
+ SheetHeader.displayName = 'SheetHeader';
1715
+ const SheetFooter = (_a) => {
1716
+ var { className } = _a, props = __rest(_a, ["className"]);
1717
+ return (jsx("div", Object.assign({ className: cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className) }, props)));
1718
+ };
1719
+ SheetFooter.displayName = 'SheetFooter';
1720
+ const SheetTitle = React.forwardRef((_a, ref) => {
1721
+ var { className } = _a, props = __rest(_a, ["className"]);
1722
+ return (jsx(DialogPrimitive.Title, Object.assign({ ref: ref, className: cn('text-foreground text-lg font-semibold', className) }, props)));
1723
+ });
1724
+ SheetTitle.displayName = DialogPrimitive.Title.displayName;
1725
+ const SheetDescription = React.forwardRef((_a, ref) => {
1726
+ var { className } = _a, props = __rest(_a, ["className"]);
1727
+ return (jsx(DialogPrimitive.Description, Object.assign({ ref: ref, className: cn('text-muted-foreground text-sm', className) }, props)));
1728
+ });
1729
+ SheetDescription.displayName = DialogPrimitive.Description.displayName;
1730
+ const Sheet = Object.assign($Sheet, {
1731
+ Portal: SheetPortal,
1732
+ Overlay: SheetOverlay,
1733
+ Trigger: SheetTrigger,
1734
+ Close: SheetClose,
1735
+ Content: SheetContent,
1736
+ Header: SheetHeader,
1737
+ Footer: SheetFooter,
1738
+ Title: SheetTitle,
1739
+ Description: SheetDescription,
1740
+ });
1741
+
1742
+ const Skeleton = (_a) => {
1743
+ var { className } = _a, props = __rest(_a, ["className"]);
1744
+ return (jsx("div", Object.assign({ className: cn('bg-muted animate-pulse rounded-md', className) }, props)));
1745
+ };
1746
+ Skeleton.displayName = 'Skeleton';
1747
+
1748
+ const SIDEBAR_COOKIE_NAME = 'sidebar:state';
1749
+ const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
1750
+ const SIDEBAR_WIDTH = '16rem';
1751
+ const SIDEBAR_WIDTH_MOBILE = '18rem';
1752
+ const SIDEBAR_WIDTH_ICON = '3rem';
1753
+ const SIDEBAR_KEYBOARD_SHORTCUT = 'b';
1754
+ const SidebarContext = createContext(null);
1755
+ function useSidebar() {
1756
+ const context = useContext(SidebarContext);
1666
1757
  if (!context) {
1667
- throw new Error('Please use LayoutContextProvider!');
1758
+ throw new Error('useSidebar must be used within a SidebarProvider.');
1668
1759
  }
1669
1760
  return context;
1670
1761
  }
1671
- const THEME_KEY = 'tw-react-components__theme';
1672
- const SIDEBAR_KEY = 'tw-react-components__sidebar';
1673
- function getValueFromLocalStorage(key, _default) {
1674
- var _a;
1675
- const transformers = {
1676
- string: String,
1677
- boolean: (value) => value === 'true',
1678
- };
1679
- return typeof window !== 'undefined'
1680
- ? transformers[typeof _default]((_a = window.localStorage.getItem(key)) !== null && _a !== void 0 ? _a : _default)
1681
- : _default;
1682
- }
1762
+ const SidebarContextProvider = forwardRef((_a, ref) => {
1763
+ var { defaultOpen = true, open: openProp, onOpenChange: setOpenProp, className, style, children } = _a, props = __rest(_a, ["defaultOpen", "open", "onOpenChange", "className", "style", "children"]);
1764
+ const isMobile = useIsMobile();
1765
+ const [openMobile, setOpenMobile] = useState(false);
1766
+ const screenRef = useRef(document.documentElement);
1767
+ // This is the internal state of the sidebar.
1768
+ // We use openProp and setOpenProp for control from outside the component.
1769
+ const [_open, _setOpen] = useState(defaultOpen);
1770
+ const open = openProp !== null && openProp !== void 0 ? openProp : _open;
1771
+ const setOpen = useCallback((value) => {
1772
+ if (setOpenProp) {
1773
+ return setOpenProp === null || setOpenProp === void 0 ? void 0 : setOpenProp(typeof value === 'function' ? value(open) : value);
1774
+ }
1775
+ _setOpen(value);
1776
+ // This sets the cookie to keep the sidebar state.
1777
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${open}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
1778
+ }, [setOpenProp, open]);
1779
+ // Helper to toggle the sidebar.
1780
+ const toggleSidebar = useCallback(() => {
1781
+ return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
1782
+ }, [isMobile, setOpen, setOpenMobile]);
1783
+ // Add swipe gesture support for opening and closing the sidebar.
1784
+ useOnSwipe(screenRef, (direction) => direction === 'right' ? setOpen(true) : direction === 'left' && setOpen(false));
1785
+ // Adds a keyboard shortcut to toggle the sidebar.
1786
+ useEffect(() => {
1787
+ const handleKeyDown = (event) => {
1788
+ if (event.key === SIDEBAR_KEYBOARD_SHORTCUT && (event.metaKey || event.ctrlKey)) {
1789
+ event.preventDefault();
1790
+ toggleSidebar();
1791
+ }
1792
+ };
1793
+ window.addEventListener('keydown', handleKeyDown);
1794
+ return () => window.removeEventListener('keydown', handleKeyDown);
1795
+ }, [toggleSidebar]);
1796
+ // We add a state so that we can do data-state="expanded" or "collapsed".
1797
+ // This makes it easier to style the sidebar with Tailwind classes.
1798
+ const state = open ? 'expanded' : 'collapsed';
1799
+ const contextValue = useMemo(() => ({
1800
+ state,
1801
+ open,
1802
+ setOpen,
1803
+ isMobile,
1804
+ openMobile,
1805
+ setOpenMobile,
1806
+ toggleSidebar,
1807
+ }), [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]);
1808
+ return (jsx(SidebarContext.Provider, { value: contextValue, children: jsx("div", Object.assign({ style: Object.assign({ '--sidebar-width': SIDEBAR_WIDTH, '--sidebar-width-icon': SIDEBAR_WIDTH_ICON }, style), className: cn('group/sidebar-wrapper has-[[data-variant=inset]]:bg-sidebar flex min-h-svh w-full', className), ref: ref }, props, { children: children })) }));
1809
+ });
1810
+ SidebarContextProvider.displayName = 'SidebarContextProvider';
1811
+ const $Sidebar = forwardRef((_a, ref) => {
1812
+ var { side = 'left', variant = 'sidebar', collapsible = 'offcanvas', className, children } = _a, props = __rest(_a, ["side", "variant", "collapsible", "className", "children"]);
1813
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
1814
+ if (collapsible === 'none') {
1815
+ return (jsx("div", Object.assign({ className: cn('bg-sidebar text-sidebar-foreground flex h-full w-[--sidebar-width] flex-col', className), ref: ref }, props, { children: children })));
1816
+ }
1817
+ if (isMobile) {
1818
+ return (jsx(Sheet, Object.assign({ open: openMobile, onOpenChange: setOpenMobile }, props, { children: jsx(Sheet.Content, { "data-sidebar": "sidebar", "data-mobile": "true", className: "bg-sidebar text-sidebar-foreground w-[--sidebar-width] p-0 [&>button]:hidden", style: {
1819
+ '--sidebar-width': SIDEBAR_WIDTH_MOBILE,
1820
+ }, side: side, children: jsx("div", { className: "flex h-full w-full flex-col", children: children }) }) })));
1821
+ }
1822
+ return (jsxs("div", { ref: ref, className: "text-sidebar-foreground group peer hidden md:block", "data-state": state, "data-collapsible": state === 'collapsed' ? collapsible : '', "data-variant": variant, "data-side": side, children: [jsx("div", { className: cn('relative h-svh w-[--sidebar-width] bg-transparent transition-[width] duration-200 ease-linear', 'group-data-[collapsible=offcanvas]:w-0', 'group-data-[side=right]:rotate-180', variant === 'floating' || variant === 'inset'
1823
+ ? 'group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]'
1824
+ : 'group-data-[collapsible=icon]:w-[--sidebar-width-icon]') }), jsx("div", Object.assign({ className: cn('fixed inset-y-0 z-10 hidden h-svh w-[--sidebar-width] transition-[left,right,width] duration-200 ease-linear md:flex', side === 'left'
1825
+ ? 'left-0 group-data-[collapsible=offcanvas]:left-[calc(var(--sidebar-width)*-1)]'
1826
+ : 'right-0 group-data-[collapsible=offcanvas]:right-[calc(var(--sidebar-width)*-1)]',
1827
+ // Adjust the padding for floating and inset variants.
1828
+ variant === 'floating' || variant === 'inset'
1829
+ ? 'p-2 group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4)_+2px)]'
1830
+ : 'border-sidebar-border group-data-[collapsible=icon]:w-[--sidebar-width-icon] group-data-[side=left]:border-r group-data-[side=right]:border-l', className) }, props, { children: jsx("div", { "data-sidebar": "sidebar", className: "bg-sidebar group-data-[variant=floating]:border-sidebar-border flex h-full w-full flex-col group-data-[variant=floating]:rounded-lg group-data-[variant=floating]:border group-data-[variant=floating]:shadow", children: children }) }))] }));
1831
+ });
1832
+ $Sidebar.displayName = 'Sidebar';
1833
+ const SidebarTrigger = forwardRef((_a, ref) => {
1834
+ var { className, onClick } = _a, props = __rest(_a, ["className", "onClick"]);
1835
+ const { toggleSidebar } = useSidebar();
1836
+ return (jsx(Button, Object.assign({ ref: ref, "data-sidebar": "trigger", variant: "text", suffixIcon: PanelLeft, className: cn('h-7 w-7', className), onClick: (event) => {
1837
+ onClick === null || onClick === void 0 ? void 0 : onClick(event);
1838
+ toggleSidebar();
1839
+ } }, props)));
1840
+ });
1841
+ SidebarTrigger.displayName = 'SidebarTrigger';
1842
+ const SidebarRail = forwardRef((_a, ref) => {
1843
+ var { className } = _a, props = __rest(_a, ["className"]);
1844
+ const { toggleSidebar } = useSidebar();
1845
+ return (jsx("button", Object.assign({ ref: ref, "data-sidebar": "rail", "aria-label": "Toggle Sidebar", tabIndex: -1, onClick: toggleSidebar, title: "Toggle Sidebar", className: cn('hover:after:bg-sidebar-border absolute inset-y-0 z-20 hidden w-4 -translate-x-1/2 transition-all ease-linear after:absolute after:inset-y-0 after:left-1/2 after:w-[2px] group-data-[side=left]:-right-4 group-data-[side=right]:left-0 sm:flex', '[[data-side=left]_&]:cursor-w-resize [[data-side=right]_&]:cursor-e-resize', '[[data-side=left][data-state=collapsed]_&]:cursor-e-resize [[data-side=right][data-state=collapsed]_&]:cursor-w-resize', 'group-data-[collapsible=offcanvas]:hover:bg-sidebar group-data-[collapsible=offcanvas]:translate-x-0 group-data-[collapsible=offcanvas]:after:left-full', '[[data-side=left][data-collapsible=offcanvas]_&]:-right-2', '[[data-side=right][data-collapsible=offcanvas]_&]:-left-2', className) }, props)));
1846
+ });
1847
+ SidebarRail.displayName = 'SidebarRail';
1848
+ const SidebarInset = forwardRef((_a, ref) => {
1849
+ var { className } = _a, props = __rest(_a, ["className"]);
1850
+ return (jsx("main", Object.assign({ ref: ref, className: cn('bg-background relative flex min-h-svh flex-1 flex-col', 'peer-data-[variant=inset]:min-h-[calc(100svh-theme(spacing.4))] md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow', className) }, props)));
1851
+ });
1852
+ SidebarInset.displayName = 'SidebarInset';
1853
+ const SidebarInput = forwardRef((_a, ref) => {
1854
+ var { className } = _a, props = __rest(_a, ["className"]);
1855
+ return (jsx(BasicInput, Object.assign({ ref: ref, "data-sidebar": "input", className: cn('focus-visible:ring-sidebar-ring focus-visible:ring-2', className) }, props)));
1856
+ });
1857
+ SidebarInput.displayName = 'SidebarInput';
1858
+ const SidebarHeader = forwardRef((_a, ref) => {
1859
+ var { className } = _a, props = __rest(_a, ["className"]);
1860
+ return (jsx("div", Object.assign({ ref: ref, "data-sidebar": "header", className: cn('flex flex-col gap-2 p-2', className) }, props)));
1861
+ });
1862
+ SidebarHeader.displayName = 'SidebarHeader';
1863
+ const SidebarFooter = forwardRef((_a, ref) => {
1864
+ var { className } = _a, props = __rest(_a, ["className"]);
1865
+ return (jsx("div", Object.assign({ ref: ref, "data-sidebar": "footer", className: cn('flex flex-col gap-2 p-2', className) }, props)));
1866
+ });
1867
+ SidebarFooter.displayName = 'SidebarFooter';
1868
+ const SidebarSeparator = forwardRef((_a, ref) => {
1869
+ var { className } = _a, props = __rest(_a, ["className"]);
1870
+ return (jsx(Separator, Object.assign({ ref: ref, "data-sidebar": "separator", className: cn('bg-sidebar-border mx-2 w-auto', className) }, props)));
1871
+ });
1872
+ SidebarSeparator.displayName = 'SidebarSeparator';
1873
+ const SidebarContent = forwardRef((_a, ref) => {
1874
+ var { className } = _a, props = __rest(_a, ["className"]);
1875
+ return (jsx("div", Object.assign({ ref: ref, "data-sidebar": "content", className: cn('flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden', className) }, props)));
1876
+ });
1877
+ SidebarContent.displayName = 'SidebarContent';
1878
+ const SidebarGroup = forwardRef((_a, ref) => {
1879
+ var { className } = _a, props = __rest(_a, ["className"]);
1880
+ return (jsx("div", Object.assign({ ref: ref, "data-sidebar": "group", className: cn('relative flex w-full min-w-0 flex-col p-2', className) }, props)));
1881
+ });
1882
+ SidebarGroup.displayName = 'SidebarGroup';
1883
+ const SidebarGroupLabel = forwardRef((_a, ref) => {
1884
+ var { className, asChild = false } = _a, props = __rest(_a, ["className", "asChild"]);
1885
+ const Comp = asChild ? Slot : 'div';
1886
+ return (jsx(Comp, Object.assign({ ref: ref, "data-sidebar": "group-label", className: cn('text-sidebar-foreground/70 ring-sidebar-ring flex h-8 shrink-0 items-center rounded-md px-2 text-xs font-medium outline-none transition-[margin,opa] duration-200 ease-linear focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0', 'group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0', className) }, props)));
1887
+ });
1888
+ SidebarGroupLabel.displayName = 'SidebarGroupLabel';
1889
+ const SidebarGroupAction = forwardRef((_a, ref) => {
1890
+ var { className, asChild = false } = _a, props = __rest(_a, ["className", "asChild"]);
1891
+ const Comp = asChild ? Slot : 'button';
1892
+ return (jsx(Comp, Object.assign({ ref: ref, "data-sidebar": "group-action", className: cn('text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground absolute right-3 top-3.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-none transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
1893
+ // Increases the hit area of the button on mobile.
1894
+ 'after:absolute after:-inset-2 after:md:hidden', 'group-data-[collapsible=icon]:hidden', className) }, props)));
1895
+ });
1896
+ SidebarGroupAction.displayName = 'SidebarGroupAction';
1897
+ const SidebarGroupContent = forwardRef((_a, ref) => {
1898
+ var { className } = _a, props = __rest(_a, ["className"]);
1899
+ return (jsx("div", Object.assign({ ref: ref, "data-sidebar": "group-content", className: cn('w-full text-sm', className) }, props)));
1900
+ });
1901
+ SidebarGroupContent.displayName = 'SidebarGroupContent';
1902
+ const SidebarMenu = forwardRef((_a, ref) => {
1903
+ var { className } = _a, props = __rest(_a, ["className"]);
1904
+ return (jsx("ul", Object.assign({ ref: ref, "data-sidebar": "menu", className: cn('flex w-full min-w-0 flex-col gap-1', className) }, props)));
1905
+ });
1906
+ SidebarMenu.displayName = 'SidebarMenu';
1907
+ const SidebarMenuItem = forwardRef((_a, ref) => {
1908
+ var { className } = _a, props = __rest(_a, ["className"]);
1909
+ return (jsx("li", Object.assign({ ref: ref, "data-sidebar": "menu-item", className: cn('group/menu-item relative', className) }, props)));
1910
+ });
1911
+ SidebarMenuItem.displayName = 'SidebarMenuItem';
1912
+ const sidebarMenuButtonVariants = cva('peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0', {
1913
+ variants: {
1914
+ variant: {
1915
+ default: 'hover:bg-sidebar-accent hover:text-sidebar-accent-foreground',
1916
+ outline: 'bg-background shadow-[0_0_0_1px_hsl(var(--sidebar-border))] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground hover:shadow-[0_0_0_1px_hsl(var(--sidebar-accent))]',
1917
+ },
1918
+ size: {
1919
+ default: 'h-8 text-sm',
1920
+ sm: 'h-7 text-xs',
1921
+ lg: 'h-12 text-sm group-data-[collapsible=icon]:!p-0',
1922
+ },
1923
+ },
1924
+ defaultVariants: {
1925
+ variant: 'default',
1926
+ size: 'default',
1927
+ },
1928
+ });
1929
+ const SidebarMenuButton = forwardRef((_a, ref) => {
1930
+ var { asChild = false, isActive = false, variant = 'default', size = 'default', tooltip, className } = _a, props = __rest(_a, ["asChild", "isActive", "variant", "size", "tooltip", "className"]);
1931
+ const Comp = asChild ? Slot : 'button';
1932
+ const { isMobile, state } = useSidebar();
1933
+ const button = (jsx(Comp, Object.assign({ ref: ref, "data-sidebar": "menu-button", "data-size": size, "data-active": isActive, className: cn(sidebarMenuButtonVariants({ variant, size }), className) }, props)));
1934
+ if (!tooltip || state !== 'collapsed' || isMobile) {
1935
+ return button;
1936
+ }
1937
+ if (typeof tooltip === 'string') {
1938
+ tooltip = {
1939
+ content: tooltip,
1940
+ };
1941
+ }
1942
+ return (jsx(Tooltip, Object.assign({ asChild: true, placement: "right" }, tooltip, { children: button })));
1943
+ });
1944
+ SidebarMenuButton.displayName = 'SidebarMenuButton';
1945
+ const SidebarMenuAction = forwardRef((_a, ref) => {
1946
+ var { className, asChild = false, showOnHover = false } = _a, props = __rest(_a, ["className", "asChild", "showOnHover"]);
1947
+ const Comp = asChild ? Slot : 'button';
1948
+ return (jsx(Comp, Object.assign({ ref: ref, "data-sidebar": "menu-action", className: cn('text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground peer-hover/menu-button:text-sidebar-accent-foreground absolute right-1 top-1.5 flex aspect-square w-5 items-center justify-center rounded-md p-0 outline-none transition-transform focus-visible:ring-2 [&>svg]:size-4 [&>svg]:shrink-0',
1949
+ // Increases the hit area of the button on mobile.
1950
+ 'after:absolute after:-inset-2 after:md:hidden', 'peer-data-[size=sm]/menu-button:top-1', 'peer-data-[size=default]/menu-button:top-1.5', 'peer-data-[size=lg]/menu-button:top-2.5', 'group-data-[collapsible=icon]:hidden', showOnHover &&
1951
+ 'peer-data-[active=true]/menu-button:text-sidebar-accent-foreground group-focus-within/menu-item:opacity-100 group-hover/menu-item:opacity-100 data-[state=open]:opacity-100 md:opacity-0', className) }, props)));
1952
+ });
1953
+ SidebarMenuAction.displayName = 'SidebarMenuAction';
1954
+ const SidebarMenuBadge = forwardRef((_a, ref) => {
1955
+ var { className } = _a, props = __rest(_a, ["className"]);
1956
+ return (jsx("div", Object.assign({ ref: ref, "data-sidebar": "menu-badge", className: cn('text-sidebar-foreground pointer-events-none absolute right-1 flex h-5 min-w-5 select-none items-center justify-center rounded-md px-1 text-xs font-medium tabular-nums', 'peer-hover/menu-button:text-sidebar-accent-foreground peer-data-[active=true]/menu-button:text-sidebar-accent-foreground', 'peer-data-[size=sm]/menu-button:top-1', 'peer-data-[size=default]/menu-button:top-1.5', 'peer-data-[size=lg]/menu-button:top-2.5', 'group-data-[collapsible=icon]:hidden', className) }, props)));
1957
+ });
1958
+ SidebarMenuBadge.displayName = 'SidebarMenuBadge';
1959
+ const SidebarMenuSkeleton = forwardRef((_a, ref) => {
1960
+ var { className, showIcon = false } = _a, props = __rest(_a, ["className", "showIcon"]);
1961
+ // Random width between 50 to 90%.
1962
+ const width = useMemo(() => {
1963
+ return `${Math.floor(Math.random() * 40) + 50}%`;
1964
+ }, []);
1965
+ return (jsxs("div", Object.assign({ ref: ref, "data-sidebar": "menu-skeleton", className: cn('flex h-8 items-center gap-2 rounded-md px-2', className) }, props, { children: [showIcon && jsx(Skeleton, { className: "size-4 rounded-md", "data-sidebar": "menu-skeleton-icon" }), jsx(Skeleton, { className: "h-4 max-w-[--skeleton-width] flex-1", "data-sidebar": "menu-skeleton-text", style: {
1966
+ '--skeleton-width': width,
1967
+ } })] })));
1968
+ });
1969
+ SidebarMenuSkeleton.displayName = 'SidebarMenuSkeleton';
1970
+ const SidebarMenuSub = forwardRef((_a, ref) => {
1971
+ var { className } = _a, props = __rest(_a, ["className"]);
1972
+ return (jsx("ul", Object.assign({ ref: ref, "data-sidebar": "menu-sub", className: cn('border-sidebar-border mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l px-2.5 py-0.5', 'group-data-[collapsible=icon]:hidden', className) }, props)));
1973
+ });
1974
+ SidebarMenuSub.displayName = 'SidebarMenuSub';
1975
+ const SidebarMenuSubItem = forwardRef((_a, ref) => {
1976
+ var props = __rest(_a, []);
1977
+ return (jsx("li", Object.assign({ ref: ref }, props)));
1978
+ });
1979
+ SidebarMenuSubItem.displayName = 'SidebarMenuSubItem';
1980
+ const SidebarMenuSubButton = forwardRef((_a, ref) => {
1981
+ var { asChild = false, size = 'md', isActive, className } = _a, props = __rest(_a, ["asChild", "size", "isActive", "className"]);
1982
+ const Comp = asChild ? Slot : 'a';
1983
+ return (jsx(Comp, Object.assign({ ref: ref, "data-sidebar": "menu-sub-button", "data-size": size, "data-active": isActive, className: cn('text-sidebar-foreground ring-sidebar-ring hover:bg-sidebar-accent hover:text-sidebar-accent-foreground active:bg-sidebar-accent active:text-sidebar-accent-foreground [&>svg]:text-sidebar-accent-foreground flex h-7 min-w-0 -translate-x-px items-center gap-2 overflow-hidden rounded-md px-2 outline-none focus-visible:ring-2 disabled:pointer-events-none disabled:opacity-50 aria-disabled:pointer-events-none aria-disabled:opacity-50 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0', 'data-[active=true]:bg-sidebar-accent data-[active=true]:text-sidebar-accent-foreground', size === 'sm' && 'text-xs', size === 'md' && 'text-sm', 'group-data-[collapsible=icon]:hidden', className) }, props)));
1984
+ });
1985
+ SidebarMenuSubButton.displayName = 'SidebarMenuSubButton';
1986
+ const Sidebar = Object.assign($Sidebar, {
1987
+ Content: SidebarContent,
1988
+ Footer: SidebarFooter,
1989
+ Group: SidebarGroup,
1990
+ GroupAction: SidebarGroupAction,
1991
+ GroupContent: SidebarGroupContent,
1992
+ GroupLabel: SidebarGroupLabel,
1993
+ Header: SidebarHeader,
1994
+ Input: SidebarInput,
1995
+ Inset: SidebarInset,
1996
+ Menu: SidebarMenu,
1997
+ MenuAction: SidebarMenuAction,
1998
+ MenuBadge: SidebarMenuBadge,
1999
+ MenuButton: SidebarMenuButton,
2000
+ MenuItem: SidebarMenuItem,
2001
+ MenuSkeleton: SidebarMenuSkeleton,
2002
+ MenuSub: SidebarMenuSub,
2003
+ MenuSubButton: SidebarMenuSubButton,
2004
+ MenuSubItem: SidebarMenuSubItem,
2005
+ Rail: SidebarRail,
2006
+ Separator: SidebarSeparator,
2007
+ Trigger: SidebarTrigger,
2008
+ });
1683
2009
 
1684
- const Navbar = ({ leftSlot, rightSlot }) => {
1685
- const { setSidebarOpen } = useLayoutContext();
1686
- return (jsx(Block, { className: "border-b p-3 dark:border-slate-700", fullWidth: true, children: jsxs(Flex, { align: "center", justify: "between", children: [jsxs(Flex, { align: "center", children: [jsx(Button, { className: "xl:hidden", prefixIcon: MenuIcon, variant: "text", onClick: () => setSidebarOpen(true) }), leftSlot] }), rightSlot] }) }));
1687
- };
2010
+ const Navbar = ({ leftSlot, rightSlot }) => (jsx(Block, { className: "border-b p-3 dark:border-slate-700", fullWidth: true, children: jsxs(Flex, { align: "center", justify: "between", children: [jsxs(Flex, { align: "center", children: [jsx(Sidebar.Trigger, {}), leftSlot] }), rightSlot] }) }));
1688
2011
 
1689
- const SidebarItemComp = ({ pathname, title, label, Icon, active, isChild, basePath, sidebarOpen, items, onClick, }) => (jsxs(Link, { className: cn('flex h-10 w-full cursor-pointer items-center overflow-hidden rounded-md p-2 font-medium', {
1690
- 'gap-2': sidebarOpen,
1691
- 'gap-3': !sidebarOpen,
1692
- 'pl-2.5': !sidebarOpen,
1693
- 'dark:text-white': active,
1694
- 'bg-slate-100 dark:bg-slate-800': active && !isChild && !items,
1695
- 'bg-slate-200 dark:bg-slate-900': active && (isChild || items),
1696
- 'text-slate-500 dark:text-slate-400': !active,
1697
- 'hover:bg-slate-100 dark:hover:bg-slate-800': !active && !isChild,
1698
- 'hover:bg-slate-200 dark:hover:bg-slate-900': !active && isChild,
1699
- }), to: [basePath, pathname].join('/').replace(/\/{2,}/g, '/'), onClick: onClick, children: [jsx(Icon, { className: "h-5 w-5 min-w-min", size: 16 }), jsxs("div", { className: "min-w-max", children: [title, jsx("div", { className: "ml-auto flex items-center space-x-2", children: label })] })] }));
1700
-
1701
- const Sidebar = forwardRef(({ className, items, basePath = '/', smallLogo, fullLogo, footer }, ref) => {
2012
+ const Layout = ({ children, className, sidebarProps, navbarProps, }) => {
2013
+ return (jsxs(Flex, { className: "h-screen w-screen gap-0 text-black dark:bg-slate-900 dark:text-white", children: [jsxs(Sidebar, Object.assign({ collapsible: "icon" }, sidebarProps.root, { children: [jsx(Sidebar.Header, { children: sidebarProps.smallLogo && sidebarProps.fullLogo && (jsx("div", { className: "cursor-pointer overflow-hidden whitespace-nowrap py-2 text-center text-lg", children: jsxs(Link, { to: "/", children: [jsx("span", { className: "group-data-[state=collapsed]:hidden", children: sidebarProps.fullLogo }), jsx("span", { className: "group-data-[state=expanded]:hidden", children: sidebarProps.smallLogo })] }) })) }), jsx(Sidebar.Content, { className: "gap-0", children: sidebarProps.items.map((item, index) => item.type === 'item' ? (jsx(Sidebar.Group, { children: jsx(Sidebar.Menu, { children: jsx(RenderSideBarItem, Object.assign({ basePath: sidebarProps.basePath }, item)) }) }, index)) : (jsxs(Sidebar.Group, { children: [item.title && jsx(Sidebar.GroupLabel, { children: item.title }), jsx(Sidebar.GroupContent, { children: jsx(Sidebar.Menu, { children: item.items.map((item, index) => (jsx(RenderSideBarItem, Object.assign({ basePath: sidebarProps.basePath }, item), index))) }) })] }, index))) }), jsx(Sidebar.Rail, {})] })), jsxs(Flex, { className: "gap-0 overflow-hidden", direction: "column", fullHeight: true, fullWidth: true, children: [jsx(Navbar, Object.assign({}, navbarProps)), jsx(Flex, { className: cn('overflow-hidden p-3', className), direction: "column", fullWidth: true, fullHeight: true, children: children })] })] }));
2014
+ };
2015
+ const RenderSideBarItem = ({ basePath = '/', pathname, title, Icon, items, }) => {
1702
2016
  const location = useLocation();
1703
- const { sidebarOpen, setSidebarOpen } = useLayoutContext();
2017
+ const { open } = useSidebar();
1704
2018
  const currentPath = useMemo(() => location.pathname.replace(basePath, '').replace(/^\/*/, ''), [basePath, location.pathname]);
1705
- const parentTab = useMemo(() => {
1706
- var _a;
1707
- return (_a = items.filter(isItem).find((item) => isLinkStartsWithPathname(currentPath, item.pathname))) === null || _a === void 0 ? void 0 : _a.pathname;
1708
- }, [currentPath, items]);
1709
- const OpenCloseIcon = sidebarOpen ? ChevronsLeftIcon : ChevronsRightIcon;
1710
- return (jsxs(Fragment, { children: [jsx("div", { className: "absolute left-0 top-0 h-full w-full backdrop-blur-sm transition-opacity data-[open=true]:z-50 data-[open=false]:hidden data-[open=false]:opacity-0 data-[open=true]:opacity-100 xl:hidden", "data-open": sidebarOpen }), jsxs("nav", { className: cn('group/navbar fixed left-0 top-0 z-50 flex h-full w-56 shrink-0 flex-col bg-white p-2 transition-all duration-200 ease-in-out xl:relative dark:bg-slate-900', 'border-r data-[open=false]:-translate-x-full xl:data-[open=false]:w-16 xl:data-[open=true]:w-72 xl:data-[open=false]:translate-x-0 xl:data-[open=false]:hover:w-72 dark:border-slate-700', className), "data-open": sidebarOpen, ref: ref, children: [smallLogo && fullLogo && (jsx("div", { className: "mb-2 cursor-pointer overflow-hidden whitespace-nowrap p-2 py-3 text-center text-2xl", children: jsxs(Link, { to: "/", children: [jsx("span", { className: cn('group-hover/navbar:block', !sidebarOpen && 'hidden'), children: fullLogo }), jsx("span", { className: cn('group-hover/navbar:hidden', sidebarOpen && 'hidden'), children: smallLogo })] }) })), jsx(Accordion.Root, { className: "overflow-hidden", type: "single", value: parentTab, children: items.map((item, index) => {
1711
- var _a;
1712
- return !item.hidden &&
1713
- (item.type === 'separator' ? (!item.title ? (jsx(Block, { className: "my-2 h-px bg-slate-300 dark:bg-slate-700" }, index)) : (jsx(Block, { className: "mb-2 mt-6 pl-2 text-sm font-bold text-slate-600 group-hover/navbar:block data-[open=false]:hidden dark:text-slate-500", "data-open": sidebarOpen, children: item.title }, index))) : (jsxs(Accordion.Item, { className: cn('flex flex-col rounded-md', {
1714
- 'bg-slate-100 dark:bg-slate-800': item.items && isLinkStartsWithPathname(currentPath, item.pathname),
1715
- }), value: item.pathname, children: [jsx(Accordion.Header, { children: jsxs(Accordion.Trigger, { className: "relative w-full p-0.5 data-[state=open]:[--rotate-chevron:90deg]", children: [jsx(SidebarItemComp, Object.assign({}, item, { active: isLinkStartsWithPathname(currentPath, item.pathname) &&
1716
- (!item.items ||
1717
- item.items.every((subItem) => !isLinkStartsWithPathname(currentPath, `${item.pathname}/${subItem.pathname}`))), basePath: basePath, sidebarOpen: sidebarOpen, onClick: ((_a = item.items) === null || _a === void 0 ? void 0 : _a.length) ? undefined : () => setSidebarOpen(false) })), item.items && (jsx(ChevronRightIcon, { className: cn('absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 rotate-[var(--rotate-chevron,0deg)] transition-transform duration-200', !sidebarOpen && 'invisible', 'group-hover/navbar:visible') }))] }) }), item.items && (jsx(Accordion.Content, { className: "overflow-hidden data-[state=closed]:animate-[slideUp_200ms_ease-out] data-[state=open]:animate-[slideDown_200ms_ease-out]", children: jsx("div", { className: "flex flex-col gap-1 p-1 pt-0", children: item.items.map((subItem) => {
1718
- const subPathname = `${item.pathname}/${subItem.pathname}`;
1719
- return (!subItem.hidden && (jsx(SidebarItemComp, Object.assign({}, subItem, { pathname: subPathname, isChild: true, active: isLinkStartsWithPathname(currentPath, subPathname), basePath: basePath, sidebarOpen: sidebarOpen, onClick: () => setSidebarOpen(false) }), subPathname)));
1720
- }) }) }))] }, item.pathname)));
1721
- }) }), jsxs(Flex, { className: "mt-auto", direction: "column", fullWidth: true, children: [footer, jsx(Button, { className: "invisible w-full justify-center xl:visible", variant: "text", prefixIcon: OpenCloseIcon, onClick: () => setSidebarOpen(!sidebarOpen) })] })] })] }));
1722
- });
2019
+ return (jsxs(Sidebar.MenuItem, { children: [jsx(Sidebar.MenuButton, { asChild: true, tooltip: title, isActive: isLinkStartsWithPathname(currentPath, pathname) &&
2020
+ (!items ||
2021
+ (!open &&
2022
+ items.some((item) => isLinkStartsWithPathname(currentPath, `${pathname}/${item.pathname}`)))), children: jsxs(Link, { to: pathname, className: "font-medium", children: [Icon && jsx(Icon, {}), title] }) }), items && (jsx(Sidebar.MenuSub, { children: items.map((subItem, index) => (jsx(Sidebar.MenuSubItem, { children: jsx(Sidebar.MenuSubButton, { asChild: true, isActive: isLinkStartsWithPathname(currentPath, `${pathname}/${subItem.pathname}`), children: jsx(Link, { to: `${pathname}/${subItem.pathname}`, children: subItem.title }) }) }, index))) }))] }));
2023
+ };
1723
2024
  function isLinkStartsWithPathname(link, pathname) {
1724
2025
  return pathname === '' ? link === pathname : link.startsWith(pathname);
1725
2026
  }
1726
- function isItem(item) {
1727
- return item.type !== 'separator';
1728
- }
1729
-
1730
- const Layout = ({ children, className, sidebarProps, navbarProps, }) => {
1731
- const { sidebarOpen, setSidebarOpen } = useLayoutContext();
1732
- const screenRef = useRef(null);
1733
- const sidebarRef = useRef(null);
1734
- useOnSwipe(screenRef, (direction) => direction === 'right' ? setSidebarOpen(true) : direction === 'left' && setSidebarOpen(false));
1735
- useOutsideClick(sidebarRef, () => sidebarOpen && window.document.documentElement.offsetWidth <= 1024 && setSidebarOpen(false));
1736
- return (jsxs(Flex, { className: "h-screen gap-0 text-black dark:bg-slate-900 dark:text-white", ref: screenRef, children: [jsx(Sidebar, Object.assign({}, sidebarProps, { open: sidebarOpen, ref: sidebarRef })), jsxs(Flex, { className: "gap-0 overflow-hidden", direction: "column", fullHeight: true, fullWidth: true, children: [jsx(Navbar, Object.assign({}, navbarProps)), jsx(Flex, { className: cn('overflow-hidden p-3', className), direction: "column", fullWidth: true, fullHeight: true, children: children })] })] }));
1737
- };
1738
2027
 
1739
2028
  const $Popover = PopoverPrimitive.Root;
1740
2029
  const PopoverTrigger = PopoverPrimitive.Trigger;
@@ -1776,6 +2065,47 @@ const Tabs = Object.assign($Tabs, {
1776
2065
  Content: TabsContent,
1777
2066
  });
1778
2067
 
2068
+ const LayoutContext = createContext(undefined);
2069
+ const LayoutContextProvider = ({ children }) => {
2070
+ const [theme, setTheme] = useState(getValueFromLocalStorage(THEME_KEY, 'light'));
2071
+ useEffect(() => {
2072
+ if (theme) {
2073
+ if (theme === 'dark') {
2074
+ document.documentElement.classList.add('dark');
2075
+ }
2076
+ else {
2077
+ document.documentElement.classList.remove('dark');
2078
+ }
2079
+ }
2080
+ }, [theme]);
2081
+ const toggleTheme = () => {
2082
+ setTheme((theme) => {
2083
+ const newValue = theme === 'dark' ? 'light' : 'dark';
2084
+ window.localStorage.setItem(THEME_KEY, newValue);
2085
+ return newValue;
2086
+ });
2087
+ };
2088
+ return jsx(LayoutContext.Provider, { value: { theme, toggleTheme }, children: children });
2089
+ };
2090
+ function useLayoutContext() {
2091
+ const context = useContext(LayoutContext);
2092
+ if (!context) {
2093
+ throw new Error('Please use LayoutContextProvider!');
2094
+ }
2095
+ return context;
2096
+ }
2097
+ const THEME_KEY = 'tw-react-components__theme';
2098
+ function getValueFromLocalStorage(key, _default) {
2099
+ var _a;
2100
+ const transformers = {
2101
+ string: String,
2102
+ boolean: (value) => value === 'true',
2103
+ };
2104
+ return typeof window !== 'undefined'
2105
+ ? transformers[typeof _default]((_a = window.localStorage.getItem(key)) !== null && _a !== void 0 ? _a : _default)
2106
+ : _default;
2107
+ }
2108
+
1779
2109
  const ThemeSwitcher = ({ className }) => {
1780
2110
  const { theme, toggleTheme } = useLayoutContext();
1781
2111
  const darkMode = theme === 'dark';
@@ -1784,4 +2114,4 @@ const ThemeSwitcher = ({ className }) => {
1784
2114
  } }));
1785
2115
  };
1786
2116
 
1787
- export { Badge, BasicInput, BasicInputExtension, Block, Button, Card, CheckboxInput, ConfirmDialog, DataTable, DateTimeInput, Dialog, DropdownMenu, EmailInput, Flex, FormDialog, FormGroup, FormInputs, Hint, Label, Layout, LayoutContext, LayoutContextProvider, List, ListSorter, ListSorterDialog, Navbar, NumberInput, Pagination, PasswordInput, PdfViewerDialog, Popover, SIDEBAR_KEY, SelectInput, Sidebar, Spinner, Switch, THEME_KEY, Table, Tabs, TextInput, TextareaInput, ThemeSwitcher, Tooltip, cn, compareDates, generalComparator, getDisplayDate, isEmpty, mergeRefs, resolveTargetObject, useDays, useLayoutContext, useLongPress, useMonths, useOnSwipe, useOutsideClick, usePagination };
2117
+ export { Badge, BasicInput, BasicInputExtension, Block, Button, Card, CheckboxInput, ConfirmDialog, DataTable, DateTimeInput, Dialog, DropdownMenu, EmailInput, FileInput, Flex, FormDialog, FormGroup, FormInputs, Hint, Label, Layout, LayoutContext, LayoutContextProvider, List, ListSorter, ListSorterDialog, Navbar, NumberInput, Pagination, PasswordInput, PdfViewerDialog, Popover, SelectInput, Separator, Sheet, Sidebar, SidebarContext, SidebarContextProvider, Skeleton, Spinner, Switch, THEME_KEY, Table, Tabs, TextInput, TextareaInput, ThemeSwitcher, Tooltip, cn, compareDates, generalComparator, getDisplayDate, isEmpty, mergeRefs, resolveTargetObject, useDays, useIsMobile, useLayoutContext, useLongPress, useMonths, useOnSwipe, useOutsideClick, usePagination, useSidebar };