UNPKG

@madulinux/react-datatable

Version:

Reusable DataTable component for React with sorting, paging, filter, and export.

419 lines (406 loc) 15.9 kB
import * as React from 'react'; import React__default from 'react'; import { ClassValue } from 'clsx'; interface DataTableColumn<T> { key: keyof T | string; label: string; sortable?: boolean; render?: (row: T) => React__default.ReactNode; width?: string | number; minWidth?: string | number; maxWidth?: string | number; visible?: boolean; pinned?: boolean; priority?: number; mobileLabel?: string; headerClassName?: string; cellClassName?: string; align?: 'left' | 'center' | 'right'; } interface DataTableFilter { key: string; label: string; options?: { value: string | number; label: string; }[]; customElement?: React__default.ReactNode; type?: 'select' | 'multiselect' | 'daterange' | 'date' | 'search' | 'number' | 'boolean' | 'text'; placeholder?: string; searchable?: boolean; width?: string | number; fetchOptions?: (params: { search: string; page: number; }) => Promise<{ data: { id: number | string; label: string; }[]; hasMore: boolean; }>; } interface DataTableAdvancedFilter { key: string; label: string; type: 'text' | 'select' | 'multiselect' | 'daterange' | 'date' | 'number' | 'boolean'; options?: { value: string | number; label: string; }[]; operators?: ('equals' | 'contains' | 'startsWith' | 'endsWith' | 'gt' | 'gte' | 'lt' | 'lte' | 'between' | 'in' | 'notIn')[]; defaultOperator?: string; placeholder?: string; searchable?: boolean; multiple?: boolean; } interface DataTableFilterRule { field: string; operator: string; value: string | number | boolean | string[] | number[] | [string | number, string | number]; condition?: 'AND' | 'OR'; } interface DataTableFilterGroup { rules: DataTableFilterRule[]; condition: 'AND' | 'OR'; groups?: DataTableFilterGroup[]; } interface DataTableExportConfig { enableExport?: boolean; exportFormats?: ('csv' | 'excel')[]; exportFileName?: string; exportAllData?: boolean; exportEndpoint?: string; } interface DataTableBulkAction<T> { label: string; icon?: React__default.ReactNode; action: (selectedRows: T[]) => void | Promise<void>; variant?: 'default' | 'destructive'; requiresConfirmation?: boolean; confirmationMessage?: string; } interface DataTableSelectionConfig<T> { enableRowSelection?: boolean; selectionMode?: 'single' | 'multiple'; bulkActions?: DataTableBulkAction<T>[]; onSelectionChange?: (selectedRows: T[]) => void; } interface DataTableHeaderConfig { showHeader?: boolean; stickyHeader?: boolean; headerClassName?: string; headerRowClassName?: string; headerHeight?: string | number; } interface DataTableResponsiveConfig { enableResponsive?: boolean; breakpoints?: { mobile: number; tablet: number; desktop: number; }; mobileStackedView?: boolean; priorityColumns?: string[]; hideColumnsOnMobile?: string[]; compactMode?: boolean; } interface DataTableLayoutConfig { toolbarLayout?: 'default' | 'compact' | 'stacked'; searchPosition?: 'left' | 'right' | 'full'; actionsPosition?: 'right' | 'left' | 'bottom'; filtersLayout?: 'inline' | 'wrapped' | 'dropdown'; showLabels?: boolean; compactButtons?: boolean; paginationPosition?: 'top' | 'bottom' | 'both'; showRecordInfo?: boolean; paginationAlignment?: 'left' | 'center' | 'right' | 'between'; } interface DataTableProps<T> { columns: DataTableColumn<T>[]; defaultOrderDir?: 'asc' | 'desc'; defaultOrderBy?: string; fetchData: (params: { page: number; perPage: number; search: string; orderBy: string; orderDir: 'asc' | 'desc'; filters: Record<string, string | number | undefined>; }) => Promise<{ data: T[]; total: number; }>; filters?: DataTableFilter[]; actions?: (row: T) => React__default.ReactNode; perPageOptions?: number[]; defaultPerPage?: number; className?: string; filterValues?: Record<string, string | number | undefined>; enableColumnVisibility?: boolean; enableColumnReordering?: boolean; storageKey?: string; exportConfig?: DataTableExportConfig; selectionConfig?: DataTableSelectionConfig<T>; responsiveConfig?: DataTableResponsiveConfig; headerConfig?: DataTableHeaderConfig; layoutConfig?: DataTableLayoutConfig; advancedFilters?: DataTableAdvancedFilter[]; enableAdvancedFilters?: boolean; onAdvancedFilter?: (filterGroup: DataTableFilterGroup) => void; } /** * DataTable - Advanced data table component with sorting, filtering, pagination, and more * * @template T - Type of data items, must have id property * * @example * // Basic usage * <DataTable * columns={[ * { key: 'name', label: 'Name', sortable: true }, * { key: 'email', label: 'Email' } * ]} * fetchData={async ({ page, perPage, search }) => { * const res = await fetch(`/api/users?page=${page}`); * return res.json(); * }} * /> * * @example * // With all features * <DataTable * columns={columns} * fetchData={fetchUsers} * filters={filters} * selectionConfig={{ enableRowSelection: true }} * exportConfig={{ enableExport: true }} * enableColumnVisibility * enableAdvancedFilters * /> */ declare function DataTable<T extends { id: number | string; }>({ columns: initialColumns, defaultOrderDir, defaultOrderBy, fetchData, filters, actions, perPageOptions, defaultPerPage, className, filterValues: externalFilterValues, enableColumnVisibility, enableColumnReordering, storageKey, exportConfig, selectionConfig, responsiveConfig, headerConfig, layoutConfig, advancedFilters, enableAdvancedFilters, onAdvancedFilter, }: DataTableProps<T>): any; interface DataTablePaginationProps { page: number; totalPages: number; perPage: number; total: number; dataLength: number; screenSize: 'mobile' | 'tablet' | 'desktop'; showRecordInfo?: boolean; paginationAlignment?: 'left' | 'center' | 'right' | 'between'; compactMode?: boolean; isMobileView?: boolean; onPageChange: (page: number) => void; } /** * DataTablePagination - Pagination component for DataTable * Handles page navigation and displays record information */ declare function DataTablePagination({ page, totalPages, perPage, total, dataLength, screenSize, showRecordInfo, paginationAlignment, compactMode, isMobileView, onPageChange, }: DataTablePaginationProps): any; interface AdvancedFilterValueInputProps { field: DataTableAdvancedFilter | undefined; rule: DataTableFilterRule; onUpdate: (value: string | number | boolean | string[] | number[] | [string | number, string | number]) => void; } /** * AdvancedFilterValueInput - Input component for advanced filter values * Renders appropriate input based on field type and operator */ declare function AdvancedFilterValueInput({ field, rule, onUpdate }: AdvancedFilterValueInputProps): any; interface DataTableFilterInputProps { filter: DataTableFilter; value: string | number | boolean | undefined; onChange: (value: string | number | boolean | undefined) => void; compactMode?: boolean; isMobileView?: boolean; } declare function DataTableFilterInput({ filter, value, onChange, compactMode, isMobileView, }: DataTableFilterInputProps): any; /** * Utility functions for DataTable component */ /** * Combines multiple class names, filtering out falsy values */ declare function classNames(...classes: (string | boolean | undefined)[]): string; /** * Convert width value to CSS string * Accepts: '200px', '20%', 200 (converts to '200px') */ declare function getCSSWidth(width?: string | number): string | undefined; /** * Get column style object with width, minWidth, maxWidth */ declare function getColumnStyle(column: { width?: string | number; minWidth?: string | number; maxWidth?: string | number; }): React__default.CSSProperties; /** * Get text alignment class */ declare function getAlignmentClass(align?: 'left' | 'center' | 'right'): string; /** * Constants for DataTable styling */ declare const DATATABLE_CONSTANTS: { readonly CHECKBOX_WIDTH: "w-12"; readonly RESPONSIVE_CLASSES: { readonly compactCell: "px-2 py-1"; readonly compactText: "text-xs"; readonly compactButton: "px-2 py-1 text-xs"; }; readonly PAGINATION: { readonly maxPagesMobile: 3; readonly maxPagesDesktop: 5; }; }; /** * Get responsive classes based on settings */ declare function getResponsiveClasses(base?: string, compactMode?: boolean, isMobileView?: boolean): string; /** * Get responsive text classes */ declare function getResponsiveTextClasses(base?: string, compactMode?: boolean, isMobileView?: boolean): string; /** * Get responsive button classes */ declare function getResponsiveButtonClasses(base?: string, compactMode?: boolean, isMobileView?: boolean): string; /** * Format operator label for display */ declare function formatOperatorLabel(operator: string): string; /** * Get default operators for a field type */ declare function getDefaultOperators(fieldType: string): string[]; /** * Safe error conversion */ declare function toError(err: unknown): Error; /** * Debounce function */ declare function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void; declare const dataTableUtils_DATATABLE_CONSTANTS: typeof DATATABLE_CONSTANTS; declare const dataTableUtils_classNames: typeof classNames; declare const dataTableUtils_debounce: typeof debounce; declare const dataTableUtils_formatOperatorLabel: typeof formatOperatorLabel; declare const dataTableUtils_getAlignmentClass: typeof getAlignmentClass; declare const dataTableUtils_getCSSWidth: typeof getCSSWidth; declare const dataTableUtils_getColumnStyle: typeof getColumnStyle; declare const dataTableUtils_getDefaultOperators: typeof getDefaultOperators; declare const dataTableUtils_getResponsiveButtonClasses: typeof getResponsiveButtonClasses; declare const dataTableUtils_getResponsiveClasses: typeof getResponsiveClasses; declare const dataTableUtils_getResponsiveTextClasses: typeof getResponsiveTextClasses; declare const dataTableUtils_toError: typeof toError; declare namespace dataTableUtils { export { dataTableUtils_DATATABLE_CONSTANTS as DATATABLE_CONSTANTS, dataTableUtils_classNames as classNames, dataTableUtils_debounce as debounce, dataTableUtils_formatOperatorLabel as formatOperatorLabel, dataTableUtils_getAlignmentClass as getAlignmentClass, dataTableUtils_getCSSWidth as getCSSWidth, dataTableUtils_getColumnStyle as getColumnStyle, dataTableUtils_getDefaultOperators as getDefaultOperators, dataTableUtils_getResponsiveButtonClasses as getResponsiveButtonClasses, dataTableUtils_getResponsiveClasses as getResponsiveClasses, dataTableUtils_getResponsiveTextClasses as getResponsiveTextClasses, dataTableUtils_toError as toError }; } declare const Button: any; declare function Pagination({ className, ...props }: React.ComponentProps<"nav">): any; declare function PaginationContent({ className, ...props }: React.ComponentProps<"ul">): any; declare function PaginationItem({ ...props }: React.ComponentProps<"li">): any; type PaginationLinkProps = { isActive?: boolean; } & Pick<React.ComponentProps<typeof Button>, "size"> & React.ComponentProps<"a">; declare function PaginationLink({ className, isActive, size, ...props }: PaginationLinkProps): any; declare function PaginationPrevious({ className, ...props }: React.ComponentProps<typeof PaginationLink>): any; declare function PaginationNext({ className, ...props }: React.ComponentProps<typeof PaginationLink>): any; declare function PaginationEllipsis({ className, ...props }: React.ComponentProps<"span">): any; declare function getPaginationRange(current: number, total: number, siblingCount?: number): (number | "ellipsis")[]; /** * Props for the Select2 component * @template T - The type of items in the select, must have id and optional label */ type Select2Props<T> = { /** Current selected value(s) */ value: T | null | T[]; /** Callback when selection changes */ onChange: (val: T | null | T[]) => void; /** Function to fetch options with search and pagination */ fetchOptions: (params: { search: string; page: number; }) => Promise<{ data: T[]; hasMore: boolean; }>; /** Custom render function for each option */ renderOption?: (item: T) => React__default.ReactNode; /** Custom render function for selected value(s) */ renderSelected?: (item: T | null | T[]) => React__default.ReactNode; /** Placeholder text when no selection */ placeholder?: string; /** Enable multi-select mode */ isMulti?: boolean; /** Message when no options available */ noOptionsMessage?: string | ((search: string) => React__default.ReactNode); /** Message during loading */ loadingMessage?: string | React__default.ReactNode; /** Message when error occurs */ errorMessage?: string | ((error: Error) => React__default.ReactNode); /** Additional CSS classes */ className?: string; /** Disable the select */ disabled?: boolean; /** Debounce delay in milliseconds for search input (default: 300) */ debounceMs?: number; /** Minimum characters required before fetching options (default: 0) */ minInput?: number; /** Maximum number of items that can be selected in multi-select mode */ maxSelections?: number; /** Show Select All / Clear All buttons in multi-select mode */ showSelectAll?: boolean; /** Callback when max selections reached */ onMaxSelectionsReached?: () => void; }; /** * Select2 - Advanced select component with async data fetching, search, and multi-select support * * @template T - Type of items, must have `id` and optional `label` properties * * @example * // Single select * <Select2 * value={selectedUser} * onChange={setSelectedUser} * fetchOptions={async ({ search, page }) => ({ * data: await fetchUsers(search, page), * hasMore: true * })} * /> * * @example * // Multi-select with max selections * <Select2 * isMulti * maxSelections={5} * value={selectedItems} * onChange={setSelectedItems} * fetchOptions={fetchItems} * onMaxSelectionsReached={() => toast.error('Max 5 items')} * /> * * @example * // With minimum input length (for large datasets) * <Select2 * value={selectedCity} * onChange={setSelectedCity} * fetchOptions={fetchCities} * minInput={2} * placeholder="Ketik minimal 2 huruf..." * /> * * @param props - Select2Props<T> * @returns React component */ declare function Select2<T extends { id: string | number; label?: string; }>({ value, onChange, fetchOptions, renderOption, renderSelected, placeholder, isMulti, noOptionsMessage, loadingMessage, errorMessage, className, disabled, debounceMs, minInput, maxSelections, showSelectAll, onMaxSelectionsReached, }: Select2Props<T>): any; declare function cn(...inputs: ClassValue[]): string; export { AdvancedFilterValueInput, type DataTableAdvancedFilter, type DataTableBulkAction, type DataTableColumn, type DataTableExportConfig, type DataTableFilter, type DataTableFilterGroup, DataTableFilterInput, type DataTableFilterRule, type DataTableHeaderConfig, type DataTableLayoutConfig, DataTablePagination, type DataTableProps, type DataTableResponsiveConfig, type DataTableSelectionConfig, dataTableUtils as DataTableUtils, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, Select2, type Select2Props, cn, DataTable as default, getPaginationRange };