@papernote/ui 1.2.0 → 1.3.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.
Files changed (52) hide show
  1. package/dist/components/Box.d.ts +2 -1
  2. package/dist/components/Box.d.ts.map +1 -1
  3. package/dist/components/Button.d.ts +10 -1
  4. package/dist/components/Button.d.ts.map +1 -1
  5. package/dist/components/Card.d.ts +11 -2
  6. package/dist/components/Card.d.ts.map +1 -1
  7. package/dist/components/DataTable.d.ts +17 -3
  8. package/dist/components/DataTable.d.ts.map +1 -1
  9. package/dist/components/EmptyState.d.ts +3 -1
  10. package/dist/components/EmptyState.d.ts.map +1 -1
  11. package/dist/components/Grid.d.ts +4 -2
  12. package/dist/components/Grid.d.ts.map +1 -1
  13. package/dist/components/Input.d.ts +2 -0
  14. package/dist/components/Input.d.ts.map +1 -1
  15. package/dist/components/MultiSelect.d.ts +13 -1
  16. package/dist/components/MultiSelect.d.ts.map +1 -1
  17. package/dist/components/Stack.d.ts +25 -5
  18. package/dist/components/Stack.d.ts.map +1 -1
  19. package/dist/components/Text.d.ts +20 -4
  20. package/dist/components/Text.d.ts.map +1 -1
  21. package/dist/components/Textarea.d.ts +2 -0
  22. package/dist/components/Textarea.d.ts.map +1 -1
  23. package/dist/components/index.d.ts +1 -3
  24. package/dist/components/index.d.ts.map +1 -1
  25. package/dist/index.d.ts +110 -48
  26. package/dist/index.esm.js +144 -138
  27. package/dist/index.esm.js.map +1 -1
  28. package/dist/index.js +143 -138
  29. package/dist/index.js.map +1 -1
  30. package/dist/styles.css +8 -51
  31. package/package.json +1 -1
  32. package/src/components/Box.stories.tsx +377 -0
  33. package/src/components/Box.tsx +8 -4
  34. package/src/components/Button.tsx +23 -10
  35. package/src/components/Card.tsx +20 -5
  36. package/src/components/DataTable.stories.tsx +36 -25
  37. package/src/components/DataTable.tsx +95 -5
  38. package/src/components/EmptyState.stories.tsx +124 -72
  39. package/src/components/EmptyState.tsx +10 -0
  40. package/src/components/Grid.stories.tsx +348 -0
  41. package/src/components/Grid.tsx +12 -5
  42. package/src/components/Input.tsx +12 -2
  43. package/src/components/MultiSelect.tsx +41 -10
  44. package/src/components/Stack.stories.tsx +24 -1
  45. package/src/components/Stack.tsx +40 -10
  46. package/src/components/Text.stories.tsx +273 -0
  47. package/src/components/Text.tsx +33 -8
  48. package/src/components/Textarea.tsx +32 -21
  49. package/src/components/index.ts +1 -4
  50. package/dist/components/Table.d.ts +0 -26
  51. package/dist/components/Table.d.ts.map +0 -1
  52. package/src/components/Table.tsx +0 -239
package/dist/index.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { Loader2, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Check, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Info, Trash2, Circle, ChevronsRight, ChevronsLeft, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, Home, ArrowUpDown, ArrowUp, ArrowDown, FileText, Image, File as File$1, User, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Download, Save, XCircle, Filter, BarChart3, MessageSquare } from 'lucide-react';
3
2
  import * as React from 'react';
4
3
  import React__default, { forwardRef, useState, useRef, useId, useImperativeHandle, useEffect, useCallback, useMemo, cloneElement, isValidElement, Component, createContext as createContext$1, useLayoutEffect, createElement, useContext, useReducer } from 'react';
4
+ import { Loader2, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Check, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Info, Trash2, Circle, ChevronsRight, ChevronsLeft, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, Home, FileText, Image, File as File$1, User, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Download, Save, XCircle, Filter, BarChart3, MessageSquare } from 'lucide-react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { Link as Link$1 } from 'react-router-dom';
7
7
 
@@ -11,6 +11,8 @@ import { Link as Link$1 } from 'react-router-dom';
11
11
  * A versatile button component that supports multiple visual styles, sizes, icons,
12
12
  * loading states, and notification badges.
13
13
  *
14
+ * Supports ref forwarding for DOM access.
15
+ *
14
16
  * @example Basic usage
15
17
  * ```tsx
16
18
  * <Button variant="primary">Click me</Button>
@@ -37,8 +39,14 @@ import { Link as Link$1 } from 'react-router-dom';
37
39
  * <Bell />
38
40
  * </Button>
39
41
  * ```
42
+ *
43
+ * @example With ref
44
+ * ```tsx
45
+ * const buttonRef = useRef<HTMLButtonElement>(null);
46
+ * <Button ref={buttonRef}>Focusable</Button>
47
+ * ```
40
48
  */
41
- function Button({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }) {
49
+ const Button = forwardRef(({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }, ref) => {
42
50
  const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-400 disabled:opacity-40 disabled:cursor-not-allowed';
43
51
  const variantStyles = {
44
52
  primary: 'bg-accent-500 text-white border-accent-500 hover:bg-accent-600 hover:shadow-sm active:scale-[0.98]',
@@ -69,7 +77,7 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
69
77
  md: 'min-w-[18px] h-[18px] text-[11px] px-1.5',
70
78
  lg: 'min-w-[20px] h-5 text-xs px-1.5',
71
79
  };
72
- const buttonElement = (jsxs("button", { className: `
80
+ const buttonElement = (jsxs("button", { ref: ref, className: `
73
81
  ${baseStyles}
74
82
  ${variantStyles[variant]}
75
83
  ${sizeStyles[size]}
@@ -92,7 +100,8 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
92
100
  shadow-sm
93
101
  pointer-events-none
94
102
  `, "aria-label": `${badgeContent} notifications`, children: badgeContent })] }));
95
- }
103
+ });
104
+ Button.displayName = 'Button';
96
105
 
97
106
  /**
98
107
  * ButtonGroup component - Toggle button group for single or multiple selection.
@@ -239,7 +248,7 @@ function ButtonGroup({ options, value, values = [], onChange, onChangeMultiple,
239
248
  * />
240
249
  * ```
241
250
  */
242
- const Input = forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
251
+ const Input = forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, loading = false, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
243
252
  const inputId = id || `input-${Math.random().toString(36).substring(2, 9)}`;
244
253
  const [showPassword, setShowPassword] = useState(false);
245
254
  // Handle clear button click
@@ -311,7 +320,7 @@ const Input = forwardRef(({ label, helperText, validationState, validationMessag
311
320
  ${validationState && !suffix && !suffixIcon && !showPasswordToggle ? 'pr-10' : ''}
312
321
  ${(showPasswordToggle && type === 'password') || validationState || suffix || suffixIcon ? 'pr-20' : ''}
313
322
  ${className}
314
- `, ...props }), suffix && (jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && (jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsx(X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsx(EyeOff, { className: "h-5 w-5" }) : jsx(Eye, { className: "h-5 w-5" }) })), validationState && (jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
323
+ `, ...props }), suffix && (jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [loading && (jsx("div", { className: "pointer-events-none text-ink-400", children: jsx(Loader2, { className: "h-5 w-5 animate-spin" }) })), suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && !loading && (jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsx(X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsx(EyeOff, { className: "h-5 w-5" }) : jsx(Eye, { className: "h-5 w-5" }) })), validationState && (jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
315
324
  });
316
325
  Input.displayName = 'Input';
317
326
 
@@ -518,11 +527,18 @@ const Select = forwardRef((props, ref) => {
518
527
  });
519
528
  Select.displayName = 'Select';
520
529
 
521
- function MultiSelect({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, 'aria-label': ariaLabel, }) {
530
+ const MultiSelect = forwardRef(({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, loading = false, 'aria-label': ariaLabel, }, ref) => {
522
531
  const [isOpen, setIsOpen] = useState(false);
523
532
  const [searchQuery, setSearchQuery] = useState('');
524
533
  const selectRef = useRef(null);
525
534
  const searchInputRef = useRef(null);
535
+ const triggerRef = useRef(null);
536
+ // Expose imperative methods
537
+ useImperativeHandle(ref, () => ({
538
+ focus: () => triggerRef.current?.focus(),
539
+ open: () => !disabled && setIsOpen(true),
540
+ close: () => setIsOpen(false),
541
+ }));
526
542
  const selectedOptions = options.filter(opt => value.includes(opt.value));
527
543
  const hasReachedMax = maxSelections ? value.length >= maxSelections : false;
528
544
  const filteredOptions = searchable && searchQuery
@@ -569,11 +585,11 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
569
585
  e.stopPropagation();
570
586
  onChange?.([]);
571
587
  };
572
- return (jsxs("div", { className: "w-full", children: [label && (jsx("label", { className: "label", children: label })), jsxs("div", { ref: selectRef, className: "relative", children: [jsxs("button", { type: "button", onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, className: `
588
+ return (jsxs("div", { className: "w-full", children: [label && (jsx("label", { className: "label", children: label })), jsxs("div", { ref: selectRef, className: "relative", children: [jsxs("button", { ref: triggerRef, type: "button", onClick: () => !disabled && !loading && setIsOpen(!isOpen), disabled: disabled || loading, className: `
573
589
  input w-full flex items-center justify-between min-h-[42px]
574
590
  ${error ? 'border-error-400 focus:border-error-400 focus:ring-error-400' : ''}
575
- ${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
576
- `, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsx("span", { className: "text-xs", children: option.icon }), option.label, jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsx(X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxs("div", { className: "flex items-center gap-2 ml-2", children: [selectedOptions.length > 0 && !disabled && (jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsx(X, { className: "h-4 w-4" }) })), jsx(ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` })] })] }), isOpen && (jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsx("div", { className: "p-2 border-b border-paper-200", children: jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
591
+ ${disabled || loading ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
592
+ `, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsx("span", { className: "text-xs", children: option.icon }), option.label, jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsx(X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxs("div", { className: "flex items-center gap-2 ml-2", children: [loading && (jsx(Loader2, { className: "h-4 w-4 text-ink-400 animate-spin" })), !loading && selectedOptions.length > 0 && !disabled && (jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsx(X, { className: "h-4 w-4" }) })), !loading && (jsx(ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` }))] })] }), isOpen && (jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsx("div", { className: "p-2 border-b border-paper-200", children: jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
577
593
  const isSelected = value.includes(option.value);
578
594
  const isDisabled = option.disabled || (hasReachedMax && !isSelected);
579
595
  return (jsx("button", { type: "button", onClick: () => !isDisabled && handleToggle(option.value), disabled: isDisabled, className: `
@@ -585,7 +601,8 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
585
601
  ${isSelected ? 'bg-accent-600 border-accent-600' : 'border-paper-300'}
586
602
  `, children: isSelected && jsx(Check, { className: "h-3 w-3 text-white" }) }), option.icon && jsx("span", { children: option.icon }), option.label] }) }, option.value));
587
603
  })) })] }))] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || error) && (jsx("p", { className: `text-xs ${error ? 'text-error-600' : 'text-ink-600'}`, children: error || helperText })), maxSelections && (jsxs("p", { className: `text-xs ml-auto ${hasReachedMax ? 'text-warning-600 font-medium' : 'text-ink-500'}`, children: [value.length, " / ", maxSelections, " selected"] }))] })] }));
588
- }
604
+ });
605
+ MultiSelect.displayName = 'MultiSelect';
589
606
 
590
607
  const Switch = forwardRef(({ checked, onChange, label, description, disabled = false, size = 'md', loading = false, }, ref) => {
591
608
  // Generate unique IDs for ARIA
@@ -632,7 +649,7 @@ const Switch = forwardRef(({ checked, onChange, label, description, disabled = f
632
649
  });
633
650
  Switch.displayName = 'Switch';
634
651
 
635
- const Textarea = forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', className = '', id, value, rows = 4, ...props }, ref) => {
652
+ const Textarea = forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', loading = false, className = '', id, value, rows = 4, ...props }, ref) => {
636
653
  const textareaId = id || `textarea-${Math.random().toString(36).substring(2, 9)}`;
637
654
  const currentLength = typeof value === 'string' ? value.length : 0;
638
655
  const internalRef = useRef(null);
@@ -707,14 +724,15 @@ const Textarea = forwardRef(({ label, helperText, validationState, validationMes
707
724
  return 'text-ink-600';
708
725
  }
709
726
  };
710
- return (jsxs("div", { className: "w-full", children: [label && (jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
711
- block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
712
- bg-white bg-subtle-grain transition-all duration-200
713
- focus:outline-none focus:ring-2 ${getResizeClass()}
714
- disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
715
- ${getValidationClasses()}
716
- ${className}
717
- `, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
727
+ return (jsxs("div", { className: "w-full", children: [label && (jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxs("div", { className: "relative", children: [jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
728
+ block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
729
+ bg-white bg-subtle-grain transition-all duration-200
730
+ focus:outline-none focus:ring-2 ${getResizeClass()}
731
+ disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
732
+ ${getValidationClasses()}
733
+ ${loading ? 'pr-10' : ''}
734
+ ${className}
735
+ `, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), loading && (jsx("div", { className: "absolute top-3 right-3 pointer-events-none", children: jsx(Loader2, { className: "h-5 w-5 text-ink-400 animate-spin" }) }))] }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
718
736
  });
719
737
  Textarea.displayName = 'Textarea';
720
738
 
@@ -1930,6 +1948,8 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
1930
1948
  /**
1931
1949
  * Card - Container component with paper aesthetic and subtle shadow
1932
1950
  *
1951
+ * Supports ref forwarding for DOM access.
1952
+ *
1933
1953
  * A content container with paper texture, border, and shadow effects. Supports
1934
1954
  * different sizes, variants (padding/shadow levels), and loading states.
1935
1955
  *
@@ -1959,8 +1979,14 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
1959
1979
  * <p>Content</p>
1960
1980
  * </Card>
1961
1981
  * ```
1982
+ *
1983
+ * @example With ref
1984
+ * ```tsx
1985
+ * const cardRef = useRef<HTMLDivElement>(null);
1986
+ * <Card ref={cardRef}>Content</Card>
1987
+ * ```
1962
1988
  */
1963
- function Card({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, }) {
1989
+ const Card = forwardRef(({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, ...htmlProps }, ref) => {
1964
1990
  const baseStyles = 'bg-white bg-subtle-grain border-2 border-paper-300 transition-shadow duration-200';
1965
1991
  const variantStyles = {
1966
1992
  default: 'rounded-xl shadow-lg p-8',
@@ -1976,8 +2002,9 @@ function Card({ children, variant = 'default', width = 'auto', className = '', o
1976
2002
  full: 'w-full',
1977
2003
  };
1978
2004
  const interactiveStyles = onClick || hoverable ? 'cursor-pointer hover:shadow-md' : '';
1979
- return (jsx("div", { className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxs("div", { className: "space-y-4", children: [jsx(Skeleton, { className: "h-6 w-3/4" }), jsx(Skeleton, { className: "h-4 w-full" }), jsx(Skeleton, { className: "h-4 w-5/6" }), jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
1980
- }
2005
+ return (jsx("div", { ref: ref, ...htmlProps, className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxs("div", { className: "space-y-4", children: [jsx(Skeleton, { className: "h-6 w-3/4" }), jsx(Skeleton, { className: "h-4 w-full" }), jsx(Skeleton, { className: "h-4 w-5/6" }), jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
2006
+ });
2007
+ Card.displayName = 'Card';
1981
2008
  /**
1982
2009
  * CardHeader - Header section for Card component
1983
2010
  *
@@ -2075,15 +2102,34 @@ function Separator({ orientation = 'horizontal', className = '', spacing = 'md',
2075
2102
  /**
2076
2103
  * Stack component for arranging children vertically or horizontally with consistent spacing.
2077
2104
  *
2078
- * Spacing scale:
2105
+ * Supports ref forwarding for DOM access.
2106
+ *
2107
+ * Spacing scale (use either `spacing` or `gap` prop - they're aliases):
2079
2108
  * - none: 0
2080
2109
  * - xs: 0.5rem (2)
2081
2110
  * - sm: 0.75rem (3)
2082
2111
  * - md: 1.5rem (6)
2083
2112
  * - lg: 2rem (8)
2084
2113
  * - xl: 3rem (12)
2114
+ *
2115
+ * @example
2116
+ * ```tsx
2117
+ * // Using spacing prop
2118
+ * <Stack spacing="md">
2119
+ * <Card>Item 1</Card>
2120
+ * <Card>Item 2</Card>
2121
+ * </Stack>
2122
+ *
2123
+ * // Using gap prop (alias)
2124
+ * <Stack gap="md">
2125
+ * <Card>Item 1</Card>
2126
+ * <Card>Item 2</Card>
2127
+ * </Stack>
2128
+ * ```
2085
2129
  */
2086
- const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stretch', justify = 'start', wrap = false, className = '', }) => {
2130
+ const Stack = forwardRef(({ children, direction = 'vertical', spacing, gap, align = 'stretch', justify = 'start', wrap = false, className = '', ...htmlProps }, ref) => {
2131
+ // Use gap as alias for spacing (spacing takes precedence if both provided)
2132
+ const effectiveSpacing = spacing ?? gap ?? 'md';
2087
2133
  const spacingClasses = {
2088
2134
  vertical: {
2089
2135
  none: '',
@@ -2115,20 +2161,23 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
2115
2161
  between: 'justify-between',
2116
2162
  around: 'justify-around',
2117
2163
  };
2118
- return (jsx("div", { className: `
2164
+ return (jsx("div", { ref: ref, ...htmlProps, className: `
2119
2165
  flex
2120
2166
  ${direction === 'vertical' ? 'flex-col' : 'flex-row'}
2121
2167
  ${wrap ? 'flex-wrap' : ''}
2122
- ${spacingClasses[direction][spacing]}
2168
+ ${spacingClasses[direction][effectiveSpacing]}
2123
2169
  ${alignClasses[align]}
2124
2170
  ${justifyClasses[justify]}
2125
2171
  ${className}
2126
2172
  `, children: children }));
2127
- };
2173
+ });
2174
+ Stack.displayName = 'Stack';
2128
2175
 
2129
2176
  /**
2130
2177
  * Grid component for arranging children in a CSS grid layout.
2131
2178
  *
2179
+ * Supports ref forwarding for DOM access.
2180
+ *
2132
2181
  * Column options: 1, 2, 3, 4, 6, 12
2133
2182
  *
2134
2183
  * Responsive breakpoints (mobile-first):
@@ -2153,7 +2202,7 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
2153
2202
  * <Card>Item 2</Card>
2154
2203
  * </Grid>
2155
2204
  */
2156
- const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', }) => {
2205
+ const Grid = forwardRef(({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', ...htmlProps }, ref) => {
2157
2206
  // Base column classes
2158
2207
  const baseColumnClasses = {
2159
2208
  1: 'grid-cols-1',
@@ -2212,18 +2261,20 @@ const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '
2212
2261
  lg ? lgColumnClasses[lg] : '',
2213
2262
  xl ? xlColumnClasses[xl] : '',
2214
2263
  ].filter(Boolean).join(' ');
2215
- return (jsx("div", { className: `
2264
+ return (jsx("div", { ref: ref, ...htmlProps, className: `
2216
2265
  grid
2217
2266
  ${columnClassList}
2218
2267
  ${gapClasses[gap]}
2219
2268
  ${className}
2220
2269
  `, children: children }));
2221
- };
2270
+ });
2271
+ Grid.displayName = 'Grid';
2222
2272
 
2223
2273
  /**
2224
2274
  * Box component for generic containers with design system spacing and borders.
2275
+ * Supports ref forwarding for DOM access.
2225
2276
  */
2226
- const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }) => {
2277
+ const Box = forwardRef(({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }, ref) => {
2227
2278
  const spacingMap = {
2228
2279
  none: '0',
2229
2280
  xs: '2',
@@ -2308,7 +2359,7 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
2308
2359
  };
2309
2360
  return roundedClasses[rounded];
2310
2361
  };
2311
- return (jsx("div", { ...htmlProps, className: `
2362
+ return (jsx("div", { ref: ref, ...htmlProps, className: `
2312
2363
  ${getPaddingClass()}
2313
2364
  ${getMarginClass()}
2314
2365
  ${borderClasses[border]}
@@ -2318,7 +2369,8 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
2318
2369
  ${getHeightClass()}
2319
2370
  ${className}
2320
2371
  `, children: children }));
2321
- };
2372
+ });
2373
+ Box.displayName = 'Box';
2322
2374
 
2323
2375
  /**
2324
2376
  * GridItem component for items within a Grid layout.
@@ -2363,6 +2415,8 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
2363
2415
  /**
2364
2416
  * Text component for consistent typography across the application.
2365
2417
  *
2418
+ * Supports ref forwarding for DOM access.
2419
+ *
2366
2420
  * Size scale:
2367
2421
  * - xs: 0.75rem (12px)
2368
2422
  * - sm: 0.875rem (14px)
@@ -2370,8 +2424,21 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
2370
2424
  * - lg: 1.125rem (18px)
2371
2425
  * - xl: 1.25rem (20px)
2372
2426
  * - 2xl: 1.5rem (24px)
2427
+ *
2428
+ * @example
2429
+ * ```tsx
2430
+ * <Text size="lg" weight="semibold" color="primary">
2431
+ * Hello World
2432
+ * </Text>
2433
+ *
2434
+ * <Text color="warning">Warning message</Text>
2435
+ *
2436
+ * // With ref
2437
+ * const textRef = useRef<HTMLParagraphElement>(null);
2438
+ * <Text ref={textRef}>Measurable text</Text>
2439
+ * ```
2373
2440
  */
2374
- const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', }) => {
2441
+ const Text = forwardRef(({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', ...htmlProps }, ref) => {
2375
2442
  const sizeClasses = {
2376
2443
  xs: 'text-xs',
2377
2444
  sm: 'text-sm',
@@ -2393,6 +2460,7 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
2393
2460
  accent: 'text-primary-600',
2394
2461
  error: 'text-error-600',
2395
2462
  success: 'text-success-600',
2463
+ warning: 'text-warning-600',
2396
2464
  };
2397
2465
  const alignClasses = {
2398
2466
  left: 'text-left',
@@ -2424,8 +2492,9 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
2424
2492
  lineClamp ? lineClampClasses[lineClamp] : '',
2425
2493
  className,
2426
2494
  ].filter(Boolean).join(' ');
2427
- return (jsx(Component, { className: classes, children: children }));
2428
- };
2495
+ return (jsx(Component, { ref: ref, className: classes, ...htmlProps, children: children }));
2496
+ });
2497
+ Text.displayName = 'Text';
2429
2498
 
2430
2499
  const toastStyles = {
2431
2500
  success: {
@@ -6068,99 +6137,6 @@ function StepIndicator({ steps, currentStep, variant = 'horizontal', onStepClick
6068
6137
  }) }) }));
6069
6138
  }
6070
6139
 
6071
- function Table$1({ data, columns, keyExtractor, selectable = false, expandable = false, onRowSelect, renderExpandedRow, emptyState, className = '', onSort, sortColumn: externalSortColumn, sortDirection: externalSortDirection, }) {
6072
- const [internalSortColumn, setInternalSortColumn] = useState(null);
6073
- const [internalSortDirection, setInternalSortDirection] = useState(null);
6074
- // Use external sort state if provided, otherwise use internal state
6075
- const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
6076
- const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
6077
- const [selectedRows, setSelectedRows] = useState(new Set());
6078
- const [expandedRows, setExpandedRows] = useState(new Set());
6079
- // Handle sorting
6080
- const handleSort = (columnKey) => {
6081
- let newDirection;
6082
- if (sortColumn === columnKey) {
6083
- if (sortDirection === 'asc') {
6084
- newDirection = 'desc';
6085
- }
6086
- else if (sortDirection === 'desc') {
6087
- newDirection = null;
6088
- }
6089
- else {
6090
- newDirection = 'asc';
6091
- }
6092
- }
6093
- else {
6094
- newDirection = 'asc';
6095
- }
6096
- // If using external sort control, call the callback
6097
- if (onSort) {
6098
- onSort(columnKey, newDirection);
6099
- }
6100
- else {
6101
- // Otherwise update internal state
6102
- setInternalSortColumn(newDirection === null ? null : columnKey);
6103
- setInternalSortDirection(newDirection);
6104
- }
6105
- };
6106
- // Handle row selection
6107
- const handleRowSelect = (rowKey) => {
6108
- const newSelected = new Set(selectedRows);
6109
- if (newSelected.has(rowKey)) {
6110
- newSelected.delete(rowKey);
6111
- }
6112
- else {
6113
- newSelected.add(rowKey);
6114
- }
6115
- setSelectedRows(newSelected);
6116
- onRowSelect?.(Array.from(newSelected));
6117
- };
6118
- // Handle select all
6119
- const handleSelectAll = () => {
6120
- if (selectedRows.size === data.length) {
6121
- setSelectedRows(new Set());
6122
- onRowSelect?.([]);
6123
- }
6124
- else {
6125
- const allKeys = new Set(data.map(keyExtractor));
6126
- setSelectedRows(allKeys);
6127
- onRowSelect?.(Array.from(allKeys));
6128
- }
6129
- };
6130
- // Handle row expansion
6131
- const handleRowExpand = (rowKey) => {
6132
- const newExpanded = new Set(expandedRows);
6133
- if (newExpanded.has(rowKey)) {
6134
- newExpanded.delete(rowKey);
6135
- }
6136
- else {
6137
- newExpanded.add(rowKey);
6138
- }
6139
- setExpandedRows(newExpanded);
6140
- };
6141
- const getSortIcon = (columnKey) => {
6142
- if (sortColumn !== columnKey) {
6143
- return jsx(ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6144
- }
6145
- if (sortDirection === 'asc') {
6146
- return jsx(ArrowUp, { className: "h-4 w-4 text-accent-600" });
6147
- }
6148
- if (sortDirection === 'desc') {
6149
- return jsx(ArrowDown, { className: "h-4 w-4 text-accent-600" });
6150
- }
6151
- return jsx(ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6152
- };
6153
- if (data.length === 0 && emptyState) {
6154
- return jsx("div", { children: emptyState });
6155
- }
6156
- return (jsx("div", { className: `overflow-x-auto ${className}`, children: jsxs("table", { className: "table", children: [jsx("thead", { className: "table-header", children: jsxs("tr", { children: [selectable && (jsx("th", { className: "table-header-cell w-12", children: jsx("input", { type: "checkbox", checked: selectedRows.size === data.length && data.length > 0, onChange: handleSelectAll, className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": "Select all rows" }) })), expandable && jsx("th", { className: "table-header-cell w-12" }), columns.map((column) => (jsx("th", { className: "table-header-cell", style: { width: column.width }, children: column.sortable ? (jsxs("button", { onClick: () => handleSort(column.key), className: "group inline-flex items-center gap-2 hover:text-ink-900 transition-colors", children: [jsx("span", { children: column.header }), getSortIcon(column.key)] })) : (column.header) }, column.key)))] }) }), jsx("tbody", { children: data.map((row) => {
6157
- const rowKey = keyExtractor(row);
6158
- const isSelected = selectedRows.has(rowKey);
6159
- const isExpanded = expandedRows.has(rowKey);
6160
- return (jsxs(React__default.Fragment, { children: [jsxs("tr", { className: `table-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : ''}`, children: [selectable && (jsx("td", { className: "table-cell", children: jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleRowSelect(rowKey), className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": `Select row ${rowKey}` }) })), expandable && (jsx("td", { className: "table-cell", children: jsx("button", { onClick: () => handleRowExpand(rowKey), className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded ? 'Collapse row' : 'Expand row', children: isExpanded ? (jsx(ChevronDown, { className: "h-4 w-4" })) : (jsx(ChevronRight, { className: "h-4 w-4" })) }) })), columns.map((column) => (jsx("td", { className: "table-cell", children: column.accessor ? column.accessor(row) : row[column.key] }, column.key)))] }), expandable && isExpanded && renderExpandedRow && (jsx("tr", { children: jsx("td", { colSpan: columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0), className: "px-6 py-4 bg-paper-50", children: renderExpandedRow(row) }) }))] }, rowKey));
6161
- }) })] }) }));
6162
- }
6163
-
6164
6140
  function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, }) {
6165
6141
  const variantStyles = {
6166
6142
  success: 'bg-success-50 text-success-700 border-success-200',
@@ -6268,8 +6244,8 @@ const Avatar = ({ firstName, lastName, fallbackText = 'U', imageUrl, size = 'md'
6268
6244
  `, style: { textShadow: '0 1px 2px rgba(0,0,0,0.3)' }, children: getInitials() }) }));
6269
6245
  };
6270
6246
 
6271
- function EmptyState({ icon, title, description, action, secondaryAction, }) {
6272
- return (jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), (action || secondaryAction) && (jsxs("div", { className: "flex items-center gap-3", children: [action && (jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
6247
+ function EmptyState({ icon, title, description, action, secondaryAction, children, }) {
6248
+ return (jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), children && (jsx("div", { className: "mb-8 w-full max-w-md", children: children })), (action || secondaryAction) && (jsxs("div", { className: "flex items-center gap-3", children: [action && (jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
6273
6249
  }
6274
6250
 
6275
6251
  /**
@@ -7285,7 +7261,9 @@ function getColumnStyle(column, dynamicWidth) {
7285
7261
  */
7286
7262
  function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], enableContextMenu = true, onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
7287
7263
  // Visual customization props
7288
- striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60, }) {
7264
+ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
7265
+ // Pagination props
7266
+ paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true, }) {
7289
7267
  // Column resizing state
7290
7268
  const [columnWidths, setColumnWidths] = useState({});
7291
7269
  const [resizingColumn, setResizingColumn] = useState(null);
@@ -7518,16 +7496,30 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7518
7496
  }
7519
7497
  });
7520
7498
  }
7499
+ // Combine all actions: built-in first, then custom actions, then delete last
7500
+ // Delete is stored separately to ensure it's always last
7501
+ let deleteAction = null;
7521
7502
  if (onDelete) {
7522
- builtInActions.push({
7503
+ deleteAction = {
7523
7504
  label: 'Delete',
7524
7505
  icon: Trash,
7525
7506
  onClick: onDelete,
7526
7507
  variant: 'danger',
7527
7508
  tooltip: 'Delete item'
7528
- });
7509
+ };
7529
7510
  }
7530
- const allActions = [...builtInActions, ...actions];
7511
+ // Build final actions array with consistent ordering:
7512
+ // 1. Edit (first - most common action)
7513
+ // 2. View Details
7514
+ // 3. Add Related actions
7515
+ // 4. Manage Related actions
7516
+ // 5. Custom actions (from actions prop)
7517
+ // 6. Delete (always last - destructive action)
7518
+ const allActions = [
7519
+ ...builtInActions,
7520
+ ...actions,
7521
+ ...(deleteAction ? [deleteAction] : [])
7522
+ ];
7531
7523
  // Convert actions to menu items for context menu
7532
7524
  const convertActionsToMenuItems = (item) => {
7533
7525
  const visibleActions = allActions.filter(action => !action.show || action.show(item));
@@ -7876,8 +7868,22 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7876
7868
  })] }) }), jsx("tbody", { className: "bg-white table-loading transition-opacity duration-200", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
7877
7869
  // Wrap in scrollable container if virtualized
7878
7870
  const finalContent = virtualized ? (jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent })) : tableContent;
7871
+ // Calculate pagination values
7872
+ const effectiveTotalItems = totalItems ?? data.length;
7873
+ const totalPages = Math.ceil(effectiveTotalItems / pageSize);
7874
+ // Page size selector options
7875
+ const pageSizeSelectOptions = pageSizeOptions.map(size => ({
7876
+ value: String(size),
7877
+ label: `${size} per page`,
7878
+ }));
7879
+ // Render pagination controls
7880
+ const renderPaginationControls = () => {
7881
+ if (!paginated)
7882
+ return null;
7883
+ return (jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxs(Fragment, { children: ["Showing ", ((currentPage - 1) * pageSize) + 1, " - ", Math.min(currentPage * pageSize, effectiveTotalItems), " of ", effectiveTotalItems] })) : ('No items') })] }), totalPages > 1 && onPageChange && (jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
7884
+ };
7879
7885
  // Render with context menu
7880
- return (jsxs(Fragment, { children: [finalContent, contextMenuState.isOpen && contextMenuState.item && (jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
7886
+ return (jsxs(Fragment, { children: [renderPaginationControls(), finalContent, contextMenuState.isOpen && contextMenuState.item && (jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
7881
7887
  }
7882
7888
 
7883
7889
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -60339,5 +60345,5 @@ function useColumnReorder(initialColumns, options = {}) {
60339
60345
  };
60340
60346
  }
60341
60347
 
60342
- export { Accordion, ActionButton, AdminModal, Alert, AlertDialog, AppLayout, Autocomplete, Avatar, Badge, BottomSheet, Box, Breadcrumbs, Button, ButtonGroup, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Carousel, Checkbox, Chip, Collapsible, ColorPicker, Combobox, ComingSoon, CommandPalette, ConfirmDialog, ContextMenu, ControlBar, CurrencyDisplay, CurrencyInput, Dashboard, DashboardContent, DashboardHeader, DataTable, DateDisplay, DatePicker, DateRangePicker, DateTimePicker, Drawer, DrawerFooter, DropZone, Dropdown, DropdownTrigger, EmptyState, ErrorBoundary, ExpandableRowButton, ExpandableToolbar, ExpandedRowEditForm, ExportButton, FieldArray, FileUpload, FilterBar, FilterControls, FilterStatusBanner, Form, FormContext, FormControl, FormWizard, Grid, GridItem, Hide, HoverCard, InfiniteScroll, Input, KanbanBoard, Layout, Loading, LoadingOverlay, Logo, MarkdownEditor, MaskedInput, Menu, MenuDivider, Modal, ModalFooter, MultiSelect, NotificationBar, NotificationIndicator, NumberInput, Page, PageLayout, PageNavigation, Pagination, PasswordInput, Popover, Progress, QueryTransparency, RadioGroup, Rating, RichTextEditor, SearchBar, Select, Separator, Show, Sidebar, SidebarGroup, Skeleton, SkeletonCard, SkeletonTable, Slider, Spreadsheet, SpreadsheetReport, Stack, StatCard, StatItem, StatsCardGrid, StatsGrid, StatusBadge, StatusBar, StepIndicator, Stepper, Switch, Table$1 as Table, Tabs, Text, Textarea, ThemeToggle, TimePicker, Timeline, Toast, ToastContainer, Tooltip, Transfer, TreeView, TwoColumnContent, UserProfileButton, addErrorMessage, addInfoMessage, addSuccessMessage, addWarningMessage, calculateColumnWidth, createActionsSection, createFiltersSection, createMultiSheetExcel, createPageControlsSection, createQueryDetailsSection, exportDataTableToExcel, exportToExcel, formatStatisticValue, formatStatistics, loadColumnOrder, loadColumnWidths, reorderArray, saveColumnOrder, saveColumnWidths, statusManager, useColumnReorder, useColumnResize, useCommandPalette, useConfirmDialog, useFormContext, useMediaQuery };
60348
+ export { Accordion, ActionButton, AdminModal, Alert, AlertDialog, AppLayout, Autocomplete, Avatar, Badge, BottomSheet, Box, Breadcrumbs, Button, ButtonGroup, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Carousel, Checkbox, Chip, Collapsible, ColorPicker, Combobox, ComingSoon, CommandPalette, ConfirmDialog, ContextMenu, ControlBar, CurrencyDisplay, CurrencyInput, Dashboard, DashboardContent, DashboardHeader, DataTable, DateDisplay, DatePicker, DateRangePicker, DateTimePicker, Drawer, DrawerFooter, DropZone, Dropdown, DropdownTrigger, EmptyState, ErrorBoundary, ExpandableRowButton, ExpandableToolbar, ExpandedRowEditForm, ExportButton, FieldArray, FileUpload, FilterBar, FilterControls, FilterStatusBanner, Form, FormContext, FormControl, FormWizard, Grid, GridItem, Hide, HoverCard, InfiniteScroll, Input, KanbanBoard, Layout, Loading, LoadingOverlay, Logo, MarkdownEditor, MaskedInput, Menu, MenuDivider, Modal, ModalFooter, MultiSelect, NotificationBar, NotificationIndicator, NumberInput, Page, PageLayout, PageNavigation, Pagination, PasswordInput, Popover, Progress, QueryTransparency, RadioGroup, Rating, RichTextEditor, SearchBar, Select, Separator, Show, Sidebar, SidebarGroup, Skeleton, SkeletonCard, SkeletonTable, Slider, Spreadsheet, SpreadsheetReport, Stack, StatCard, StatItem, StatsCardGrid, StatsGrid, StatusBadge, StatusBar, StepIndicator, Stepper, Switch, Tabs, Text, Textarea, ThemeToggle, TimePicker, Timeline, Toast, ToastContainer, Tooltip, Transfer, TreeView, TwoColumnContent, UserProfileButton, addErrorMessage, addInfoMessage, addSuccessMessage, addWarningMessage, calculateColumnWidth, createActionsSection, createFiltersSection, createMultiSheetExcel, createPageControlsSection, createQueryDetailsSection, exportDataTableToExcel, exportToExcel, formatStatisticValue, formatStatistics, loadColumnOrder, loadColumnWidths, reorderArray, saveColumnOrder, saveColumnWidths, statusManager, useColumnReorder, useColumnResize, useCommandPalette, useConfirmDialog, useFormContext, useMediaQuery };
60343
60349
  //# sourceMappingURL=index.esm.js.map