@classytic/fluid 0.3.6 → 0.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.
@@ -1,7 +1,7 @@
1
1
  import { n as ApiPaginationData, r as ApiPaginationProps, t as ApiPagination } from "../api-pagination-CJ0vR_w6.mjs";
2
2
  import * as react_jsx_runtime0 from "react/jsx-runtime";
3
3
  import * as react from "react";
4
- import { ComponentType, ElementType, HTMLAttributes, ReactNode, RefObject } from "react";
4
+ import { ComponentPropsWithoutRef, ComponentType, ElementType, HTMLAttributes, ReactNode, RefObject } from "react";
5
5
  import { LucideIcon, LucideProps } from "lucide-react";
6
6
  import { VariantProps } from "class-variance-authority";
7
7
  import * as class_variance_authority_types0 from "class-variance-authority/types";
@@ -1186,32 +1186,28 @@ declare function SimpleTable({
1186
1186
  }: SimpleTableProps): react_jsx_runtime0.JSX.Element;
1187
1187
  //#endregion
1188
1188
  //#region src/components/tabs-wrapper.d.ts
1189
- interface TabsWrapperProps {
1189
+ type TabPreset = "default" | "line";
1190
+ interface TabsWrapperProps extends Omit<ComponentPropsWithoutRef<"div">, "defaultValue" | "dir"> {
1190
1191
  defaultValue?: string;
1191
1192
  value?: string;
1192
1193
  onValueChange?: (value: string) => void;
1193
- children: ReactNode;
1194
- className?: string;
1194
+ /** Elements rendered inside TabsList. */
1195
+ triggers: ReactNode;
1195
1196
  listClassName?: string;
1196
- variant?: "default" | "primary" | "secondary" | "outline" | "ghost" | "underline";
1197
+ preset?: TabPreset;
1198
+ fullWidth?: boolean;
1197
1199
  orientation?: "horizontal" | "vertical";
1198
1200
  layout?: "default" | "flex" | "sidebar";
1199
1201
  }
1200
1202
  declare const TabsWrapper: react.NamedExoticComponent<TabsWrapperProps>;
1201
- interface TabTriggerProps {
1203
+ interface TabTriggerProps extends Omit<ComponentPropsWithoutRef<"button">, "value"> {
1202
1204
  value: string;
1203
- children: ReactNode;
1204
- className?: string;
1205
- variant?: "default" | "primary" | "secondary" | "outline" | "ghost" | "underline";
1206
1205
  icon?: ReactNode;
1207
1206
  hideTextOnMobile?: boolean;
1208
- disabled?: boolean;
1209
1207
  }
1210
1208
  declare const TabTrigger: react.NamedExoticComponent<TabTriggerProps>;
1211
- interface TabContentProps {
1209
+ interface TabContentProps extends Omit<ComponentPropsWithoutRef<"div">, "value"> {
1212
1210
  value: string;
1213
- children: ReactNode;
1214
- className?: string;
1215
1211
  withScrollArea?: boolean;
1216
1212
  scrollAreaClassName?: string;
1217
1213
  padding?: boolean;
@@ -1226,16 +1222,16 @@ interface DynamicTabItem {
1226
1222
  disabled?: boolean;
1227
1223
  hideTextOnMobile?: boolean;
1228
1224
  }
1229
- interface DynamicTabsProps {
1225
+ interface DynamicTabsProps extends Omit<ComponentPropsWithoutRef<"div">, "defaultValue" | "dir"> {
1230
1226
  tabs?: DynamicTabItem[];
1231
1227
  defaultValue?: string;
1232
1228
  value?: string;
1233
1229
  onValueChange?: (value: string) => void;
1234
- variant?: "default" | "primary" | "secondary" | "outline" | "ghost" | "underline";
1230
+ preset?: TabPreset;
1231
+ fullWidth?: boolean;
1232
+ orientation?: "horizontal" | "vertical";
1235
1233
  layout?: "default" | "flex" | "sidebar";
1236
- className?: string;
1237
1234
  listClassName?: string;
1238
- listWrapperClassName?: string;
1239
1235
  contentClassName?: string;
1240
1236
  scrollable?: boolean;
1241
1237
  }
@@ -1611,4 +1607,4 @@ declare function AnimatedCounter({
1611
1607
  as
1612
1608
  }: AnimatedCounterProps): react.ReactElement<any, string | react.JSXElementConstructor<any>>;
1613
1609
  //#endregion
1614
- export { AccordionSection, type AccordionSectionProps, ActionDropdown, type ActionDropdownItem, type ActionDropdownProps, ActionTooltip, type ActionTooltipProps, type AnimateBaseProps, AnimatedCounter, type AnimatedCounterProps, AnimatedText, type AnimatedTextProps, type Animation, ApiPagination, type ApiPaginationData, type ApiPaginationProps, ButtonTooltip, type ButtonTooltipProps, CardWrapper, type CardWrapperProps, CheckboxDropdown, type CheckboxDropdownProps, ClientSubmitButton, type ClientSubmitButtonProps, CollapsibleCard, type CollapsibleCardProps, CollapsibleSection, type CollapsibleSectionProps, CollapsibleWrapper, type CollapsibleWrapperProps, ConfirmDialog, type ConfirmDialogProps, ConfirmSheet, type ConfirmSheetProps, CopyButton, type CopyButtonProps, CopyCodeBlock, type CopyCodeBlockProps, CopyText, type CopyTextProps, CustomPagination, type CustomPaginationProps, DEFAULT_COUNTRIES, DataCard, type DataCardProps, DeleteConfirmDialog, type DeleteConfirmDialogProps, DetailItem, type DetailItemProps, DetailView, type DetailViewItemData, type DetailViewProps, DialogWrapper, type DialogWrapperProps, type DragHandleProps, DraggableCard, type DraggableCardProps, DropdownWrapper, type DropdownWrapperProps, type DynamicTabItem, DynamicTabs, type DynamicTabsProps, ErrorState, ErrorStateInline, type ErrorStateInlineProps, type ErrorStateProps, FadeIn, FadeInUp, FaqAccordion, type FaqAccordionProps, type FaqItem, FeatureItem, type FeatureItemProps, FeatureList, type FeatureListItem, type FeatureListProps, FormDialog, type FormDialogProps, FormSheet, type FormSheetProps, IconItemMedia, type IconItemMediaProps, IconTooltip, type IconTooltipProps, InfoAlert, type InfoAlertProps, InfoRow, type InfoRowProps, InfoTooltip, type InfoTooltipProps, LoadingCard, type LoadingCardProps, PaginationInfo, type PaginationInfoProps, type PhoneCountry, PhoneInput, type PhoneInputProps, Pill, PillAvatar, PillAvatarGroup, type PillAvatarGroupProps, type PillAvatarProps, PillButton, type PillButtonProps, PillDelta, type PillDeltaProps, PillIcon, type PillIconProps, PillIndicator, type PillIndicatorProps, type PillProps, PillStatus, type PillStatusProps, RadioDropdown, type RadioDropdownProps, ResponsiveSplitLayout, type ResponsiveSplitLayoutProps, ScaleIn, SelectDropdown, type SelectDropdownOption, type SelectDropdownProps, SheetWrapper, type SheetWrapperProps, SimpleTable, type SimpleTableProps, type SlideDirection, SlideIn, type SlideInProps, StaggerChildren, type StaggerChildrenProps, StatsCard, type StatsCardProps, StatusBanner, type StatusBannerProps, type StatusBannerVariant, StepContent, type StepContentProps, Stepper, type StepperProps, type StepperStep, TabContent, type TabContentProps, TabTrigger, type TabTriggerProps, TableWrapper, type TableWrapperColumn, type TableWrapperEmptyState, type TableWrapperProps, TabsWrapper, type TabsWrapperProps, Thumbnail, type ThumbnailProps, Timeline, type TimelineItem, type TimelineProps, type TimelineStatus, TooltipWrapper, type TooltipWrapperProps, type UseInViewOptions, useInView };
1610
+ export { AccordionSection, type AccordionSectionProps, ActionDropdown, type ActionDropdownItem, type ActionDropdownProps, ActionTooltip, type ActionTooltipProps, type AnimateBaseProps, AnimatedCounter, type AnimatedCounterProps, AnimatedText, type AnimatedTextProps, type Animation, ApiPagination, type ApiPaginationData, type ApiPaginationProps, ButtonTooltip, type ButtonTooltipProps, CardWrapper, type CardWrapperProps, CheckboxDropdown, type CheckboxDropdownProps, ClientSubmitButton, type ClientSubmitButtonProps, CollapsibleCard, type CollapsibleCardProps, CollapsibleSection, type CollapsibleSectionProps, CollapsibleWrapper, type CollapsibleWrapperProps, ConfirmDialog, type ConfirmDialogProps, ConfirmSheet, type ConfirmSheetProps, CopyButton, type CopyButtonProps, CopyCodeBlock, type CopyCodeBlockProps, CopyText, type CopyTextProps, CustomPagination, type CustomPaginationProps, DEFAULT_COUNTRIES, DataCard, type DataCardProps, DeleteConfirmDialog, type DeleteConfirmDialogProps, DetailItem, type DetailItemProps, DetailView, type DetailViewItemData, type DetailViewProps, DialogWrapper, type DialogWrapperProps, type DragHandleProps, DraggableCard, type DraggableCardProps, DropdownWrapper, type DropdownWrapperProps, type DynamicTabItem, DynamicTabs, type DynamicTabsProps, ErrorState, ErrorStateInline, type ErrorStateInlineProps, type ErrorStateProps, FadeIn, FadeInUp, FaqAccordion, type FaqAccordionProps, type FaqItem, FeatureItem, type FeatureItemProps, FeatureList, type FeatureListItem, type FeatureListProps, FormDialog, type FormDialogProps, FormSheet, type FormSheetProps, IconItemMedia, type IconItemMediaProps, IconTooltip, type IconTooltipProps, InfoAlert, type InfoAlertProps, InfoRow, type InfoRowProps, InfoTooltip, type InfoTooltipProps, LoadingCard, type LoadingCardProps, PaginationInfo, type PaginationInfoProps, type PhoneCountry, PhoneInput, type PhoneInputProps, Pill, PillAvatar, PillAvatarGroup, type PillAvatarGroupProps, type PillAvatarProps, PillButton, type PillButtonProps, PillDelta, type PillDeltaProps, PillIcon, type PillIconProps, PillIndicator, type PillIndicatorProps, type PillProps, PillStatus, type PillStatusProps, RadioDropdown, type RadioDropdownProps, ResponsiveSplitLayout, type ResponsiveSplitLayoutProps, ScaleIn, SelectDropdown, type SelectDropdownOption, type SelectDropdownProps, SheetWrapper, type SheetWrapperProps, SimpleTable, type SimpleTableProps, type SlideDirection, SlideIn, type SlideInProps, StaggerChildren, type StaggerChildrenProps, StatsCard, type StatsCardProps, StatusBanner, type StatusBannerProps, type StatusBannerVariant, StepContent, type StepContentProps, Stepper, type StepperProps, type StepperStep, TabContent, type TabContentProps, type TabPreset, TabTrigger, type TabTriggerProps, TableWrapper, type TableWrapperColumn, type TableWrapperEmptyState, type TableWrapperProps, TabsWrapper, type TabsWrapperProps, Thumbnail, type ThumbnailProps, Timeline, type TimelineItem, type TimelineProps, type TimelineStatus, TooltipWrapper, type TooltipWrapperProps, type UseInViewOptions, useInView };
@@ -2,20 +2,19 @@
2
2
 
3
3
  import { t as cn } from "../utils-DQ5SCVoW.mjs";
4
4
  import { t as useMediaQuery } from "../use-media-query-BnVNIKT4.mjs";
5
- import { n as CustomPagination, r as PaginationInfo, t as ApiPagination } from "../api-pagination-DBTE0yk4.mjs";
5
+ import { a as SelectDropdown, c as PaginationInfo, i as RadioDropdown, n as CheckboxDropdown, o as ApiPagination, r as DropdownWrapper, s as CustomPagination, t as ActionDropdown } from "../dropdown-wrapper-B86u9Fri.mjs";
6
6
  import { i as ClientSubmitButton, n as FormSheet, r as SheetWrapper, t as ConfirmSheet } from "../sheet-wrapper-C13Y-Q6w.mjs";
7
7
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
8
8
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
9
9
  import * as React$1 from "react";
10
- import { Children, Fragment as Fragment$1, createElement, isValidElement, memo, useEffect, useMemo, useRef, useState } from "react";
11
- import { AlertCircle, AlertTriangle, ArrowLeft, ArrowRight, Check, CheckCircle2, ChevronDown, ChevronDownIcon, ChevronUp, ChevronUpIcon, Circle, Copy, Info, Loader2, MinusIcon, MoreHorizontal, RefreshCw, X } from "lucide-react";
10
+ import { Children, Fragment as Fragment$1, createContext, createElement, isValidElement, memo, use, useEffect, useMemo, useRef, useState } from "react";
11
+ import { AlertCircle, AlertTriangle, ArrowLeft, ArrowRight, Check, CheckCircle2, ChevronDown, ChevronDownIcon, ChevronUp, ChevronUpIcon, Circle, Copy, Info, Loader2, MinusIcon, RefreshCw, X } from "lucide-react";
12
12
  import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@/components/ui/accordion";
13
13
  import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card";
14
14
  import { Button } from "@/components/ui/button";
15
15
  import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
16
16
  import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "@/components/ui/alert-dialog";
17
17
  import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
18
- import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
19
18
  import { Alert, AlertDescription, AlertTitle } from "@/components/ui/alert";
20
19
  import { cva } from "class-variance-authority";
21
20
  import { Item, ItemContent, ItemDescription } from "@/components/ui/item";
@@ -642,170 +641,6 @@ function FormDialog({ open, onOpenChange, title, description, children, onSubmit
642
641
  });
643
642
  }
644
643
 
645
- //#endregion
646
- //#region src/components/dropdown-wrapper.tsx
647
- function DropdownWrapper({ trigger, children, align = "end", side = "bottom", sideOffset = 4, className, contentClassName, ...props }) {
648
- return /* @__PURE__ */ jsxs(DropdownMenu, {
649
- ...props,
650
- children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
651
- align,
652
- side,
653
- sideOffset,
654
- className: cn("min-w-[160px]", contentClassName),
655
- children
656
- })]
657
- });
658
- }
659
- function ActionDropdown({ items = [], triggerIcon: TriggerIcon = MoreHorizontal, triggerVariant = "ghost", triggerSize = "sm", triggerClassName, triggerLabel, showOnHover = false, align = "end", contentClassName, onOpenChange, stopPropagation = true, ...props }) {
660
- const handleTriggerClick = (e) => {
661
- if (stopPropagation) e.stopPropagation();
662
- };
663
- const trigger = /* @__PURE__ */ jsxs(Button, {
664
- variant: triggerVariant,
665
- size: triggerSize,
666
- onClick: handleTriggerClick,
667
- className: cn(showOnHover && "opacity-0 group-hover:opacity-100 transition-opacity", triggerClassName),
668
- children: [
669
- /* @__PURE__ */ jsx(TriggerIcon, { className: "h-4 w-4" }),
670
- triggerLabel && /* @__PURE__ */ jsx("span", {
671
- className: "ml-2",
672
- children: triggerLabel
673
- }),
674
- /* @__PURE__ */ jsx("span", {
675
- className: "sr-only",
676
- children: "Open menu"
677
- })
678
- ]
679
- });
680
- const handleItemClick = (item) => (e) => {
681
- if (stopPropagation) e.stopPropagation();
682
- item.onClick?.(e);
683
- };
684
- return /* @__PURE__ */ jsxs(DropdownMenu, {
685
- onOpenChange,
686
- ...props,
687
- children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
688
- align,
689
- className: cn("min-w-[180px]", contentClassName),
690
- children: items.map((item, index) => {
691
- if (item.hidden) return null;
692
- if (item.type === "separator") return /* @__PURE__ */ jsx(DropdownMenuSeparator, {}, item.key || `separator-${index}`);
693
- if (item.type === "label") return /* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsx(DropdownMenuLabel, {
694
- className: item.className,
695
- children: item.label
696
- }) }, item.key || `label-${index}`);
697
- if (item.type === "group") return /* @__PURE__ */ jsx(DropdownMenuGroup, { children: item.items?.map((groupItem, groupIndex) => {
698
- if (groupItem.hidden) return null;
699
- const GroupItemIcon = groupItem.icon;
700
- const groupItemLabel = typeof groupItem.label === "function" ? groupItem.label() : groupItem.label;
701
- return /* @__PURE__ */ jsxs(DropdownMenuItem, {
702
- onClick: handleItemClick(groupItem),
703
- disabled: groupItem.disabled,
704
- className: cn(groupItem.variant === "destructive" && "text-destructive focus:text-destructive", groupItem.className),
705
- children: [
706
- GroupItemIcon && /* @__PURE__ */ jsx(GroupItemIcon, { className: "h-4 w-4" }),
707
- /* @__PURE__ */ jsx("span", { children: groupItemLabel }),
708
- groupItem.shortcut && /* @__PURE__ */ jsx("span", {
709
- className: "ml-auto text-xs tracking-widest text-muted-foreground",
710
- children: groupItem.shortcut
711
- })
712
- ]
713
- }, groupItem.key || `group-item-${groupIndex}`);
714
- }) }, item.key || `group-${index}`);
715
- const ItemIcon = item.icon;
716
- const displayLabel = typeof item.label === "function" ? item.label() : item.label;
717
- return /* @__PURE__ */ jsxs(DropdownMenuItem, {
718
- onClick: handleItemClick(item),
719
- disabled: item.disabled,
720
- className: cn(item.variant === "destructive" && "text-destructive focus:text-destructive", item.className),
721
- children: [
722
- ItemIcon && /* @__PURE__ */ jsx(ItemIcon, { className: "h-4 w-4" }),
723
- /* @__PURE__ */ jsx("span", { children: displayLabel }),
724
- item.shortcut && /* @__PURE__ */ jsx("span", {
725
- className: "ml-auto text-xs tracking-widest text-muted-foreground",
726
- children: item.shortcut
727
- })
728
- ]
729
- }, item.key || `item-${index}`);
730
- })
731
- })]
732
- });
733
- }
734
- function SelectDropdown({ value, onValueChange, placeholder = "Select option...", options = [], triggerClassName, contentClassName, disabled = false, ...props }) {
735
- const selectedOption = options.find((option) => option.value === value);
736
- const trigger = /* @__PURE__ */ jsxs(Button, {
737
- variant: "outline",
738
- disabled,
739
- className: cn("w-full justify-between", !selectedOption && "text-muted-foreground", triggerClassName),
740
- children: [selectedOption ? selectedOption.label : placeholder, /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
741
- });
742
- return /* @__PURE__ */ jsxs(DropdownMenu, {
743
- ...props,
744
- children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
745
- align: "start",
746
- className: cn("w-full min-w-(--anchor-width)", contentClassName),
747
- children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
748
- onClick: () => onValueChange?.(option.value),
749
- className: cn("cursor-pointer", value === option.value && "bg-accent"),
750
- children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
751
- }, option.value))
752
- })]
753
- });
754
- }
755
- function CheckboxDropdown({ values = [], onValuesChange, placeholder = "Select options...", options = [], triggerClassName, contentClassName, disabled = false, showSelectedCount = true, ...props }) {
756
- const selectedOptions = options.filter((option) => values.includes(option.value));
757
- const displayText = selectedOptions.length > 0 ? showSelectedCount ? `${selectedOptions.length} selected` : selectedOptions.map((opt) => opt.label).join(", ") : placeholder;
758
- const trigger = /* @__PURE__ */ jsxs(Button, {
759
- variant: "outline",
760
- disabled,
761
- className: cn("w-full justify-between", selectedOptions.length === 0 && "text-muted-foreground", triggerClassName),
762
- children: [/* @__PURE__ */ jsx("span", {
763
- className: "truncate",
764
- children: displayText
765
- }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
766
- });
767
- const handleCheckedChange = (optionValue, checked) => {
768
- if (checked) onValuesChange?.([...values, optionValue]);
769
- else onValuesChange?.(values.filter((value) => value !== optionValue));
770
- };
771
- return /* @__PURE__ */ jsxs(DropdownMenu, {
772
- ...props,
773
- children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
774
- align: "start",
775
- className: cn("w-full min-w-(--anchor-width)", contentClassName),
776
- children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuCheckboxItem, {
777
- checked: values.includes(option.value),
778
- onCheckedChange: (checked) => handleCheckedChange(option.value, checked),
779
- children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
780
- }, option.value))
781
- })]
782
- });
783
- }
784
- function RadioDropdown({ value, onValueChange, placeholder = "Select option...", options = [], triggerClassName, contentClassName, disabled = false, ...props }) {
785
- const selectedOption = options.find((option) => option.value === value);
786
- const trigger = /* @__PURE__ */ jsxs(Button, {
787
- variant: "outline",
788
- disabled,
789
- className: cn("w-full justify-between", !selectedOption && "text-muted-foreground", triggerClassName),
790
- children: [selectedOption ? selectedOption.label : placeholder, /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
791
- });
792
- return /* @__PURE__ */ jsxs(DropdownMenu, {
793
- ...props,
794
- children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
795
- align: "start",
796
- className: cn("w-full min-w-(--anchor-width)", contentClassName),
797
- children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
798
- value,
799
- onValueChange,
800
- children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuRadioItem, {
801
- value: option.value,
802
- children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
803
- }, option.value))
804
- })
805
- })]
806
- });
807
- }
808
-
809
644
  //#endregion
810
645
  //#region src/components/error-state.tsx
811
646
  /**
@@ -1481,58 +1316,73 @@ function PillAvatarGroup({ children, className, ...props }) {
1481
1316
 
1482
1317
  //#endregion
1483
1318
  //#region src/components/tabs-wrapper.tsx
1484
- const LIST_BASE_CLASS = "flex flex-wrap items-center justify-start gap-1 h-auto rounded-md p-1 shadow-sm transition-colors";
1485
- const LIST_VARIANTS = {
1486
- default: "border border-border/50 bg-muted/60 backdrop-blur-sm",
1487
- primary: "border border-primary/30 bg-primary/10",
1488
- secondary: "border border-secondary/40 bg-secondary/10",
1489
- outline: "border border-border bg-background",
1490
- ghost: "border border-transparent bg-transparent shadow-none",
1491
- underline: "w-full mb-4 rounded-none border-b border-border/60 bg-transparent p-0 shadow-none gap-6"
1319
+ const PRESET_VARIANT = {
1320
+ default: "default",
1321
+ line: "line"
1492
1322
  };
1493
- const TRIGGER_VARIANTS = {
1494
- default: "text-muted-foreground hover:bg-muted/40 hover:text-foreground data-active:bg-background data-active:text-foreground data-active:shadow-sm",
1495
- primary: "text-primary hover:bg-primary/10 hover:text-primary data-active:bg-primary data-active:text-primary-foreground",
1496
- secondary: "text-secondary-foreground hover:bg-secondary/10 hover:text-secondary-foreground data-active:bg-secondary data-active:text-secondary-foreground",
1497
- outline: "text-foreground hover:bg-accent/40 hover:text-accent-foreground data-active:bg-accent data-active:text-accent-foreground",
1498
- ghost: "text-muted-foreground hover:bg-muted/30 hover:text-foreground data-active:bg-muted data-active:text-foreground",
1499
- underline: "text-muted-foreground rounded-none px-0 py-2 hover:bg-transparent hover:text-primary border-b-2 border-transparent data-active:border-primary data-active:text-primary data-active:shadow-none"
1323
+ const PRESETS = {
1324
+ default: {
1325
+ list: "",
1326
+ trigger: ""
1327
+ },
1328
+ line: {
1329
+ list: [
1330
+ "justify-start p-0 shadow-none flex-nowrap",
1331
+ "group-data-horizontal/tabs:w-full group-data-horizontal/tabs:border-b group-data-horizontal/tabs:border-border/60 group-data-horizontal/tabs:gap-5 group-data-horizontal/tabs:h-auto",
1332
+ "group-data-vertical/tabs:border-r group-data-vertical/tabs:border-border/60 group-data-vertical/tabs:gap-1"
1333
+ ].join(" "),
1334
+ trigger: [
1335
+ "flex-initial",
1336
+ "group-data-horizontal/tabs:px-2 group-data-horizontal/tabs:pb-2.5 group-data-horizontal/tabs:pt-1.5",
1337
+ "group-data-vertical/tabs:py-2 group-data-vertical/tabs:px-3",
1338
+ "after:bg-primary",
1339
+ "data-active:text-primary",
1340
+ "dark:data-active:text-primary"
1341
+ ].join(" ")
1342
+ }
1500
1343
  };
1501
- const TabsWrapper = memo(function TabsWrapper({ defaultValue, value, onValueChange, children, className, listClassName, variant = "default", orientation = "horizontal", layout = "default", ...props }) {
1502
- const isFlexLayout = useMemo(() => layout === "flex" || layout === "sidebar", [layout]);
1503
- const computedClasses = useMemo(() => ({
1504
- root: cn("w-full", isFlexLayout && "flex-1 flex flex-col", className),
1505
- list: cn(LIST_BASE_CLASS, isFlexLayout ? "w-full" : "w-fit", !isFlexLayout && variant !== "underline" && "mb-6", LIST_VARIANTS[variant] ?? LIST_VARIANTS.default, listClassName)
1506
- }), [
1507
- isFlexLayout,
1508
- className,
1509
- variant,
1344
+ const TabPresetContext = createContext({
1345
+ preset: "default",
1346
+ fullWidth: false
1347
+ });
1348
+ const TabsWrapper = memo(function TabsWrapper({ defaultValue, value, onValueChange, children, className, triggers, listClassName, preset = "default", fullWidth = false, orientation = "horizontal", layout = "default", ...props }) {
1349
+ const isFlexLayout = layout === "flex" || layout === "sidebar";
1350
+ const rootClassName = useMemo(() => cn("w-full", isFlexLayout && "flex-1 min-h-0", className), [isFlexLayout, className]);
1351
+ const listClass = useMemo(() => cn(PRESETS[preset].list, fullWidth && "w-full", listClassName), [
1352
+ preset,
1353
+ fullWidth,
1510
1354
  listClassName
1511
1355
  ]);
1512
- const triggers = [];
1513
- const panels = [];
1514
- Children.forEach(children, (child) => {
1515
- if (isValidElement(child) && child.type === TabContent) panels.push(child);
1516
- else triggers.push(child);
1517
- });
1518
- return /* @__PURE__ */ jsxs(Tabs, {
1519
- defaultValue,
1520
- value,
1521
- onValueChange,
1522
- orientation,
1523
- className: computedClasses.root,
1524
- ...props,
1525
- children: [/* @__PURE__ */ jsx(TabsList, {
1526
- className: computedClasses.list,
1527
- children: triggers
1528
- }), panels]
1356
+ return /* @__PURE__ */ jsx(TabPresetContext, {
1357
+ value: {
1358
+ preset,
1359
+ fullWidth
1360
+ },
1361
+ children: /* @__PURE__ */ jsxs(Tabs, {
1362
+ defaultValue,
1363
+ value,
1364
+ onValueChange,
1365
+ orientation,
1366
+ className: rootClassName,
1367
+ ...props,
1368
+ children: [/* @__PURE__ */ jsx(TabsList, {
1369
+ variant: PRESET_VARIANT[preset],
1370
+ className: listClass,
1371
+ children: triggers
1372
+ }), children]
1373
+ })
1529
1374
  });
1530
1375
  });
1531
- const TabTrigger = memo(function TabTrigger({ value, children, className, variant = "default", icon, hideTextOnMobile = false, disabled = false, ...props }) {
1376
+ const TabTrigger = memo(function TabTrigger({ value, children, className, icon, hideTextOnMobile = false, disabled = false, ...props }) {
1377
+ const { preset, fullWidth } = use(TabPresetContext);
1532
1378
  return /* @__PURE__ */ jsxs(TabsTrigger, {
1533
1379
  value,
1534
1380
  disabled,
1535
- className: useMemo(() => cn("flex items-center gap-2 transition-colors duration-200", TRIGGER_VARIANTS[variant] ?? TRIGGER_VARIANTS.default, className), [variant, className]),
1381
+ className: useMemo(() => cn(PRESETS[preset].trigger, fullWidth && "flex-1", className), [
1382
+ preset,
1383
+ fullWidth,
1384
+ className
1385
+ ]),
1536
1386
  ...props,
1537
1387
  children: [icon, hideTextOnMobile ? /* @__PURE__ */ jsx("span", {
1538
1388
  className: "hidden sm:inline",
@@ -1561,77 +1411,52 @@ const TabContent = memo(function TabContent({ value, children, className, withSc
1561
1411
  }) : children
1562
1412
  });
1563
1413
  });
1564
- const DynamicTabs = memo(function DynamicTabs({ tabs = [], defaultValue, value, onValueChange, variant = "default", layout = "default", className, listClassName, listWrapperClassName, contentClassName, scrollable = false, ...props }) {
1565
- const isFlexLayout = useMemo(() => layout === "flex" || layout === "sidebar", [layout]);
1566
- const useSheetDefaults = isFlexLayout && scrollable;
1567
- const computedClasses = useMemo(() => ({
1568
- root: cn("w-full", isFlexLayout && "flex-1 flex flex-col min-h-0", className),
1569
- listWrapper: cn("w-full", useSheetDefaults ? "px-0" : "px-6", listWrapperClassName),
1570
- flexList: cn("flex flex-wrap items-center justify-center gap-1 h-auto", variant === "underline" ? "rounded-none border-b border-border/60 bg-transparent p-0 shadow-none gap-6" : "rounded-md p-1 shadow-sm backdrop-blur-sm", LIST_VARIANTS[variant] ?? LIST_VARIANTS.default, useSheetDefaults && "mb-4 gap-0.5", listClassName),
1571
- standardList: cn(LIST_BASE_CLASS, variant !== "underline" && "w-fit mb-6", LIST_VARIANTS[variant] ?? LIST_VARIANTS.default, listClassName),
1572
- contentWrapper: cn(isFlexLayout && "flex-1 min-h-0 overflow-hidden"),
1573
- flexContent: cn("mt-0 h-full", useSheetDefaults && "px-1", contentClassName),
1574
- standardContent: cn(isFlexLayout ? "h-full" : "space-y-4 mt-6", contentClassName)
1575
- }), [
1414
+ const DynamicTabs = memo(function DynamicTabs({ tabs = [], defaultValue, value, onValueChange, preset = "default", fullWidth = false, orientation = "horizontal", layout = "default", className, listClassName, contentClassName, scrollable = false, ...props }) {
1415
+ const isFlexLayout = layout === "flex" || layout === "sidebar";
1416
+ const rootClassName = useMemo(() => cn("w-full", isFlexLayout && "flex-1 min-h-0", className), [isFlexLayout, className]);
1417
+ const listClass = useMemo(() => cn(PRESETS[preset].list, fullWidth && "w-full", isFlexLayout && "justify-center", listClassName), [
1418
+ preset,
1419
+ fullWidth,
1576
1420
  isFlexLayout,
1577
- useSheetDefaults,
1578
- className,
1579
- listWrapperClassName,
1580
- listClassName,
1581
- variant,
1582
- contentClassName
1421
+ listClassName
1583
1422
  ]);
1584
- return /* @__PURE__ */ jsxs(Tabs, {
1585
- defaultValue,
1586
- value,
1587
- onValueChange,
1588
- className: computedClasses.root,
1589
- ...props,
1590
- children: [isFlexLayout ? /* @__PURE__ */ jsx("div", {
1591
- className: computedClasses.listWrapper,
1592
- children: /* @__PURE__ */ jsx(TabsList, {
1593
- className: computedClasses.flexList,
1594
- children: tabs.map((tab) => /* @__PURE__ */ jsxs(TabTrigger, {
1423
+ const contentClass = useMemo(() => cn(isFlexLayout ? "mt-0 h-full" : "space-y-4 mt-6", contentClassName), [isFlexLayout, contentClassName]);
1424
+ const content = isFlexLayout && scrollable ? /* @__PURE__ */ jsx(ScrollArea, {
1425
+ className: "h-full w-full flex-1 min-h-0",
1426
+ children: tabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, {
1427
+ value: tab.value,
1428
+ className: contentClass,
1429
+ children: tab.content
1430
+ }, tab.value))
1431
+ }) : tabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, {
1432
+ value: tab.value,
1433
+ className: contentClass,
1434
+ children: tab.content
1435
+ }, tab.value));
1436
+ return /* @__PURE__ */ jsx(TabPresetContext, {
1437
+ value: {
1438
+ preset,
1439
+ fullWidth
1440
+ },
1441
+ children: /* @__PURE__ */ jsxs(Tabs, {
1442
+ defaultValue,
1443
+ value,
1444
+ onValueChange,
1445
+ orientation,
1446
+ className: rootClassName,
1447
+ ...props,
1448
+ children: [/* @__PURE__ */ jsx(TabsList, {
1449
+ variant: PRESET_VARIANT[preset],
1450
+ className: listClass,
1451
+ children: tabs.map((tab) => /* @__PURE__ */ jsx(TabTrigger, {
1595
1452
  value: tab.value,
1596
- variant,
1597
1453
  disabled: tab.disabled,
1598
- className: "justify-center px-3 py-2 text-xs sm:text-sm shrink-0",
1599
- children: [tab.icon, tab.hideTextOnMobile ? /* @__PURE__ */ jsx("span", {
1600
- className: "hidden sm:inline",
1601
- children: tab.label
1602
- }) : tab.label]
1603
- }, tab.value))
1604
- })
1605
- }) : /* @__PURE__ */ jsx(TabsList, {
1606
- className: computedClasses.standardList,
1607
- children: tabs.map((tab) => /* @__PURE__ */ jsxs(TabTrigger, {
1608
- value: tab.value,
1609
- variant,
1610
- disabled: tab.disabled,
1611
- className: "whitespace-nowrap",
1612
- children: [tab.icon, tab.hideTextOnMobile ? /* @__PURE__ */ jsx("span", {
1613
- className: "hidden sm:inline text-sm",
1614
- children: tab.label
1615
- }) : /* @__PURE__ */ jsx("span", {
1616
- className: "text-sm",
1454
+ icon: tab.icon,
1455
+ hideTextOnMobile: tab.hideTextOnMobile,
1617
1456
  children: tab.label
1618
- })]
1619
- }, tab.value))
1620
- }), /* @__PURE__ */ jsx("div", {
1621
- className: computedClasses.contentWrapper,
1622
- children: isFlexLayout && scrollable ? /* @__PURE__ */ jsx(ScrollArea, {
1623
- className: "h-full w-full",
1624
- children: tabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, {
1625
- value: tab.value,
1626
- className: computedClasses.flexContent,
1627
- children: tab.content
1628
1457
  }, tab.value))
1629
- }) : tabs.map((tab) => /* @__PURE__ */ jsx(TabsContent, {
1630
- value: tab.value,
1631
- className: computedClasses.standardContent,
1632
- children: tab.content
1633
- }, tab.value))
1634
- })]
1458
+ }), content]
1459
+ })
1635
1460
  });
1636
1461
  });
1637
1462
 
@@ -1684,10 +1509,11 @@ function ResponsiveSplitLayout({ leftPanel, rightPanel, className, leftPanelClas
1684
1509
  defaultValue: "left",
1685
1510
  value: mobileView,
1686
1511
  onValueChange: (val) => setMobileView(val),
1687
- variant: "default",
1512
+ preset: "default",
1513
+ fullWidth: true,
1688
1514
  layout: "flex",
1689
1515
  className: "h-full",
1690
- listWrapperClassName: "px-4 py-2 flex-shrink-0",
1516
+ listClassName: "mx-3 mt-3 mb-1 flex-shrink-0",
1691
1517
  contentClassName: "mt-0 flex-1 min-h-0"
1692
1518
  })
1693
1519
  });
@@ -1761,7 +1587,7 @@ function ResponsiveSplitLayout({ leftPanel, rightPanel, className, leftPanelClas
1761
1587
  return /* @__PURE__ */ jsxs(ResizablePanelGroup, {
1762
1588
  direction: "horizontal",
1763
1589
  className: cn("h-full", className),
1764
- autoSaveId: persistLayoutKey,
1590
+ ...persistLayoutKey ? { autoSaveId: persistLayoutKey } : {},
1765
1591
  children: [
1766
1592
  /* @__PURE__ */ jsx(ResizablePanel, {
1767
1593
  defaultSize: defaultLayout[0],
@@ -1,7 +1,7 @@
1
1
  import { n as ApiPaginationData } from "../api-pagination-CJ0vR_w6.mjs";
2
2
  import * as react_jsx_runtime0 from "react/jsx-runtime";
3
- import React, { ReactNode } from "react";
4
- import { ColumnDef } from "@tanstack/react-table";
3
+ import React$1, { ReactNode } from "react";
4
+ import { ColumnDef, Table as TanstackTable, VisibilityState, VisibilityState as VisibilityState$1 } from "@tanstack/react-table";
5
5
 
6
6
  //#region src/components/data-table.d.ts
7
7
  interface DataTablePaginationProps extends Partial<ApiPaginationData> {
@@ -15,11 +15,15 @@ interface DataTableProps<TData, TValue> {
15
15
  enableSorting?: boolean;
16
16
  enableRowSelection?: boolean;
17
17
  onRowSelectionChange?: (selectedRows: TData[]) => void;
18
+ /** Controlled column visibility state. Keys are column IDs, values are booleans. */
19
+ columnVisibility?: VisibilityState$1;
20
+ /** Callback when column visibility changes. */
21
+ onColumnVisibilityChange?: (visibility: VisibilityState$1) => void;
18
22
  className?: string;
19
23
  /** Custom loading state renderer */
20
- loadingState?: React.ReactNode;
24
+ loadingState?: React$1.ReactNode;
21
25
  /** Custom empty state renderer */
22
- emptyState?: React.ReactNode;
26
+ emptyState?: React$1.ReactNode;
23
27
  }
24
28
  declare function DataTable<TData, TValue>({
25
29
  columns,
@@ -29,6 +33,8 @@ declare function DataTable<TData, TValue>({
29
33
  enableSorting,
30
34
  enableRowSelection,
31
35
  onRowSelectionChange,
36
+ columnVisibility: controlledVisibility,
37
+ onColumnVisibilityChange,
32
38
  className,
33
39
  loadingState: customLoadingState,
34
40
  emptyState: customEmptyState
@@ -81,4 +87,34 @@ declare function DataTableToolbar({
81
87
  showResultCount
82
88
  }: DataTableToolbarProps): react_jsx_runtime0.JSX.Element;
83
89
  //#endregion
84
- export { DataTable, type DataTablePaginationProps, type DataTableProps, DataTableToolbar, type DataTableToolbarProps };
90
+ //#region src/components/data-table-column-toggle.d.ts
91
+ interface ToggleableColumn {
92
+ /** Column ID (must match the column key used in VisibilityState) */
93
+ id: string;
94
+ /** Display name shown in the toggle list */
95
+ header: string;
96
+ }
97
+ interface DataTableColumnToggleProps {
98
+ /** List of columns that can be toggled. Derive from your ColumnDef array. */
99
+ columns: ToggleableColumn[];
100
+ /** Controlled visibility state. Keys are column IDs, values are booleans. */
101
+ columnVisibility: VisibilityState$1;
102
+ /** Callback when visibility changes. */
103
+ onColumnVisibilityChange: (visibility: VisibilityState$1) => void;
104
+ /** Custom trigger element. Defaults to a Settings2 icon button. */
105
+ trigger?: React.ReactNode;
106
+ /** Label shown at the top of the dropdown */
107
+ label?: string;
108
+ /** Additional className for the trigger button */
109
+ className?: string;
110
+ }
111
+ declare function DataTableColumnToggle({
112
+ columns,
113
+ columnVisibility,
114
+ onColumnVisibilityChange,
115
+ trigger,
116
+ label,
117
+ className
118
+ }: DataTableColumnToggleProps): react_jsx_runtime0.JSX.Element;
119
+ //#endregion
120
+ export { DataTable, DataTableColumnToggle, type DataTableColumnToggleProps, type DataTablePaginationProps, type DataTableProps, DataTableToolbar, type DataTableToolbarProps, type TanstackTable, type ToggleableColumn, type VisibilityState };
@@ -3,12 +3,12 @@
3
3
  import { t as cn } from "../utils-DQ5SCVoW.mjs";
4
4
  import { t as useIsMobile } from "../use-mobile-BX3SQVo2.mjs";
5
5
  import { t as useScrollDetection } from "../use-scroll-detection-CsgsQYvy.mjs";
6
- import { t as ApiPagination } from "../api-pagination-DBTE0yk4.mjs";
6
+ import { o as ApiPagination, r as DropdownWrapper } from "../dropdown-wrapper-B86u9Fri.mjs";
7
7
  import { n as useSearch } from "../search-context-DR7DBs7S.mjs";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
10
10
  import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
11
- import { ArrowDown, ArrowUp, ArrowUpDown, ChevronLeft, ChevronRight, Search, SlidersHorizontal, X } from "lucide-react";
11
+ import { ArrowDown, ArrowUp, ArrowUpDown, ChevronLeft, ChevronRight, Search, Settings2, SlidersHorizontal, X } from "lucide-react";
12
12
  import { Button } from "@/components/ui/button";
13
13
  import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
14
14
  import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
@@ -16,6 +16,7 @@ import { Badge } from "@/components/ui/badge";
16
16
  import { Sheet, SheetContent, SheetHeader, SheetTitle } from "@/components/ui/sheet";
17
17
  import { flexRender, getCoreRowModel, getSortedRowModel, useReactTable } from "@tanstack/react-table";
18
18
  import { Input } from "@/components/ui/input";
19
+ import { Checkbox } from "@/components/ui/checkbox";
19
20
 
20
21
  //#region src/components/data-table.tsx
21
22
  const ScrollButton = React.memo(function ScrollButton({ direction, onClick, visible, className }) {
@@ -34,11 +35,14 @@ const ScrollButton = React.memo(function ScrollButton({ direction, onClick, visi
34
35
  children: direction === "left" ? /* @__PURE__ */ jsx(ChevronLeft, { className: "size-5" }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-5" })
35
36
  });
36
37
  });
37
- function DataTable({ columns, data, isLoading = false, pagination, enableSorting = false, enableRowSelection = false, onRowSelectionChange, className, loadingState: customLoadingState, emptyState: customEmptyState }) {
38
+ function DataTable({ columns, data, isLoading = false, pagination, enableSorting = false, enableRowSelection = false, onRowSelectionChange, columnVisibility: controlledVisibility, onColumnVisibilityChange, className, loadingState: customLoadingState, emptyState: customEmptyState }) {
38
39
  const [sorting, setSorting] = useState([]);
39
40
  const [rowSelection, setRowSelection] = useState({});
41
+ const [internalVisibility, setInternalVisibility] = useState({});
40
42
  const scrollAreaRef = useRef(null);
41
43
  const { canScrollLeft, canScrollRight, isScrollable, checkScroll } = useScrollDetection(scrollAreaRef);
44
+ const visibility = controlledVisibility ?? internalVisibility;
45
+ const setVisibility = onColumnVisibilityChange ?? setInternalVisibility;
42
46
  const { total = 0, limit = 10, pages = 1, page = 1, hasNext = false, hasPrev = false, onPageChange = () => {} } = pagination ?? {};
43
47
  const table = useReactTable({
44
48
  data,
@@ -46,6 +50,9 @@ function DataTable({ columns, data, isLoading = false, pagination, enableSorting
46
50
  getCoreRowModel: getCoreRowModel(),
47
51
  getSortedRowModel: enableSorting ? getSortedRowModel() : void 0,
48
52
  onSortingChange: setSorting,
53
+ onColumnVisibilityChange: (updater) => {
54
+ setVisibility(typeof updater === "function" ? updater(visibility) : updater);
55
+ },
49
56
  onRowSelectionChange: enableRowSelection ? (updater) => {
50
57
  setRowSelection(updater);
51
58
  if (onRowSelectionChange) {
@@ -55,6 +62,7 @@ function DataTable({ columns, data, isLoading = false, pagination, enableSorting
55
62
  } : void 0,
56
63
  state: {
57
64
  sorting,
65
+ columnVisibility: visibility,
58
66
  rowSelection: enableRowSelection ? rowSelection : void 0
59
67
  },
60
68
  enableRowSelection
@@ -106,8 +114,9 @@ function DataTable({ columns, data, isLoading = false, pagination, enableSorting
106
114
  })]
107
115
  })
108
116
  }), []);
117
+ const visibleColumnCount = table.getVisibleLeafColumns().length;
109
118
  const defaultEmptyState = useMemo(() => /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
110
- colSpan: columns.length,
119
+ colSpan: visibleColumnCount,
111
120
  className: "h-32 text-center",
112
121
  children: /* @__PURE__ */ jsxs("div", {
113
122
  className: "flex flex-col items-center justify-center py-8",
@@ -126,7 +135,7 @@ function DataTable({ columns, data, isLoading = false, pagination, enableSorting
126
135
  })
127
136
  ]
128
137
  })
129
- }) }), [columns.length]);
138
+ }) }), [visibleColumnCount]);
130
139
  if (isLoading) return /* @__PURE__ */ jsx(Fragment, { children: customLoadingState || defaultLoadingState });
131
140
  return /* @__PURE__ */ jsxs("div", {
132
141
  className: cn("flex flex-col h-full gap-4", className),
@@ -159,7 +168,7 @@ function DataTable({ columns, data, isLoading = false, pagination, enableSorting
159
168
  children: flexRender(cell.column.columnDef.cell, cell.getContext())
160
169
  }, cell.id))
161
170
  }, row.id)) : customEmptyState ? /* @__PURE__ */ jsx(TableRow, { children: /* @__PURE__ */ jsx(TableCell, {
162
- colSpan: columns.length,
171
+ colSpan: visibleColumnCount,
163
172
  className: "h-32 text-center",
164
173
  children: customEmptyState
165
174
  }) }) : defaultEmptyState })] })
@@ -370,4 +379,42 @@ function DataTableToolbar({ children, className, showSearch = true, searchPlaceh
370
379
  }
371
380
 
372
381
  //#endregion
373
- export { DataTable, DataTableToolbar };
382
+ //#region src/components/data-table-column-toggle.tsx
383
+ function DataTableColumnToggle({ columns, columnVisibility, onColumnVisibilityChange, trigger, label = "Columns", className }) {
384
+ const defaultTrigger = /* @__PURE__ */ jsxs(Button, {
385
+ variant: "outline",
386
+ size: "sm",
387
+ className: cn("shrink-0", className),
388
+ children: [/* @__PURE__ */ jsx(Settings2, { className: "mr-2 h-4 w-4" }), label]
389
+ });
390
+ return /* @__PURE__ */ jsxs(DropdownWrapper, {
391
+ trigger: trigger ?? defaultTrigger,
392
+ contentClassName: "min-w-[150px]",
393
+ children: [
394
+ /* @__PURE__ */ jsx("div", {
395
+ className: "px-1.5 py-1 text-xs font-medium text-muted-foreground",
396
+ children: label
397
+ }),
398
+ /* @__PURE__ */ jsx("div", { className: "bg-border -mx-1 my-1 h-px" }),
399
+ columns.map((col) => {
400
+ const isVisible = columnVisibility[col.id] !== false;
401
+ return /* @__PURE__ */ jsxs("div", {
402
+ role: "menuitemcheckbox",
403
+ "aria-checked": isVisible,
404
+ className: "flex items-center gap-2 rounded-md px-2 py-1.5 text-sm cursor-pointer hover:bg-accent select-none",
405
+ onClick: () => onColumnVisibilityChange({
406
+ ...columnVisibility,
407
+ [col.id]: !isVisible
408
+ }),
409
+ children: [/* @__PURE__ */ jsx(Checkbox, {
410
+ checked: isVisible,
411
+ className: "pointer-events-none"
412
+ }), col.header]
413
+ }, col.id);
414
+ })
415
+ ]
416
+ });
417
+ }
418
+
419
+ //#endregion
420
+ export { DataTable, DataTableColumnToggle, DataTableToolbar };
@@ -0,0 +1,357 @@
1
+ import { t as cn } from "./utils-DQ5SCVoW.mjs";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { ChevronDown, MoreHorizontal } from "lucide-react";
5
+ import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
6
+ import { Button } from "@/components/ui/button";
7
+ import { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuTrigger } from "@/components/ui/dropdown-menu";
8
+
9
+ //#region src/components/custom-pagination.tsx
10
+ function CustomPagination({ page, onPageChange, pages, hasPrev, hasNext }) {
11
+ const [isMobile, setIsMobile] = useState(false);
12
+ const currentPageNum = Number(page);
13
+ useEffect(() => {
14
+ const checkMobile = () => {
15
+ setIsMobile(window.innerWidth < 640);
16
+ };
17
+ checkMobile();
18
+ window.addEventListener("resize", checkMobile);
19
+ return () => window.removeEventListener("resize", checkMobile);
20
+ }, []);
21
+ if (pages <= 1) return null;
22
+ const getPageNumbers = () => {
23
+ const delta = isMobile ? 1 : 2;
24
+ const range = [];
25
+ const rangeWithDots = [];
26
+ for (let i = Math.max(2, currentPageNum - delta); i <= Math.min(pages - 1, currentPageNum + delta); i++) range.push(i);
27
+ if (currentPageNum - delta > 2) rangeWithDots.push(1, "...");
28
+ else rangeWithDots.push(1);
29
+ rangeWithDots.push(...range);
30
+ if (currentPageNum + delta < pages - 1) rangeWithDots.push("...", pages);
31
+ else if (pages > 1) {
32
+ if (!range.includes(pages)) rangeWithDots.push(pages);
33
+ }
34
+ return [...new Set(rangeWithDots)];
35
+ };
36
+ if (isMobile && pages > 5) return /* @__PURE__ */ jsx(Pagination, {
37
+ className: "mx-0 w-auto",
38
+ children: /* @__PURE__ */ jsxs(PaginationContent, {
39
+ className: "gap-1",
40
+ children: [
41
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationPrevious, {
42
+ onClick: () => hasPrev ? onPageChange(currentPageNum - 1) : void 0,
43
+ className: cn("cursor-pointer transition-colors h-8 px-2 text-xs", !hasPrev && "pointer-events-none opacity-50 cursor-not-allowed", hasPrev && "hover:bg-accent hover:text-accent-foreground"),
44
+ "aria-disabled": !hasPrev
45
+ }) }),
46
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsxs("div", {
47
+ className: "flex h-8 items-center justify-center px-3 text-xs font-medium bg-primary text-primary-foreground rounded-md",
48
+ children: [
49
+ currentPageNum,
50
+ " / ",
51
+ pages
52
+ ]
53
+ }) }),
54
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationNext, {
55
+ onClick: () => hasNext ? onPageChange(currentPageNum + 1) : void 0,
56
+ className: cn("cursor-pointer transition-colors h-8 px-2 text-xs", !hasNext && "pointer-events-none opacity-50 cursor-not-allowed", hasNext && "hover:bg-accent hover:text-accent-foreground"),
57
+ "aria-disabled": !hasNext
58
+ }) })
59
+ ]
60
+ })
61
+ });
62
+ return /* @__PURE__ */ jsx(Pagination, {
63
+ className: "mx-0 w-auto",
64
+ children: /* @__PURE__ */ jsxs(PaginationContent, {
65
+ className: "gap-1 flex-wrap",
66
+ children: [
67
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationPrevious, {
68
+ onClick: () => hasPrev ? onPageChange(currentPageNum - 1) : void 0,
69
+ className: cn("cursor-pointer transition-colors", isMobile ? "h-8 px-2 text-xs" : "h-9 px-3 text-sm", !hasPrev && "pointer-events-none opacity-50 cursor-not-allowed", hasPrev && "hover:bg-accent hover:text-accent-foreground"),
70
+ "aria-disabled": !hasPrev
71
+ }) }),
72
+ getPageNumbers().map((pageNum, index) => /* @__PURE__ */ jsx(PaginationItem, { children: pageNum === "..." ? /* @__PURE__ */ jsx("span", {
73
+ className: cn("flex items-center justify-center text-muted-foreground", isMobile ? "h-8 w-8 text-xs" : "h-9 w-9 text-sm"),
74
+ children: "..."
75
+ }) : /* @__PURE__ */ jsx(PaginationLink, {
76
+ className: cn("cursor-pointer transition-colors", isMobile ? "h-8 w-8 text-xs p-0" : "h-9 w-9 text-sm p-0", "hover:bg-accent hover:text-accent-foreground", Number(currentPageNum) === Number(pageNum) && "bg-primary text-primary-foreground hover:bg-primary/90"),
77
+ onClick: () => typeof pageNum === "number" ? onPageChange(pageNum) : void 0,
78
+ isActive: Number(currentPageNum) === Number(pageNum),
79
+ "aria-label": `Go to page ${pageNum}`,
80
+ "aria-current": Number(currentPageNum) === Number(pageNum) ? "page" : void 0,
81
+ children: pageNum
82
+ }) }, `pagination-page-${pageNum}-${index}`)),
83
+ /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationNext, {
84
+ onClick: () => hasNext ? onPageChange(currentPageNum + 1) : void 0,
85
+ className: cn("cursor-pointer transition-colors", isMobile ? "h-8 px-2 text-xs" : "h-9 px-3 text-sm", !hasNext && "pointer-events-none opacity-50 cursor-not-allowed", hasNext && "hover:bg-accent hover:text-accent-foreground"),
86
+ "aria-disabled": !hasNext
87
+ }) })
88
+ ]
89
+ })
90
+ });
91
+ }
92
+ function PaginationInfo({ page, total, limit = 10 }) {
93
+ const [isMobile, setIsMobile] = useState(false);
94
+ useEffect(() => {
95
+ const checkMobile = () => {
96
+ setIsMobile(window.innerWidth < 640);
97
+ };
98
+ checkMobile();
99
+ window.addEventListener("resize", checkMobile);
100
+ return () => window.removeEventListener("resize", checkMobile);
101
+ }, []);
102
+ if (total === 0) return /* @__PURE__ */ jsx("div", {
103
+ className: "flex-1 text-sm text-muted-foreground",
104
+ children: /* @__PURE__ */ jsx("p", { children: "No entries found" })
105
+ });
106
+ const startEntry = (page - 1) * limit + 1;
107
+ const endEntry = Math.min(page * limit, total);
108
+ return /* @__PURE__ */ jsx("div", {
109
+ className: "flex-1 text-sm text-muted-foreground",
110
+ children: /* @__PURE__ */ jsx("p", {
111
+ className: cn("whitespace-nowrap", isMobile && "text-xs"),
112
+ children: isMobile ? /* @__PURE__ */ jsxs("span", { children: [
113
+ startEntry.toLocaleString(),
114
+ "-",
115
+ endEntry.toLocaleString(),
116
+ " of",
117
+ " ",
118
+ total.toLocaleString()
119
+ ] }) : /* @__PURE__ */ jsxs("span", { children: [
120
+ "Showing",
121
+ " ",
122
+ /* @__PURE__ */ jsx("span", {
123
+ className: "font-medium text-foreground",
124
+ children: startEntry.toLocaleString()
125
+ }),
126
+ " ",
127
+ "to",
128
+ " ",
129
+ /* @__PURE__ */ jsx("span", {
130
+ className: "font-medium text-foreground",
131
+ children: endEntry.toLocaleString()
132
+ }),
133
+ " ",
134
+ "of",
135
+ " ",
136
+ /* @__PURE__ */ jsx("span", {
137
+ className: "font-medium text-foreground",
138
+ children: total.toLocaleString()
139
+ }),
140
+ " ",
141
+ total === 1 ? "result" : "results"
142
+ ] })
143
+ })
144
+ });
145
+ }
146
+
147
+ //#endregion
148
+ //#region src/components/api-pagination.tsx
149
+ /**
150
+ * ApiPagination - A reusable pagination component for API-driven data
151
+ */
152
+ function ApiPagination({ total = 0, limit = 10, pages = 1, page = 1, hasNext = false, hasPrev = false, onPageChange = () => {}, className, showInfo = true, infoPosition = "left" }) {
153
+ const infoComponent = showInfo && /* @__PURE__ */ jsx("div", {
154
+ className: "shrink-0",
155
+ children: /* @__PURE__ */ jsx(PaginationInfo, {
156
+ total,
157
+ page,
158
+ limit
159
+ })
160
+ });
161
+ const paginationComponent = /* @__PURE__ */ jsx("div", {
162
+ className: "flex justify-center sm:justify-end",
163
+ children: /* @__PURE__ */ jsx(CustomPagination, {
164
+ page,
165
+ pages,
166
+ hasPrev,
167
+ hasNext,
168
+ onPageChange
169
+ })
170
+ });
171
+ return /* @__PURE__ */ jsx("div", {
172
+ className: cn("shrink-0 bg-muted/30 rounded-lg border border-border p-3 mb-2", className),
173
+ children: /* @__PURE__ */ jsx("div", {
174
+ className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4",
175
+ children: infoPosition === "left" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
176
+ className: "order-2 sm:order-1",
177
+ children: infoComponent
178
+ }), /* @__PURE__ */ jsx("div", {
179
+ className: "order-1 sm:order-2",
180
+ children: paginationComponent
181
+ })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
182
+ className: "order-1 sm:order-1",
183
+ children: paginationComponent
184
+ }), /* @__PURE__ */ jsx("div", {
185
+ className: "order-2 sm:order-2",
186
+ children: infoComponent
187
+ })] })
188
+ })
189
+ });
190
+ }
191
+
192
+ //#endregion
193
+ //#region src/components/dropdown-wrapper.tsx
194
+ function DropdownWrapper({ trigger, children, align = "end", side = "bottom", sideOffset = 4, className, contentClassName, ...props }) {
195
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
196
+ ...props,
197
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
198
+ align,
199
+ side,
200
+ sideOffset,
201
+ className: cn("min-w-[160px]", contentClassName),
202
+ children
203
+ })]
204
+ });
205
+ }
206
+ function ActionDropdown({ items = [], triggerIcon: TriggerIcon = MoreHorizontal, triggerVariant = "ghost", triggerSize = "sm", triggerClassName, triggerLabel, showOnHover = false, align = "end", contentClassName, onOpenChange, stopPropagation = true, ...props }) {
207
+ const handleTriggerClick = (e) => {
208
+ if (stopPropagation) e.stopPropagation();
209
+ };
210
+ const trigger = /* @__PURE__ */ jsxs(Button, {
211
+ variant: triggerVariant,
212
+ size: triggerSize,
213
+ onClick: handleTriggerClick,
214
+ className: cn(showOnHover && "opacity-0 group-hover:opacity-100 transition-opacity", triggerClassName),
215
+ children: [
216
+ /* @__PURE__ */ jsx(TriggerIcon, { className: "h-4 w-4" }),
217
+ triggerLabel && /* @__PURE__ */ jsx("span", {
218
+ className: "ml-2",
219
+ children: triggerLabel
220
+ }),
221
+ /* @__PURE__ */ jsx("span", {
222
+ className: "sr-only",
223
+ children: "Open menu"
224
+ })
225
+ ]
226
+ });
227
+ const handleItemClick = (item) => (e) => {
228
+ if (stopPropagation) e.stopPropagation();
229
+ item.onClick?.(e);
230
+ };
231
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
232
+ onOpenChange,
233
+ ...props,
234
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
235
+ align,
236
+ className: cn("min-w-[180px]", contentClassName),
237
+ children: items.map((item, index) => {
238
+ if (item.hidden) return null;
239
+ if (item.type === "separator") return /* @__PURE__ */ jsx(DropdownMenuSeparator, {}, item.key || `separator-${index}`);
240
+ if (item.type === "label") return /* @__PURE__ */ jsx(DropdownMenuGroup, { children: /* @__PURE__ */ jsx(DropdownMenuLabel, {
241
+ className: item.className,
242
+ children: item.label
243
+ }) }, item.key || `label-${index}`);
244
+ if (item.type === "group") return /* @__PURE__ */ jsx(DropdownMenuGroup, { children: item.items?.map((groupItem, groupIndex) => {
245
+ if (groupItem.hidden) return null;
246
+ const GroupItemIcon = groupItem.icon;
247
+ const groupItemLabel = typeof groupItem.label === "function" ? groupItem.label() : groupItem.label;
248
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
249
+ onClick: handleItemClick(groupItem),
250
+ disabled: groupItem.disabled,
251
+ className: cn(groupItem.variant === "destructive" && "text-destructive focus:text-destructive", groupItem.className),
252
+ children: [
253
+ GroupItemIcon && /* @__PURE__ */ jsx(GroupItemIcon, { className: "h-4 w-4" }),
254
+ /* @__PURE__ */ jsx("span", { children: groupItemLabel }),
255
+ groupItem.shortcut && /* @__PURE__ */ jsx("span", {
256
+ className: "ml-auto text-xs tracking-widest text-muted-foreground",
257
+ children: groupItem.shortcut
258
+ })
259
+ ]
260
+ }, groupItem.key || `group-item-${groupIndex}`);
261
+ }) }, item.key || `group-${index}`);
262
+ const ItemIcon = item.icon;
263
+ const displayLabel = typeof item.label === "function" ? item.label() : item.label;
264
+ return /* @__PURE__ */ jsxs(DropdownMenuItem, {
265
+ onClick: handleItemClick(item),
266
+ disabled: item.disabled,
267
+ className: cn(item.variant === "destructive" && "text-destructive focus:text-destructive", item.className),
268
+ children: [
269
+ ItemIcon && /* @__PURE__ */ jsx(ItemIcon, { className: "h-4 w-4" }),
270
+ /* @__PURE__ */ jsx("span", { children: displayLabel }),
271
+ item.shortcut && /* @__PURE__ */ jsx("span", {
272
+ className: "ml-auto text-xs tracking-widest text-muted-foreground",
273
+ children: item.shortcut
274
+ })
275
+ ]
276
+ }, item.key || `item-${index}`);
277
+ })
278
+ })]
279
+ });
280
+ }
281
+ function SelectDropdown({ value, onValueChange, placeholder = "Select option...", options = [], triggerClassName, contentClassName, disabled = false, ...props }) {
282
+ const selectedOption = options.find((option) => option.value === value);
283
+ const trigger = /* @__PURE__ */ jsxs(Button, {
284
+ variant: "outline",
285
+ disabled,
286
+ className: cn("w-full justify-between", !selectedOption && "text-muted-foreground", triggerClassName),
287
+ children: [selectedOption ? selectedOption.label : placeholder, /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
288
+ });
289
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
290
+ ...props,
291
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
292
+ align: "start",
293
+ className: cn("w-full min-w-(--anchor-width)", contentClassName),
294
+ children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuItem, {
295
+ onClick: () => onValueChange?.(option.value),
296
+ className: cn("cursor-pointer", value === option.value && "bg-accent"),
297
+ children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
298
+ }, option.value))
299
+ })]
300
+ });
301
+ }
302
+ function CheckboxDropdown({ values = [], onValuesChange, placeholder = "Select options...", options = [], triggerClassName, contentClassName, disabled = false, showSelectedCount = true, ...props }) {
303
+ const selectedOptions = options.filter((option) => values.includes(option.value));
304
+ const displayText = selectedOptions.length > 0 ? showSelectedCount ? `${selectedOptions.length} selected` : selectedOptions.map((opt) => opt.label).join(", ") : placeholder;
305
+ const trigger = /* @__PURE__ */ jsxs(Button, {
306
+ variant: "outline",
307
+ disabled,
308
+ className: cn("w-full justify-between", selectedOptions.length === 0 && "text-muted-foreground", triggerClassName),
309
+ children: [/* @__PURE__ */ jsx("span", {
310
+ className: "truncate",
311
+ children: displayText
312
+ }), /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
313
+ });
314
+ const handleCheckedChange = (optionValue, checked) => {
315
+ if (checked) onValuesChange?.([...values, optionValue]);
316
+ else onValuesChange?.(values.filter((value) => value !== optionValue));
317
+ };
318
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
319
+ ...props,
320
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
321
+ align: "start",
322
+ className: cn("w-full min-w-(--anchor-width)", contentClassName),
323
+ children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuCheckboxItem, {
324
+ checked: values.includes(option.value),
325
+ onCheckedChange: (checked) => handleCheckedChange(option.value, checked),
326
+ children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
327
+ }, option.value))
328
+ })]
329
+ });
330
+ }
331
+ function RadioDropdown({ value, onValueChange, placeholder = "Select option...", options = [], triggerClassName, contentClassName, disabled = false, ...props }) {
332
+ const selectedOption = options.find((option) => option.value === value);
333
+ const trigger = /* @__PURE__ */ jsxs(Button, {
334
+ variant: "outline",
335
+ disabled,
336
+ className: cn("w-full justify-between", !selectedOption && "text-muted-foreground", triggerClassName),
337
+ children: [selectedOption ? selectedOption.label : placeholder, /* @__PURE__ */ jsx(ChevronDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })]
338
+ });
339
+ return /* @__PURE__ */ jsxs(DropdownMenu, {
340
+ ...props,
341
+ children: [/* @__PURE__ */ jsx(DropdownMenuTrigger, { render: trigger }), /* @__PURE__ */ jsx(DropdownMenuContent, {
342
+ align: "start",
343
+ className: cn("w-full min-w-(--anchor-width)", contentClassName),
344
+ children: /* @__PURE__ */ jsx(DropdownMenuRadioGroup, {
345
+ value,
346
+ onValueChange,
347
+ children: options.map((option) => /* @__PURE__ */ jsxs(DropdownMenuRadioItem, {
348
+ value: option.value,
349
+ children: [option.icon && /* @__PURE__ */ jsx(option.icon, { className: "mr-2 h-4 w-4" }), option.label]
350
+ }, option.value))
351
+ })
352
+ })]
353
+ });
354
+ }
355
+
356
+ //#endregion
357
+ export { SelectDropdown as a, PaginationInfo as c, RadioDropdown as i, CheckboxDropdown as n, ApiPagination as o, DropdownWrapper as r, CustomPagination as s, ActionDropdown as t };
package/dist/forms.mjs CHANGED
@@ -12,12 +12,12 @@ import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput, InputGr
12
12
  import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
13
13
  import { Badge } from "@/components/ui/badge";
14
14
  import { Input } from "@/components/ui/input";
15
+ import { Checkbox } from "@/components/ui/checkbox";
15
16
  import { format, isValid, set } from "date-fns";
16
17
  import { Controller } from "react-hook-form";
17
18
  import { Field, FieldContent, FieldDescription, FieldError as FieldError$1, FieldLabel } from "@/components/ui/field";
18
19
  import { Textarea } from "@/components/ui/textarea";
19
20
  import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
20
- import { Checkbox } from "@/components/ui/checkbox";
21
21
  import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
22
22
  import { Switch } from "@/components/ui/switch";
23
23
  import { Calendar } from "@/components/ui/calendar";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@classytic/fluid",
3
- "version": "0.3.6",
3
+ "version": "0.4.0",
4
4
  "type": "module",
5
5
  "description": "Fluid UI - Custom components built on shadcn/ui and base ui by Classytic",
6
6
  "main": "./dist/index.mjs",
@@ -1,190 +0,0 @@
1
- import { t as cn } from "./utils-DQ5SCVoW.mjs";
2
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useState } from "react";
4
- import { Pagination, PaginationContent, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious } from "@/components/ui/pagination";
5
-
6
- //#region src/components/custom-pagination.tsx
7
- function CustomPagination({ page, onPageChange, pages, hasPrev, hasNext }) {
8
- const [isMobile, setIsMobile] = useState(false);
9
- const currentPageNum = Number(page);
10
- useEffect(() => {
11
- const checkMobile = () => {
12
- setIsMobile(window.innerWidth < 640);
13
- };
14
- checkMobile();
15
- window.addEventListener("resize", checkMobile);
16
- return () => window.removeEventListener("resize", checkMobile);
17
- }, []);
18
- if (pages <= 1) return null;
19
- const getPageNumbers = () => {
20
- const delta = isMobile ? 1 : 2;
21
- const range = [];
22
- const rangeWithDots = [];
23
- for (let i = Math.max(2, currentPageNum - delta); i <= Math.min(pages - 1, currentPageNum + delta); i++) range.push(i);
24
- if (currentPageNum - delta > 2) rangeWithDots.push(1, "...");
25
- else rangeWithDots.push(1);
26
- rangeWithDots.push(...range);
27
- if (currentPageNum + delta < pages - 1) rangeWithDots.push("...", pages);
28
- else if (pages > 1) {
29
- if (!range.includes(pages)) rangeWithDots.push(pages);
30
- }
31
- return [...new Set(rangeWithDots)];
32
- };
33
- if (isMobile && pages > 5) return /* @__PURE__ */ jsx(Pagination, {
34
- className: "mx-0 w-auto",
35
- children: /* @__PURE__ */ jsxs(PaginationContent, {
36
- className: "gap-1",
37
- children: [
38
- /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationPrevious, {
39
- onClick: () => hasPrev ? onPageChange(currentPageNum - 1) : void 0,
40
- className: cn("cursor-pointer transition-colors h-8 px-2 text-xs", !hasPrev && "pointer-events-none opacity-50 cursor-not-allowed", hasPrev && "hover:bg-accent hover:text-accent-foreground"),
41
- "aria-disabled": !hasPrev
42
- }) }),
43
- /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsxs("div", {
44
- className: "flex h-8 items-center justify-center px-3 text-xs font-medium bg-primary text-primary-foreground rounded-md",
45
- children: [
46
- currentPageNum,
47
- " / ",
48
- pages
49
- ]
50
- }) }),
51
- /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationNext, {
52
- onClick: () => hasNext ? onPageChange(currentPageNum + 1) : void 0,
53
- className: cn("cursor-pointer transition-colors h-8 px-2 text-xs", !hasNext && "pointer-events-none opacity-50 cursor-not-allowed", hasNext && "hover:bg-accent hover:text-accent-foreground"),
54
- "aria-disabled": !hasNext
55
- }) })
56
- ]
57
- })
58
- });
59
- return /* @__PURE__ */ jsx(Pagination, {
60
- className: "mx-0 w-auto",
61
- children: /* @__PURE__ */ jsxs(PaginationContent, {
62
- className: "gap-1 flex-wrap",
63
- children: [
64
- /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationPrevious, {
65
- onClick: () => hasPrev ? onPageChange(currentPageNum - 1) : void 0,
66
- className: cn("cursor-pointer transition-colors", isMobile ? "h-8 px-2 text-xs" : "h-9 px-3 text-sm", !hasPrev && "pointer-events-none opacity-50 cursor-not-allowed", hasPrev && "hover:bg-accent hover:text-accent-foreground"),
67
- "aria-disabled": !hasPrev
68
- }) }),
69
- getPageNumbers().map((pageNum, index) => /* @__PURE__ */ jsx(PaginationItem, { children: pageNum === "..." ? /* @__PURE__ */ jsx("span", {
70
- className: cn("flex items-center justify-center text-muted-foreground", isMobile ? "h-8 w-8 text-xs" : "h-9 w-9 text-sm"),
71
- children: "..."
72
- }) : /* @__PURE__ */ jsx(PaginationLink, {
73
- className: cn("cursor-pointer transition-colors", isMobile ? "h-8 w-8 text-xs p-0" : "h-9 w-9 text-sm p-0", "hover:bg-accent hover:text-accent-foreground", Number(currentPageNum) === Number(pageNum) && "bg-primary text-primary-foreground hover:bg-primary/90"),
74
- onClick: () => typeof pageNum === "number" ? onPageChange(pageNum) : void 0,
75
- isActive: Number(currentPageNum) === Number(pageNum),
76
- "aria-label": `Go to page ${pageNum}`,
77
- "aria-current": Number(currentPageNum) === Number(pageNum) ? "page" : void 0,
78
- children: pageNum
79
- }) }, `pagination-page-${pageNum}-${index}`)),
80
- /* @__PURE__ */ jsx(PaginationItem, { children: /* @__PURE__ */ jsx(PaginationNext, {
81
- onClick: () => hasNext ? onPageChange(currentPageNum + 1) : void 0,
82
- className: cn("cursor-pointer transition-colors", isMobile ? "h-8 px-2 text-xs" : "h-9 px-3 text-sm", !hasNext && "pointer-events-none opacity-50 cursor-not-allowed", hasNext && "hover:bg-accent hover:text-accent-foreground"),
83
- "aria-disabled": !hasNext
84
- }) })
85
- ]
86
- })
87
- });
88
- }
89
- function PaginationInfo({ page, total, limit = 10 }) {
90
- const [isMobile, setIsMobile] = useState(false);
91
- useEffect(() => {
92
- const checkMobile = () => {
93
- setIsMobile(window.innerWidth < 640);
94
- };
95
- checkMobile();
96
- window.addEventListener("resize", checkMobile);
97
- return () => window.removeEventListener("resize", checkMobile);
98
- }, []);
99
- if (total === 0) return /* @__PURE__ */ jsx("div", {
100
- className: "flex-1 text-sm text-muted-foreground",
101
- children: /* @__PURE__ */ jsx("p", { children: "No entries found" })
102
- });
103
- const startEntry = (page - 1) * limit + 1;
104
- const endEntry = Math.min(page * limit, total);
105
- return /* @__PURE__ */ jsx("div", {
106
- className: "flex-1 text-sm text-muted-foreground",
107
- children: /* @__PURE__ */ jsx("p", {
108
- className: cn("whitespace-nowrap", isMobile && "text-xs"),
109
- children: isMobile ? /* @__PURE__ */ jsxs("span", { children: [
110
- startEntry.toLocaleString(),
111
- "-",
112
- endEntry.toLocaleString(),
113
- " of",
114
- " ",
115
- total.toLocaleString()
116
- ] }) : /* @__PURE__ */ jsxs("span", { children: [
117
- "Showing",
118
- " ",
119
- /* @__PURE__ */ jsx("span", {
120
- className: "font-medium text-foreground",
121
- children: startEntry.toLocaleString()
122
- }),
123
- " ",
124
- "to",
125
- " ",
126
- /* @__PURE__ */ jsx("span", {
127
- className: "font-medium text-foreground",
128
- children: endEntry.toLocaleString()
129
- }),
130
- " ",
131
- "of",
132
- " ",
133
- /* @__PURE__ */ jsx("span", {
134
- className: "font-medium text-foreground",
135
- children: total.toLocaleString()
136
- }),
137
- " ",
138
- total === 1 ? "result" : "results"
139
- ] })
140
- })
141
- });
142
- }
143
-
144
- //#endregion
145
- //#region src/components/api-pagination.tsx
146
- /**
147
- * ApiPagination - A reusable pagination component for API-driven data
148
- */
149
- function ApiPagination({ total = 0, limit = 10, pages = 1, page = 1, hasNext = false, hasPrev = false, onPageChange = () => {}, className, showInfo = true, infoPosition = "left" }) {
150
- const infoComponent = showInfo && /* @__PURE__ */ jsx("div", {
151
- className: "shrink-0",
152
- children: /* @__PURE__ */ jsx(PaginationInfo, {
153
- total,
154
- page,
155
- limit
156
- })
157
- });
158
- const paginationComponent = /* @__PURE__ */ jsx("div", {
159
- className: "flex justify-center sm:justify-end",
160
- children: /* @__PURE__ */ jsx(CustomPagination, {
161
- page,
162
- pages,
163
- hasPrev,
164
- hasNext,
165
- onPageChange
166
- })
167
- });
168
- return /* @__PURE__ */ jsx("div", {
169
- className: cn("shrink-0 bg-muted/30 rounded-lg border border-border p-3 mb-2", className),
170
- children: /* @__PURE__ */ jsx("div", {
171
- className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between sm:gap-4",
172
- children: infoPosition === "left" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
173
- className: "order-2 sm:order-1",
174
- children: infoComponent
175
- }), /* @__PURE__ */ jsx("div", {
176
- className: "order-1 sm:order-2",
177
- children: paginationComponent
178
- })] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
179
- className: "order-1 sm:order-1",
180
- children: paginationComponent
181
- }), /* @__PURE__ */ jsx("div", {
182
- className: "order-2 sm:order-2",
183
- children: infoComponent
184
- })] })
185
- })
186
- });
187
- }
188
-
189
- //#endregion
190
- export { CustomPagination as n, PaginationInfo as r, ApiPagination as t };