@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.js CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var jsxRuntime = require('react/jsx-runtime');
4
- var lucideReact = require('lucide-react');
5
4
  var React = require('react');
5
+ var lucideReact = require('lucide-react');
6
6
  var reactDom = require('react-dom');
7
7
  var reactRouterDom = require('react-router-dom');
8
8
 
@@ -31,6 +31,8 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
31
31
  * A versatile button component that supports multiple visual styles, sizes, icons,
32
32
  * loading states, and notification badges.
33
33
  *
34
+ * Supports ref forwarding for DOM access.
35
+ *
34
36
  * @example Basic usage
35
37
  * ```tsx
36
38
  * <Button variant="primary">Click me</Button>
@@ -57,8 +59,14 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
57
59
  * <Bell />
58
60
  * </Button>
59
61
  * ```
62
+ *
63
+ * @example With ref
64
+ * ```tsx
65
+ * const buttonRef = useRef<HTMLButtonElement>(null);
66
+ * <Button ref={buttonRef}>Focusable</Button>
67
+ * ```
60
68
  */
61
- function Button({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }) {
69
+ const Button = React.forwardRef(({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }, ref) => {
62
70
  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';
63
71
  const variantStyles = {
64
72
  primary: 'bg-accent-500 text-white border-accent-500 hover:bg-accent-600 hover:shadow-sm active:scale-[0.98]',
@@ -89,7 +97,7 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
89
97
  md: 'min-w-[18px] h-[18px] text-[11px] px-1.5',
90
98
  lg: 'min-w-[20px] h-5 text-xs px-1.5',
91
99
  };
92
- const buttonElement = (jsxRuntime.jsxs("button", { className: `
100
+ const buttonElement = (jsxRuntime.jsxs("button", { ref: ref, className: `
93
101
  ${baseStyles}
94
102
  ${variantStyles[variant]}
95
103
  ${sizeStyles[size]}
@@ -112,7 +120,8 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
112
120
  shadow-sm
113
121
  pointer-events-none
114
122
  `, "aria-label": `${badgeContent} notifications`, children: badgeContent })] }));
115
- }
123
+ });
124
+ Button.displayName = 'Button';
116
125
 
117
126
  /**
118
127
  * ButtonGroup component - Toggle button group for single or multiple selection.
@@ -259,7 +268,7 @@ function ButtonGroup({ options, value, values = [], onChange, onChangeMultiple,
259
268
  * />
260
269
  * ```
261
270
  */
262
- const Input = React.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) => {
271
+ const Input = React.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) => {
263
272
  const inputId = id || `input-${Math.random().toString(36).substring(2, 9)}`;
264
273
  const [showPassword, setShowPassword] = React.useState(false);
265
274
  // Handle clear button click
@@ -331,7 +340,7 @@ const Input = React.forwardRef(({ label, helperText, validationState, validation
331
340
  ${validationState && !suffix && !suffixIcon && !showPasswordToggle ? 'pr-10' : ''}
332
341
  ${(showPasswordToggle && type === 'password') || validationState || suffix || suffixIcon ? 'pr-20' : ''}
333
342
  ${className}
334
- `, ...props }), suffix && (jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxRuntime.jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsxRuntime.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: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsxRuntime.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 ? jsxRuntime.jsx(lucideReact.EyeOff, { className: "h-5 w-5" }) : jsxRuntime.jsx(lucideReact.Eye, { className: "h-5 w-5" }) })), validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxRuntime.jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsxRuntime.jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxRuntime.jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
343
+ `, ...props }), suffix && (jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxRuntime.jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [loading && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: jsxRuntime.jsx(lucideReact.Loader2, { className: "h-5 w-5 animate-spin" }) })), suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && !loading && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsxRuntime.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: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsxRuntime.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 ? jsxRuntime.jsx(lucideReact.EyeOff, { className: "h-5 w-5" }) : jsxRuntime.jsx(lucideReact.Eye, { className: "h-5 w-5" }) })), validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxRuntime.jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsxRuntime.jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxRuntime.jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
335
344
  });
336
345
  Input.displayName = 'Input';
337
346
 
@@ -538,11 +547,18 @@ const Select = React.forwardRef((props, ref) => {
538
547
  });
539
548
  Select.displayName = 'Select';
540
549
 
541
- function MultiSelect({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, 'aria-label': ariaLabel, }) {
550
+ const MultiSelect = React.forwardRef(({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, loading = false, 'aria-label': ariaLabel, }, ref) => {
542
551
  const [isOpen, setIsOpen] = React.useState(false);
543
552
  const [searchQuery, setSearchQuery] = React.useState('');
544
553
  const selectRef = React.useRef(null);
545
554
  const searchInputRef = React.useRef(null);
555
+ const triggerRef = React.useRef(null);
556
+ // Expose imperative methods
557
+ React.useImperativeHandle(ref, () => ({
558
+ focus: () => triggerRef.current?.focus(),
559
+ open: () => !disabled && setIsOpen(true),
560
+ close: () => setIsOpen(false),
561
+ }));
546
562
  const selectedOptions = options.filter(opt => value.includes(opt.value));
547
563
  const hasReachedMax = maxSelections ? value.length >= maxSelections : false;
548
564
  const filteredOptions = searchable && searchQuery
@@ -589,11 +605,11 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
589
605
  e.stopPropagation();
590
606
  onChange?.([]);
591
607
  };
592
- return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsx("label", { className: "label", children: label })), jsxRuntime.jsxs("div", { ref: selectRef, className: "relative", children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, className: `
608
+ return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsx("label", { className: "label", children: label })), jsxRuntime.jsxs("div", { ref: selectRef, className: "relative", children: [jsxRuntime.jsxs("button", { ref: triggerRef, type: "button", onClick: () => !disabled && !loading && setIsOpen(!isOpen), disabled: disabled || loading, className: `
593
609
  input w-full flex items-center justify-between min-h-[42px]
594
610
  ${error ? 'border-error-400 focus:border-error-400 focus:ring-error-400' : ''}
595
- ${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
596
- `, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsxRuntime.jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsxRuntime.jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxRuntime.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 && jsxRuntime.jsx("span", { className: "text-xs", children: option.icon }), option.label, jsxRuntime.jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ml-2", children: [selectedOptions.length > 0 && !disabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), jsxRuntime.jsx(lucideReact.ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` })] })] }), isOpen && (jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "p-2 border-b border-paper-200", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsxRuntime.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" })] }) })), jsxRuntime.jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
611
+ ${disabled || loading ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
612
+ `, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsxRuntime.jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsxRuntime.jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxRuntime.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 && jsxRuntime.jsx("span", { className: "text-xs", children: option.icon }), option.label, jsxRuntime.jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ml-2", children: [loading && (jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 text-ink-400 animate-spin" })), !loading && selectedOptions.length > 0 && !disabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), !loading && (jsxRuntime.jsx(lucideReact.ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` }))] })] }), isOpen && (jsxRuntime.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 && (jsxRuntime.jsx("div", { className: "p-2 border-b border-paper-200", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsxRuntime.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" })] }) })), jsxRuntime.jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
597
613
  const isSelected = value.includes(option.value);
598
614
  const isDisabled = option.disabled || (hasReachedMax && !isSelected);
599
615
  return (jsxRuntime.jsx("button", { type: "button", onClick: () => !isDisabled && handleToggle(option.value), disabled: isDisabled, className: `
@@ -605,7 +621,8 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
605
621
  ${isSelected ? 'bg-accent-600 border-accent-600' : 'border-paper-300'}
606
622
  `, children: isSelected && jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3 text-white" }) }), option.icon && jsxRuntime.jsx("span", { children: option.icon }), option.label] }) }, option.value));
607
623
  })) })] }))] }), jsxRuntime.jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || error) && (jsxRuntime.jsx("p", { className: `text-xs ${error ? 'text-error-600' : 'text-ink-600'}`, children: error || helperText })), maxSelections && (jsxRuntime.jsxs("p", { className: `text-xs ml-auto ${hasReachedMax ? 'text-warning-600 font-medium' : 'text-ink-500'}`, children: [value.length, " / ", maxSelections, " selected"] }))] })] }));
608
- }
624
+ });
625
+ MultiSelect.displayName = 'MultiSelect';
609
626
 
610
627
  const Switch = React.forwardRef(({ checked, onChange, label, description, disabled = false, size = 'md', loading = false, }, ref) => {
611
628
  // Generate unique IDs for ARIA
@@ -652,7 +669,7 @@ const Switch = React.forwardRef(({ checked, onChange, label, description, disabl
652
669
  });
653
670
  Switch.displayName = 'Switch';
654
671
 
655
- const Textarea = React.forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', className = '', id, value, rows = 4, ...props }, ref) => {
672
+ const Textarea = React.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) => {
656
673
  const textareaId = id || `textarea-${Math.random().toString(36).substring(2, 9)}`;
657
674
  const currentLength = typeof value === 'string' ? value.length : 0;
658
675
  const internalRef = React.useRef(null);
@@ -727,14 +744,15 @@ const Textarea = React.forwardRef(({ label, helperText, validationState, validat
727
744
  return 'text-ink-600';
728
745
  }
729
746
  };
730
- return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsxRuntime.jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxRuntime.jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
731
- block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
732
- bg-white bg-subtle-grain transition-all duration-200
733
- focus:outline-none focus:ring-2 ${getResizeClass()}
734
- disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
735
- ${getValidationClasses()}
736
- ${className}
737
- `, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsxRuntime.jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxRuntime.jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
747
+ return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsxRuntime.jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
748
+ block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
749
+ bg-white bg-subtle-grain transition-all duration-200
750
+ focus:outline-none focus:ring-2 ${getResizeClass()}
751
+ disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
752
+ ${getValidationClasses()}
753
+ ${loading ? 'pr-10' : ''}
754
+ ${className}
755
+ `, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), loading && (jsxRuntime.jsx("div", { className: "absolute top-3 right-3 pointer-events-none", children: jsxRuntime.jsx(lucideReact.Loader2, { className: "h-5 w-5 text-ink-400 animate-spin" }) }))] }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsxRuntime.jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxRuntime.jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
738
756
  });
739
757
  Textarea.displayName = 'Textarea';
740
758
 
@@ -1950,6 +1968,8 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
1950
1968
  /**
1951
1969
  * Card - Container component with paper aesthetic and subtle shadow
1952
1970
  *
1971
+ * Supports ref forwarding for DOM access.
1972
+ *
1953
1973
  * A content container with paper texture, border, and shadow effects. Supports
1954
1974
  * different sizes, variants (padding/shadow levels), and loading states.
1955
1975
  *
@@ -1979,8 +1999,14 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
1979
1999
  * <p>Content</p>
1980
2000
  * </Card>
1981
2001
  * ```
2002
+ *
2003
+ * @example With ref
2004
+ * ```tsx
2005
+ * const cardRef = useRef<HTMLDivElement>(null);
2006
+ * <Card ref={cardRef}>Content</Card>
2007
+ * ```
1982
2008
  */
1983
- function Card({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, }) {
2009
+ const Card = React.forwardRef(({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, ...htmlProps }, ref) => {
1984
2010
  const baseStyles = 'bg-white bg-subtle-grain border-2 border-paper-300 transition-shadow duration-200';
1985
2011
  const variantStyles = {
1986
2012
  default: 'rounded-xl shadow-lg p-8',
@@ -1996,8 +2022,9 @@ function Card({ children, variant = 'default', width = 'auto', className = '', o
1996
2022
  full: 'w-full',
1997
2023
  };
1998
2024
  const interactiveStyles = onClick || hoverable ? 'cursor-pointer hover:shadow-md' : '';
1999
- return (jsxRuntime.jsx("div", { className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx(Skeleton, { className: "h-6 w-3/4" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-full" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-5/6" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
2000
- }
2025
+ return (jsxRuntime.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 ? (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx(Skeleton, { className: "h-6 w-3/4" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-full" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-5/6" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
2026
+ });
2027
+ Card.displayName = 'Card';
2001
2028
  /**
2002
2029
  * CardHeader - Header section for Card component
2003
2030
  *
@@ -2095,15 +2122,34 @@ function Separator({ orientation = 'horizontal', className = '', spacing = 'md',
2095
2122
  /**
2096
2123
  * Stack component for arranging children vertically or horizontally with consistent spacing.
2097
2124
  *
2098
- * Spacing scale:
2125
+ * Supports ref forwarding for DOM access.
2126
+ *
2127
+ * Spacing scale (use either `spacing` or `gap` prop - they're aliases):
2099
2128
  * - none: 0
2100
2129
  * - xs: 0.5rem (2)
2101
2130
  * - sm: 0.75rem (3)
2102
2131
  * - md: 1.5rem (6)
2103
2132
  * - lg: 2rem (8)
2104
2133
  * - xl: 3rem (12)
2134
+ *
2135
+ * @example
2136
+ * ```tsx
2137
+ * // Using spacing prop
2138
+ * <Stack spacing="md">
2139
+ * <Card>Item 1</Card>
2140
+ * <Card>Item 2</Card>
2141
+ * </Stack>
2142
+ *
2143
+ * // Using gap prop (alias)
2144
+ * <Stack gap="md">
2145
+ * <Card>Item 1</Card>
2146
+ * <Card>Item 2</Card>
2147
+ * </Stack>
2148
+ * ```
2105
2149
  */
2106
- const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stretch', justify = 'start', wrap = false, className = '', }) => {
2150
+ const Stack = React.forwardRef(({ children, direction = 'vertical', spacing, gap, align = 'stretch', justify = 'start', wrap = false, className = '', ...htmlProps }, ref) => {
2151
+ // Use gap as alias for spacing (spacing takes precedence if both provided)
2152
+ const effectiveSpacing = spacing ?? gap ?? 'md';
2107
2153
  const spacingClasses = {
2108
2154
  vertical: {
2109
2155
  none: '',
@@ -2135,20 +2181,23 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
2135
2181
  between: 'justify-between',
2136
2182
  around: 'justify-around',
2137
2183
  };
2138
- return (jsxRuntime.jsx("div", { className: `
2184
+ return (jsxRuntime.jsx("div", { ref: ref, ...htmlProps, className: `
2139
2185
  flex
2140
2186
  ${direction === 'vertical' ? 'flex-col' : 'flex-row'}
2141
2187
  ${wrap ? 'flex-wrap' : ''}
2142
- ${spacingClasses[direction][spacing]}
2188
+ ${spacingClasses[direction][effectiveSpacing]}
2143
2189
  ${alignClasses[align]}
2144
2190
  ${justifyClasses[justify]}
2145
2191
  ${className}
2146
2192
  `, children: children }));
2147
- };
2193
+ });
2194
+ Stack.displayName = 'Stack';
2148
2195
 
2149
2196
  /**
2150
2197
  * Grid component for arranging children in a CSS grid layout.
2151
2198
  *
2199
+ * Supports ref forwarding for DOM access.
2200
+ *
2152
2201
  * Column options: 1, 2, 3, 4, 6, 12
2153
2202
  *
2154
2203
  * Responsive breakpoints (mobile-first):
@@ -2173,7 +2222,7 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
2173
2222
  * <Card>Item 2</Card>
2174
2223
  * </Grid>
2175
2224
  */
2176
- const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', }) => {
2225
+ const Grid = React.forwardRef(({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', ...htmlProps }, ref) => {
2177
2226
  // Base column classes
2178
2227
  const baseColumnClasses = {
2179
2228
  1: 'grid-cols-1',
@@ -2232,18 +2281,20 @@ const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '
2232
2281
  lg ? lgColumnClasses[lg] : '',
2233
2282
  xl ? xlColumnClasses[xl] : '',
2234
2283
  ].filter(Boolean).join(' ');
2235
- return (jsxRuntime.jsx("div", { className: `
2284
+ return (jsxRuntime.jsx("div", { ref: ref, ...htmlProps, className: `
2236
2285
  grid
2237
2286
  ${columnClassList}
2238
2287
  ${gapClasses[gap]}
2239
2288
  ${className}
2240
2289
  `, children: children }));
2241
- };
2290
+ });
2291
+ Grid.displayName = 'Grid';
2242
2292
 
2243
2293
  /**
2244
2294
  * Box component for generic containers with design system spacing and borders.
2295
+ * Supports ref forwarding for DOM access.
2245
2296
  */
2246
- const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }) => {
2297
+ const Box = React.forwardRef(({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }, ref) => {
2247
2298
  const spacingMap = {
2248
2299
  none: '0',
2249
2300
  xs: '2',
@@ -2328,7 +2379,7 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
2328
2379
  };
2329
2380
  return roundedClasses[rounded];
2330
2381
  };
2331
- return (jsxRuntime.jsx("div", { ...htmlProps, className: `
2382
+ return (jsxRuntime.jsx("div", { ref: ref, ...htmlProps, className: `
2332
2383
  ${getPaddingClass()}
2333
2384
  ${getMarginClass()}
2334
2385
  ${borderClasses[border]}
@@ -2338,7 +2389,8 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
2338
2389
  ${getHeightClass()}
2339
2390
  ${className}
2340
2391
  `, children: children }));
2341
- };
2392
+ });
2393
+ Box.displayName = 'Box';
2342
2394
 
2343
2395
  /**
2344
2396
  * GridItem component for items within a Grid layout.
@@ -2383,6 +2435,8 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
2383
2435
  /**
2384
2436
  * Text component for consistent typography across the application.
2385
2437
  *
2438
+ * Supports ref forwarding for DOM access.
2439
+ *
2386
2440
  * Size scale:
2387
2441
  * - xs: 0.75rem (12px)
2388
2442
  * - sm: 0.875rem (14px)
@@ -2390,8 +2444,21 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
2390
2444
  * - lg: 1.125rem (18px)
2391
2445
  * - xl: 1.25rem (20px)
2392
2446
  * - 2xl: 1.5rem (24px)
2447
+ *
2448
+ * @example
2449
+ * ```tsx
2450
+ * <Text size="lg" weight="semibold" color="primary">
2451
+ * Hello World
2452
+ * </Text>
2453
+ *
2454
+ * <Text color="warning">Warning message</Text>
2455
+ *
2456
+ * // With ref
2457
+ * const textRef = useRef<HTMLParagraphElement>(null);
2458
+ * <Text ref={textRef}>Measurable text</Text>
2459
+ * ```
2393
2460
  */
2394
- const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', }) => {
2461
+ const Text = React.forwardRef(({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', ...htmlProps }, ref) => {
2395
2462
  const sizeClasses = {
2396
2463
  xs: 'text-xs',
2397
2464
  sm: 'text-sm',
@@ -2413,6 +2480,7 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
2413
2480
  accent: 'text-primary-600',
2414
2481
  error: 'text-error-600',
2415
2482
  success: 'text-success-600',
2483
+ warning: 'text-warning-600',
2416
2484
  };
2417
2485
  const alignClasses = {
2418
2486
  left: 'text-left',
@@ -2444,8 +2512,9 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
2444
2512
  lineClamp ? lineClampClasses[lineClamp] : '',
2445
2513
  className,
2446
2514
  ].filter(Boolean).join(' ');
2447
- return (jsxRuntime.jsx(Component, { className: classes, children: children }));
2448
- };
2515
+ return (jsxRuntime.jsx(Component, { ref: ref, className: classes, ...htmlProps, children: children }));
2516
+ });
2517
+ Text.displayName = 'Text';
2449
2518
 
2450
2519
  const toastStyles = {
2451
2520
  success: {
@@ -6088,99 +6157,6 @@ function StepIndicator({ steps, currentStep, variant = 'horizontal', onStepClick
6088
6157
  }) }) }));
6089
6158
  }
6090
6159
 
6091
- function Table$1({ data, columns, keyExtractor, selectable = false, expandable = false, onRowSelect, renderExpandedRow, emptyState, className = '', onSort, sortColumn: externalSortColumn, sortDirection: externalSortDirection, }) {
6092
- const [internalSortColumn, setInternalSortColumn] = React.useState(null);
6093
- const [internalSortDirection, setInternalSortDirection] = React.useState(null);
6094
- // Use external sort state if provided, otherwise use internal state
6095
- const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
6096
- const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
6097
- const [selectedRows, setSelectedRows] = React.useState(new Set());
6098
- const [expandedRows, setExpandedRows] = React.useState(new Set());
6099
- // Handle sorting
6100
- const handleSort = (columnKey) => {
6101
- let newDirection;
6102
- if (sortColumn === columnKey) {
6103
- if (sortDirection === 'asc') {
6104
- newDirection = 'desc';
6105
- }
6106
- else if (sortDirection === 'desc') {
6107
- newDirection = null;
6108
- }
6109
- else {
6110
- newDirection = 'asc';
6111
- }
6112
- }
6113
- else {
6114
- newDirection = 'asc';
6115
- }
6116
- // If using external sort control, call the callback
6117
- if (onSort) {
6118
- onSort(columnKey, newDirection);
6119
- }
6120
- else {
6121
- // Otherwise update internal state
6122
- setInternalSortColumn(newDirection === null ? null : columnKey);
6123
- setInternalSortDirection(newDirection);
6124
- }
6125
- };
6126
- // Handle row selection
6127
- const handleRowSelect = (rowKey) => {
6128
- const newSelected = new Set(selectedRows);
6129
- if (newSelected.has(rowKey)) {
6130
- newSelected.delete(rowKey);
6131
- }
6132
- else {
6133
- newSelected.add(rowKey);
6134
- }
6135
- setSelectedRows(newSelected);
6136
- onRowSelect?.(Array.from(newSelected));
6137
- };
6138
- // Handle select all
6139
- const handleSelectAll = () => {
6140
- if (selectedRows.size === data.length) {
6141
- setSelectedRows(new Set());
6142
- onRowSelect?.([]);
6143
- }
6144
- else {
6145
- const allKeys = new Set(data.map(keyExtractor));
6146
- setSelectedRows(allKeys);
6147
- onRowSelect?.(Array.from(allKeys));
6148
- }
6149
- };
6150
- // Handle row expansion
6151
- const handleRowExpand = (rowKey) => {
6152
- const newExpanded = new Set(expandedRows);
6153
- if (newExpanded.has(rowKey)) {
6154
- newExpanded.delete(rowKey);
6155
- }
6156
- else {
6157
- newExpanded.add(rowKey);
6158
- }
6159
- setExpandedRows(newExpanded);
6160
- };
6161
- const getSortIcon = (columnKey) => {
6162
- if (sortColumn !== columnKey) {
6163
- return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6164
- }
6165
- if (sortDirection === 'asc') {
6166
- return jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4 text-accent-600" });
6167
- }
6168
- if (sortDirection === 'desc') {
6169
- return jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-4 w-4 text-accent-600" });
6170
- }
6171
- return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6172
- };
6173
- if (data.length === 0 && emptyState) {
6174
- return jsxRuntime.jsx("div", { children: emptyState });
6175
- }
6176
- return (jsxRuntime.jsx("div", { className: `overflow-x-auto ${className}`, children: jsxRuntime.jsxs("table", { className: "table", children: [jsxRuntime.jsx("thead", { className: "table-header", children: jsxRuntime.jsxs("tr", { children: [selectable && (jsxRuntime.jsx("th", { className: "table-header-cell w-12", children: jsxRuntime.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 && jsxRuntime.jsx("th", { className: "table-header-cell w-12" }), columns.map((column) => (jsxRuntime.jsx("th", { className: "table-header-cell", style: { width: column.width }, children: column.sortable ? (jsxRuntime.jsxs("button", { onClick: () => handleSort(column.key), className: "group inline-flex items-center gap-2 hover:text-ink-900 transition-colors", children: [jsxRuntime.jsx("span", { children: column.header }), getSortIcon(column.key)] })) : (column.header) }, column.key)))] }) }), jsxRuntime.jsx("tbody", { children: data.map((row) => {
6177
- const rowKey = keyExtractor(row);
6178
- const isSelected = selectedRows.has(rowKey);
6179
- const isExpanded = expandedRows.has(rowKey);
6180
- return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { className: `table-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : ''}`, children: [selectable && (jsxRuntime.jsx("td", { className: "table-cell", children: jsxRuntime.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 && (jsxRuntime.jsx("td", { className: "table-cell", children: jsxRuntime.jsx("button", { onClick: () => handleRowExpand(rowKey), className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded ? 'Collapse row' : 'Expand row', children: isExpanded ? (jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" })) : (jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })) }) })), columns.map((column) => (jsxRuntime.jsx("td", { className: "table-cell", children: column.accessor ? column.accessor(row) : row[column.key] }, column.key)))] }), expandable && isExpanded && renderExpandedRow && (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0), className: "px-6 py-4 bg-paper-50", children: renderExpandedRow(row) }) }))] }, rowKey));
6181
- }) })] }) }));
6182
- }
6183
-
6184
6160
  function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, }) {
6185
6161
  const variantStyles = {
6186
6162
  success: 'bg-success-50 text-success-700 border-success-200',
@@ -6288,8 +6264,8 @@ const Avatar = ({ firstName, lastName, fallbackText = 'U', imageUrl, size = 'md'
6288
6264
  `, style: { textShadow: '0 1px 2px rgba(0,0,0,0.3)' }, children: getInitials() }) }));
6289
6265
  };
6290
6266
 
6291
- function EmptyState({ icon, title, description, action, secondaryAction, }) {
6292
- return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsxRuntime.jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsxRuntime.jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsxRuntime.jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), (action || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [action && (jsxRuntime.jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsxRuntime.jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
6267
+ function EmptyState({ icon, title, description, action, secondaryAction, children, }) {
6268
+ return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsxRuntime.jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsxRuntime.jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsxRuntime.jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), children && (jsxRuntime.jsx("div", { className: "mb-8 w-full max-w-md", children: children })), (action || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [action && (jsxRuntime.jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsxRuntime.jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
6293
6269
  }
6294
6270
 
6295
6271
  /**
@@ -7305,7 +7281,9 @@ function getColumnStyle(column, dynamicWidth) {
7305
7281
  */
7306
7282
  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,
7307
7283
  // Visual customization props
7308
- 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, }) {
7284
+ 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,
7285
+ // Pagination props
7286
+ paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true, }) {
7309
7287
  // Column resizing state
7310
7288
  const [columnWidths, setColumnWidths] = React.useState({});
7311
7289
  const [resizingColumn, setResizingColumn] = React.useState(null);
@@ -7538,16 +7516,30 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7538
7516
  }
7539
7517
  });
7540
7518
  }
7519
+ // Combine all actions: built-in first, then custom actions, then delete last
7520
+ // Delete is stored separately to ensure it's always last
7521
+ let deleteAction = null;
7541
7522
  if (onDelete) {
7542
- builtInActions.push({
7523
+ deleteAction = {
7543
7524
  label: 'Delete',
7544
7525
  icon: lucideReact.Trash,
7545
7526
  onClick: onDelete,
7546
7527
  variant: 'danger',
7547
7528
  tooltip: 'Delete item'
7548
- });
7529
+ };
7549
7530
  }
7550
- const allActions = [...builtInActions, ...actions];
7531
+ // Build final actions array with consistent ordering:
7532
+ // 1. Edit (first - most common action)
7533
+ // 2. View Details
7534
+ // 3. Add Related actions
7535
+ // 4. Manage Related actions
7536
+ // 5. Custom actions (from actions prop)
7537
+ // 6. Delete (always last - destructive action)
7538
+ const allActions = [
7539
+ ...builtInActions,
7540
+ ...actions,
7541
+ ...(deleteAction ? [deleteAction] : [])
7542
+ ];
7551
7543
  // Convert actions to menu items for context menu
7552
7544
  const convertActionsToMenuItems = (item) => {
7553
7545
  const visibleActions = allActions.filter(action => !action.show || action.show(item));
@@ -7896,8 +7888,22 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7896
7888
  })] }) }), jsxRuntime.jsx("tbody", { className: "bg-white table-loading transition-opacity duration-200", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
7897
7889
  // Wrap in scrollable container if virtualized
7898
7890
  const finalContent = virtualized ? (jsxRuntime.jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent })) : tableContent;
7891
+ // Calculate pagination values
7892
+ const effectiveTotalItems = totalItems ?? data.length;
7893
+ const totalPages = Math.ceil(effectiveTotalItems / pageSize);
7894
+ // Page size selector options
7895
+ const pageSizeSelectOptions = pageSizeOptions.map(size => ({
7896
+ value: String(size),
7897
+ label: `${size} per page`,
7898
+ }));
7899
+ // Render pagination controls
7900
+ const renderPaginationControls = () => {
7901
+ if (!paginated)
7902
+ return null;
7903
+ return (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsxRuntime.jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: ["Showing ", ((currentPage - 1) * pageSize) + 1, " - ", Math.min(currentPage * pageSize, effectiveTotalItems), " of ", effectiveTotalItems] })) : ('No items') })] }), totalPages > 1 && onPageChange && (jsxRuntime.jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
7904
+ };
7899
7905
  // Render with context menu
7900
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [finalContent, contextMenuState.isOpen && contextMenuState.item && (jsxRuntime.jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
7906
+ return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderPaginationControls(), finalContent, contextMenuState.isOpen && contextMenuState.item && (jsxRuntime.jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
7901
7907
  }
7902
7908
 
7903
7909
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -60476,7 +60482,6 @@ exports.StatusBar = StatusBar;
60476
60482
  exports.StepIndicator = StepIndicator;
60477
60483
  exports.Stepper = Stepper;
60478
60484
  exports.Switch = Switch;
60479
- exports.Table = Table$1;
60480
60485
  exports.Tabs = Tabs;
60481
60486
  exports.Text = Text;
60482
60487
  exports.Textarea = Textarea;