tw-react-components 0.0.173 → 0.0.175

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,4 +1,4 @@
1
- import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import { clsx } from 'clsx';
3
3
  import { twMerge } from 'tailwind-merge';
4
4
  import dayjs from 'dayjs';
@@ -142,6 +142,42 @@ function resolveTargetObject(payload, fieldChain, defaultValue) {
142
142
  return resolveTargetObject(payload[key], rest, defaultValue);
143
143
  }
144
144
 
145
+ const Block = (_a) => {
146
+ var { children, className, centered, container, fullWidth, fullHeight, dataTestId = 'block' } = _a, props = __rest(_a, ["children", "className", "centered", "container", "fullWidth", "fullHeight", "dataTestId"]);
147
+ return (jsx("div", Object.assign({ "data-testid": dataTestId, className: cn(centered && 'mx-auto', container && 'container', fullWidth && 'w-full', fullHeight && 'h-full', className) }, props, { children: children })));
148
+ };
149
+
150
+ const directionClasses = {
151
+ row: {
152
+ normal: 'flex-row',
153
+ reverse: 'flex-row-reverse',
154
+ },
155
+ column: {
156
+ normal: 'flex-col',
157
+ reverse: 'flex-col-reverse',
158
+ },
159
+ };
160
+ const alignClasses = {
161
+ start: 'items-start',
162
+ center: 'items-center',
163
+ end: 'items-end',
164
+ };
165
+ const justifyClasses = {
166
+ start: 'justify-start',
167
+ center: 'justify-center',
168
+ between: 'justify-between',
169
+ end: 'justify-end',
170
+ };
171
+ const Flex = (_a) => {
172
+ var { children, className, reverse, wrap, direction = 'row', align = 'start', justify = 'start', dataTestId = 'flex' } = _a, blockProps = __rest(_a, ["children", "className", "reverse", "wrap", "direction", "align", "justify", "dataTestId"]);
173
+ return (jsx(Block, Object.assign({ className: cn('flex gap-2', wrap && 'flex-wrap', directionClasses[direction][reverse ? 'reverse' : 'normal'], alignClasses[align], justifyClasses[justify], className), dataTestId: dataTestId }, blockProps, { children: children })));
174
+ };
175
+
176
+ const Spinner = ({ className, fullScreen, dataTestId = 'spinner' }) => (jsx("div", { className: cn('flex w-full items-center justify-center bg-white dark:bg-slate-900', {
177
+ 'h-screen': fullScreen,
178
+ 'h-full': !fullScreen,
179
+ }, className), "data-testid": dataTestId, children: jsxs("svg", { className: "h-8 w-8 animate-spin text-black dark:text-white", fill: "none", viewBox: "0 0 24 24", children: [jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }) }));
180
+
145
181
  const variantClassNames = {
146
182
  filled: {
147
183
  slate: {
@@ -565,12 +601,12 @@ const sizeClassNames = {
565
601
  },
566
602
  };
567
603
  const Button = (_a) => {
568
- var { children, className, size = 'medium', color = 'slate', variant = 'filled', rounded, prefixIcon: PrefixIcon, suffixIcon: SuffixIcon, unstyled, dataTestId = 'button' } = _a, props = __rest(_a, ["children", "className", "size", "color", "variant", "rounded", "prefixIcon", "suffixIcon", "unstyled", "dataTestId"]);
569
- return (jsxs("button", Object.assign({ className: cn('relative flex aspect-square items-center font-medium duration-200', sizeClassNames[size].base, variantClassNames[variant][color].base, rounded ? 'rounded-full' : 'rounded-md', props.disabled
604
+ var { children, className, size = 'medium', color = 'slate', variant = 'filled', rounded, loading, disabled, prefixIcon: PrefixIcon, suffixIcon: SuffixIcon, unstyled, dataTestId = 'button' } = _a, props = __rest(_a, ["children", "className", "size", "color", "variant", "rounded", "loading", "disabled", "prefixIcon", "suffixIcon", "unstyled", "dataTestId"]);
605
+ return (jsxs("button", Object.assign({ className: cn('relative flex aspect-square items-center font-medium duration-200', sizeClassNames[size].base, variantClassNames[variant][color].base, rounded ? 'rounded-full' : 'rounded-md', disabled || loading
570
606
  ? 'cursor-not-allowed opacity-50'
571
607
  : !unstyled
572
608
  ? `${variantClassNames[variant][color].hover} ${variantClassNames[variant][color].focus} ${variantClassNames[variant][color].active} cursor-pointer`
573
- : 'cursor-default', children ? `${sizeClassNames[size].withChildren} aspect-[initial]` : 'justify-center', className), "data-testid": dataTestId, type: "button" }, props, { children: [PrefixIcon && (jsx(PrefixIcon, { className: children ? sizeClassNames[size].icon.withChildren : sizeClassNames[size].icon.base })), children, SuffixIcon && (jsx(SuffixIcon, { className: children ? sizeClassNames[size].icon.withChildren : sizeClassNames[size].icon.base }))] })));
609
+ : 'cursor-default', children ? `${sizeClassNames[size].withChildren} aspect-[initial]` : 'justify-center', className), "data-testid": dataTestId, type: "button", disabled: disabled || loading }, props, { children: [loading && (jsx(Flex, { className: cn('absolute inset-0', rounded ? 'rounded-full' : 'rounded-md'), align: "center", justify: "center", children: jsx(Spinner, { className: "h-5 w-5 animate-spin bg-transparent dark:bg-transparent", dataTestId: `${dataTestId}-spinner` }) })), PrefixIcon && (jsx(PrefixIcon, { className: children ? sizeClassNames[size].icon.withChildren : sizeClassNames[size].icon.base })), children, SuffixIcon && (jsx(SuffixIcon, { className: children ? sizeClassNames[size].icon.withChildren : sizeClassNames[size].icon.base }))] })));
574
610
  };
575
611
 
576
612
  const Badge = (_a) => {
@@ -578,11 +614,6 @@ const Badge = (_a) => {
578
614
  return (jsx(Button, Object.assign({ size: size, dataTestId: dataTestId }, props)));
579
615
  };
580
616
 
581
- const Block = (_a) => {
582
- var { children, className, centered, container, fullWidth, fullHeight, dataTestId = 'block' } = _a, props = __rest(_a, ["children", "className", "centered", "container", "fullWidth", "fullHeight", "dataTestId"]);
583
- return (jsx("div", Object.assign({ "data-testid": dataTestId, className: cn(centered && 'mx-auto', container && 'container', fullWidth && 'w-full', fullHeight && 'h-full', className) }, props, { children: children })));
584
- };
585
-
586
617
  const Card = (_a) => {
587
618
  var { children, className, dataTestId = 'card' } = _a, blockProps = __rest(_a, ["children", "className", "dataTestId"]);
588
619
  return (jsx(Block, Object.assign({ className: cn('bg-background rounded-lg border p-2 dark:border-slate-700', className), dataTestId: dataTestId }, blockProps, { children: children })));
@@ -605,32 +636,6 @@ const Collapsible = Object.assign(CollapsibleRoot, {
605
636
  Content: CollapsibleContent,
606
637
  });
607
638
 
608
- const directionClasses = {
609
- row: {
610
- normal: 'flex-row',
611
- reverse: 'flex-row-reverse',
612
- },
613
- column: {
614
- normal: 'flex-col',
615
- reverse: 'flex-col-reverse',
616
- },
617
- };
618
- const alignClasses = {
619
- start: 'items-start',
620
- center: 'items-center',
621
- end: 'items-end',
622
- };
623
- const justifyClasses = {
624
- start: 'justify-start',
625
- center: 'justify-center',
626
- between: 'justify-between',
627
- end: 'justify-end',
628
- };
629
- const Flex = (_a) => {
630
- var { children, className, reverse, wrap, direction = 'row', align = 'start', justify = 'start', dataTestId = 'flex' } = _a, blockProps = __rest(_a, ["children", "className", "reverse", "wrap", "direction", "align", "justify", "dataTestId"]);
631
- return (jsx(Block, Object.assign({ className: cn('flex gap-2', wrap && 'flex-wrap', directionClasses[direction][reverse ? 'reverse' : 'normal'], alignClasses[align], justifyClasses[justify], className), dataTestId: dataTestId }, blockProps, { children: children })));
632
- };
633
-
634
639
  dayjs.extend(localeData);
635
640
  function useDays(locale = 'en') {
636
641
  return useMemo(() => {
@@ -1500,11 +1505,6 @@ const PaginationItem = (_a) => {
1500
1505
  }), align: "center", justify: "center", fullHeight: true }, props, { children: children })));
1501
1506
  };
1502
1507
 
1503
- const Spinner = ({ className, fullScreen, dataTestId = 'spinner' }) => (jsx("div", { className: cn('flex w-full items-center justify-center bg-white dark:bg-slate-900', {
1504
- 'h-screen': fullScreen,
1505
- 'h-full': !fullScreen,
1506
- }, className), "data-testid": dataTestId, children: jsxs("svg", { className: "h-8 w-8 animate-spin text-black dark:text-white", fill: "none", viewBox: "0 0 24 24", children: [jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }) }));
1507
-
1508
1508
  const $Table = (_a) => {
1509
1509
  var { children, className, dataTestId = 'table' } = _a, props = __rest(_a, ["children", "className", "dataTestId"]);
1510
1510
  return (jsx(Flex, { className: cn('overflow-auto rounded-lg', className), fullWidth: true, children: jsx("table", Object.assign({ className: "min-w-full divide-y divide-slate-200 dark:divide-slate-800 dark:text-white", "data-testid": dataTestId }, props, { children: children })) }));
@@ -1679,7 +1679,15 @@ const Dialog = Object.assign($Dialog, {
1679
1679
  Description: DialogDescription,
1680
1680
  });
1681
1681
 
1682
- const ConfirmDialog = ({ open, title, children, yesLabel, noLabel, onConfirm, onClose, dataTestId = 'confirm-dialog', }) => (jsx(Dialog, { open: open, onOpenChange: (value) => !value && onClose(), children: jsxs(Dialog.Content, { dataTestId: `${dataTestId}-content`, children: [jsx(Dialog.Header, { dataTestId: `${dataTestId}-header`, children: jsx(Dialog.Title, { dataTestId: `${dataTestId}-title`, children: title }) }), children, jsxs(Dialog.Footer, { dataTestId: `${dataTestId}-footer`, children: [jsx(Dialog.Close, { asChild: true, children: jsx(Button, { color: "red", "data-testid": `${dataTestId}-no-button`, children: noLabel !== null && noLabel !== void 0 ? noLabel : 'No' }) }), jsx(Dialog.Close, { asChild: true, children: jsx(Button, { color: "green", onClick: onConfirm, "data-testid": `${dataTestId}-yes-button`, children: yesLabel !== null && yesLabel !== void 0 ? yesLabel : 'Yes' }) })] })] }) }));
1682
+ const ConfirmDialog = ({ open, title, children, yesLabel, noLabel, onConfirm, onClose, dataTestId = 'confirm-dialog', }) => {
1683
+ const [loading, setLoading] = useState(false);
1684
+ const handleConfirm = () => __awaiter(void 0, void 0, void 0, function* () {
1685
+ setLoading(true);
1686
+ yield onConfirm();
1687
+ setLoading(false);
1688
+ });
1689
+ return (jsx(Dialog, { open: open, onOpenChange: (value) => !value && onClose(), children: jsxs(Dialog.Content, { dataTestId: `${dataTestId}-content`, children: [jsx(Dialog.Header, { dataTestId: `${dataTestId}-header`, children: jsx(Dialog.Title, { dataTestId: `${dataTestId}-title`, children: title }) }), children, jsxs(Dialog.Footer, { dataTestId: `${dataTestId}-footer`, children: [jsx(Dialog.Close, { asChild: true, children: jsx(Button, { color: "red", disabled: loading, "data-testid": `${dataTestId}-no-button`, children: noLabel !== null && noLabel !== void 0 ? noLabel : 'No' }) }), jsx(Button, { color: "green", loading: loading, onClick: handleConfirm, "data-testid": `${dataTestId}-yes-button`, children: yesLabel !== null && yesLabel !== void 0 ? yesLabel : 'Yes' })] })] }) }));
1690
+ };
1683
1691
 
1684
1692
  const SheetTrigger = DialogPrimitive.Trigger;
1685
1693
  const SheetClose = DialogPrimitive.Close;
@@ -1741,7 +1749,7 @@ const Sheet = Object.assign(DialogPrimitive.Root, {
1741
1749
 
1742
1750
  const FormDialog = ({ className, formClassName, open, title, form, children, submitLabel = 'Submit', cancelLabel = 'Cancel', extraAction, as: As = Sheet, onSubmit, onInvalid, onClose, dataTestId = 'form-dialog', }) => {
1743
1751
  const id = useId();
1744
- return (jsx(As, { open: open, onOpenChange: (value) => !value && onClose(), children: jsxs(As.Content, { className: className, dataTestId: `${dataTestId}-content`, children: [jsx(As.Header, { dataTestId: `${dataTestId}-header`, children: jsx(As.Title, { dataTestId: `${dataTestId}-title`, children: title }) }), jsx(FormProvider, Object.assign({}, form, { children: jsx("form", { id: `form-${id}`, className: cn('flex h-full w-full flex-col gap-2 overflow-auto', formClassName), onSubmit: form.handleSubmit(onSubmit, onInvalid), "data-testid": `${dataTestId}-form`, children: children }) })), jsxs(As.Footer, { className: "w-full sm:justify-between", dataTestId: `${dataTestId}-footer`, children: [extraAction, jsxs(As.Footer, { className: "ml-auto", dataTestId: `${dataTestId}-actions`, children: [jsx(As.Close, { asChild: true, children: jsx(Button, { color: "red", dataTestId: `${dataTestId}-cancel-button`, children: cancelLabel }) }), jsx(Button, { color: "green", type: "submit", form: `form-${id}`, disabled: form.formState.isSubmitting, dataTestId: `${dataTestId}-submit-button`, children: submitLabel })] })] })] }) }));
1752
+ return (jsx(As, { open: open, onOpenChange: (value) => !value && onClose(), children: jsxs(As.Content, { className: className, dataTestId: `${dataTestId}-content`, children: [jsx(As.Header, { dataTestId: `${dataTestId}-header`, children: jsx(As.Title, { dataTestId: `${dataTestId}-title`, children: title }) }), jsx(FormProvider, Object.assign({}, form, { children: jsx("form", { id: `form-${id}`, className: cn('flex h-full w-full flex-col gap-2 overflow-auto', formClassName), onSubmit: form.handleSubmit(onSubmit, onInvalid), "data-testid": `${dataTestId}-form`, children: children }) })), jsxs(As.Footer, { className: "w-full sm:justify-between", dataTestId: `${dataTestId}-footer`, children: [extraAction, jsxs(As.Footer, { className: "ml-auto", dataTestId: `${dataTestId}-actions`, children: [jsx(As.Close, { asChild: true, children: jsx(Button, { color: "red", dataTestId: `${dataTestId}-cancel-button`, disabled: form.formState.isSubmitting, children: cancelLabel }) }), jsx(Button, { color: "green", type: "submit", form: `form-${id}`, loading: form.formState.isSubmitting, dataTestId: `${dataTestId}-submit-button`, children: submitLabel })] })] })] }) }));
1745
1753
  };
1746
1754
 
1747
1755
  function ListSorter({ className, items, dataTestId = 'list-sorter', idResolver, renderer, onChange, }) {
@@ -1772,14 +1780,19 @@ function SortableItem({ item, index, dataTestId, renderer, }) {
1772
1780
 
1773
1781
  function ListSorterDialog({ className, open, title, items, idResolver, renderer, cancelLabel, submitLabel, onSubmit, onClose, dataTestId = 'list-sorter-dialog', }) {
1774
1782
  const [sortedItems, setSortedItems] = useState(structuredClone(items));
1783
+ const [loading, setLoading] = useState(false);
1775
1784
  useEffect(() => {
1776
1785
  if (!open) {
1777
1786
  setSortedItems(structuredClone(items));
1778
1787
  }
1779
1788
  }, [items, open]);
1780
- const preFinish = () => onSubmit(sortedItems);
1789
+ const handleSubmit = () => __awaiter(this, void 0, void 0, function* () {
1790
+ setLoading(true);
1791
+ yield onSubmit(sortedItems);
1792
+ setLoading(false);
1793
+ });
1781
1794
  const customRenderer = (item, index, listeners) => (jsxs(Flex, { align: "center", className: "gap-4 p-4 focus:outline-hidden dark:bg-slate-900 hover:dark:bg-slate-800", "data-testid": `${dataTestId}-item-${index}`, children: [jsx(Flex, Object.assign({ align: "center", justify: "center", className: "cursor-move rounded-lg p-2 hover:bg-slate-200 dark:hover:bg-slate-700", "data-testid": `${dataTestId}-drag-handle-${index}` }, listeners, { children: jsx(ArrowUpDownIcon, { className: "h-5 w-5" }) })), renderer(item, index, listeners)] }));
1782
- return (jsx(Dialog, { open: open, onOpenChange: (value) => !value && onClose(), children: jsxs(Dialog.Content, { className: className, onPointerDownOutside: (event) => event.preventDefault(), dataTestId: `${dataTestId}-content`, children: [jsx(Dialog.Header, { dataTestId: `${dataTestId}-header`, children: jsx(Dialog.Title, { dataTestId: `${dataTestId}-title`, children: title }) }), jsx(ListSorter, { className: "divide-y overflow-auto rounded-lg border dark:divide-slate-700 dark:border-slate-700 dark:text-white", items: sortedItems, idResolver: idResolver, renderer: customRenderer, onChange: setSortedItems, dataTestId: `${dataTestId}-sorter` }), jsxs(Dialog.Footer, { dataTestId: `${dataTestId}-footer`, children: [jsx(Dialog.Close, { asChild: true, children: jsx(Button, { color: "red", dataTestId: `${dataTestId}-cancel-button`, children: cancelLabel !== null && cancelLabel !== void 0 ? cancelLabel : 'Cancel' }) }), jsx(Button, { color: "green", onClick: preFinish, dataTestId: `${dataTestId}-submit-button`, children: submitLabel !== null && submitLabel !== void 0 ? submitLabel : 'Submit' })] })] }) }));
1795
+ return (jsx(Dialog, { open: open, onOpenChange: (value) => !value && onClose(), children: jsxs(Dialog.Content, { className: className, onPointerDownOutside: (event) => event.preventDefault(), dataTestId: `${dataTestId}-content`, children: [jsx(Dialog.Header, { dataTestId: `${dataTestId}-header`, children: jsx(Dialog.Title, { dataTestId: `${dataTestId}-title`, children: title }) }), jsx(ListSorter, { className: "divide-y overflow-auto rounded-lg border dark:divide-slate-700 dark:border-slate-700 dark:text-white", items: sortedItems, idResolver: idResolver, renderer: customRenderer, onChange: setSortedItems, dataTestId: `${dataTestId}-sorter` }), jsxs(Dialog.Footer, { dataTestId: `${dataTestId}-footer`, children: [jsx(Dialog.Close, { asChild: true, children: jsx(Button, { color: "red", disabled: loading, dataTestId: `${dataTestId}-cancel-button`, children: cancelLabel !== null && cancelLabel !== void 0 ? cancelLabel : 'Cancel' }) }), jsx(Button, { color: "green", loading: loading, onClick: handleSubmit, dataTestId: `${dataTestId}-submit-button`, children: submitLabel !== null && submitLabel !== void 0 ? submitLabel : 'Submit' })] })] }) }));
1783
1796
  }
1784
1797
 
1785
1798
  const PdfViewerDialog = ({ open, title, url, data, onClose, dataTestId = 'pdf-viewer-dialog', }) => {
@@ -1835,7 +1848,15 @@ const SidebarContextProvider = (_a) => {
1835
1848
  return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open);
1836
1849
  }, [isMobile, setOpen, setOpenMobile]);
1837
1850
  // Add swipe gesture support for opening and closing the sidebar.
1838
- useOnSwipe(screenRef, (direction) => direction === 'right' ? setOpen(true) : direction === 'left' && setOpen(false));
1851
+ useOnSwipe(screenRef, (direction) => {
1852
+ const _setOpen = isMobile ? setOpenMobile : setOpen;
1853
+ if (direction === 'right') {
1854
+ _setOpen(true);
1855
+ }
1856
+ else if (direction === 'left') {
1857
+ _setOpen(false);
1858
+ }
1859
+ });
1839
1860
  // Adds a keyboard shortcut to toggle the sidebar.
1840
1861
  useEffect(() => {
1841
1862
  const handleKeyDown = (event) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tw-react-components",
3
3
  "description": "A set of React components build with TailwindCSS to make a nice dashboard.",
4
- "version": "0.0.173",
4
+ "version": "0.0.175",
5
5
  "license": "MIT",
6
6
  "homepage": "https://bacali95.github.io/tw-react-components",
7
7
  "type": "module",
@@ -7,6 +7,7 @@ export type ButtonProps = ComponentProps<'button'> & {
7
7
  color?: Color;
8
8
  variant?: ButtonVariant;
9
9
  rounded?: boolean;
10
+ loading?: boolean;
10
11
  prefixIcon?: LucideIcon;
11
12
  suffixIcon?: LucideIcon;
12
13
  unstyled?: boolean;
@@ -1,10 +1,10 @@
1
- import type { FC, PropsWithChildren, ReactNode } from 'react';
1
+ import { type FC, type PropsWithChildren, type ReactNode } from 'react';
2
2
  type Props = {
3
3
  open: boolean;
4
4
  title: ReactNode;
5
5
  yesLabel?: string;
6
6
  noLabel?: string;
7
- onConfirm: () => void;
7
+ onConfirm: () => void | Promise<void>;
8
8
  onClose: () => void;
9
9
  dataTestId?: string;
10
10
  };
@@ -8,6 +8,6 @@ export type ListSorterDialogProps<T extends ListSorterItem> = {
8
8
  } & Omit<ListSorterProps<T>, 'onChange'> & {
9
9
  cancelLabel?: string;
10
10
  submitLabel?: string;
11
- onSubmit: (items: T[]) => void;
11
+ onSubmit: (items: T[]) => void | Promise<void>;
12
12
  };
13
13
  export declare function ListSorterDialog<T extends ListSorterItem>({ className, open, title, items, idResolver, renderer, cancelLabel, submitLabel, onSubmit, onClose, dataTestId, }: ListSorterDialogProps<T>): import("react/jsx-runtime").JSX.Element;