@papernote/ui 1.1.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 (114) hide show
  1. package/LICENSE +21 -21
  2. package/README.md +455 -455
  3. package/dist/components/Box.d.ts +2 -1
  4. package/dist/components/Box.d.ts.map +1 -1
  5. package/dist/components/Button.d.ts +10 -1
  6. package/dist/components/Button.d.ts.map +1 -1
  7. package/dist/components/Card.d.ts +11 -2
  8. package/dist/components/Card.d.ts.map +1 -1
  9. package/dist/components/CurrencyInput.d.ts +52 -0
  10. package/dist/components/CurrencyInput.d.ts.map +1 -0
  11. package/dist/components/DataTable.d.ts +19 -3
  12. package/dist/components/DataTable.d.ts.map +1 -1
  13. package/dist/components/EmptyState.d.ts +3 -1
  14. package/dist/components/EmptyState.d.ts.map +1 -1
  15. package/dist/components/Grid.d.ts +4 -2
  16. package/dist/components/Grid.d.ts.map +1 -1
  17. package/dist/components/Input.d.ts +2 -0
  18. package/dist/components/Input.d.ts.map +1 -1
  19. package/dist/components/Modal.d.ts.map +1 -1
  20. package/dist/components/MultiSelect.d.ts +13 -1
  21. package/dist/components/MultiSelect.d.ts.map +1 -1
  22. package/dist/components/Page.d.ts +2 -0
  23. package/dist/components/Page.d.ts.map +1 -1
  24. package/dist/components/PageLayout.d.ts +5 -1
  25. package/dist/components/PageLayout.d.ts.map +1 -1
  26. package/dist/components/Stack.d.ts +25 -5
  27. package/dist/components/Stack.d.ts.map +1 -1
  28. package/dist/components/Text.d.ts +20 -4
  29. package/dist/components/Text.d.ts.map +1 -1
  30. package/dist/components/Textarea.d.ts +2 -0
  31. package/dist/components/Textarea.d.ts.map +1 -1
  32. package/dist/components/index.d.ts +5 -3
  33. package/dist/components/index.d.ts.map +1 -1
  34. package/dist/index.d.ts +311 -49
  35. package/dist/index.esm.js +557 -224
  36. package/dist/index.esm.js.map +1 -1
  37. package/dist/index.js +555 -219
  38. package/dist/index.js.map +1 -1
  39. package/dist/styles.css +2838 -2679
  40. package/dist/utils/excelExport.d.ts +143 -0
  41. package/dist/utils/excelExport.d.ts.map +1 -0
  42. package/dist/utils/index.d.ts +2 -0
  43. package/dist/utils/index.d.ts.map +1 -1
  44. package/package.json +1 -1
  45. package/src/components/AdminModal.css +49 -49
  46. package/src/components/Box.stories.tsx +377 -0
  47. package/src/components/Box.tsx +8 -4
  48. package/src/components/Button.tsx +23 -10
  49. package/src/components/Card.tsx +20 -5
  50. package/src/components/CurrencyInput.stories.tsx +290 -0
  51. package/src/components/CurrencyInput.tsx +193 -0
  52. package/src/components/DataTable.stories.tsx +36 -25
  53. package/src/components/DataTable.tsx +170 -16
  54. package/src/components/EmptyState.stories.tsx +124 -72
  55. package/src/components/EmptyState.tsx +10 -0
  56. package/src/components/Grid.stories.tsx +348 -0
  57. package/src/components/Grid.tsx +12 -5
  58. package/src/components/Input.tsx +12 -2
  59. package/src/components/Modal.stories.tsx +64 -0
  60. package/src/components/Modal.tsx +15 -2
  61. package/src/components/MultiSelect.tsx +41 -10
  62. package/src/components/Page.stories.tsx +76 -0
  63. package/src/components/Page.tsx +35 -3
  64. package/src/components/PageLayout.stories.tsx +75 -0
  65. package/src/components/PageLayout.tsx +28 -9
  66. package/src/components/RoleManager.css +10 -10
  67. package/src/components/Spreadsheet.css +216 -216
  68. package/src/components/Spreadsheet.stories.tsx +362 -362
  69. package/src/components/Spreadsheet.tsx +351 -351
  70. package/src/components/SpreadsheetSimple.stories.tsx +27 -27
  71. package/src/components/Stack.stories.tsx +24 -1
  72. package/src/components/Stack.tsx +40 -10
  73. package/src/components/Tabs.tsx +152 -152
  74. package/src/components/Text.stories.tsx +273 -0
  75. package/src/components/Text.tsx +33 -8
  76. package/src/components/Textarea.tsx +32 -21
  77. package/src/components/index.ts +6 -4
  78. package/src/styles/index.css +41 -4
  79. package/src/utils/excelExport.stories.tsx +535 -0
  80. package/src/utils/excelExport.ts +225 -0
  81. package/src/utils/index.ts +3 -0
  82. package/tailwind.config.js +253 -253
  83. package/dist/components/Button.stories.d.ts +0 -51
  84. package/dist/components/Button.stories.d.ts.map +0 -1
  85. package/dist/components/ChartVisualizationUI.d.ts +0 -21
  86. package/dist/components/ChartVisualizationUI.d.ts.map +0 -1
  87. package/dist/components/ChatUI.d.ts +0 -23
  88. package/dist/components/ChatUI.d.ts.map +0 -1
  89. package/dist/components/CommissionDashboardUI.d.ts +0 -25
  90. package/dist/components/CommissionDashboardUI.d.ts.map +0 -1
  91. package/dist/components/DataTable.stories.d.ts +0 -23
  92. package/dist/components/DataTable.stories.d.ts.map +0 -1
  93. package/dist/components/FormField.d.ts +0 -35
  94. package/dist/components/FormField.d.ts.map +0 -1
  95. package/dist/components/Input.stories.d.ts +0 -366
  96. package/dist/components/Input.stories.d.ts.map +0 -1
  97. package/dist/components/InsightsPanelUI.d.ts +0 -21
  98. package/dist/components/InsightsPanelUI.d.ts.map +0 -1
  99. package/dist/components/PaymentHistoryTimeline.d.ts +0 -34
  100. package/dist/components/PaymentHistoryTimeline.d.ts.map +0 -1
  101. package/dist/components/RelationshipManagerUI.d.ts +0 -60
  102. package/dist/components/RelationshipManagerUI.d.ts.map +0 -1
  103. package/dist/components/RoleManager.d.ts +0 -19
  104. package/dist/components/RoleManager.d.ts.map +0 -1
  105. package/dist/components/SplitCommissionBadge.d.ts +0 -18
  106. package/dist/components/SplitCommissionBadge.d.ts.map +0 -1
  107. package/dist/components/Spreadsheet.css +0 -216
  108. package/dist/components/Table.d.ts +0 -26
  109. package/dist/components/Table.d.ts.map +0 -1
  110. package/dist/components/__tests__/Button.test.d.ts +0 -2
  111. package/dist/components/__tests__/Button.test.d.ts.map +0 -1
  112. package/dist/components/__tests__/Input.test.d.ts +0 -2
  113. package/dist/components/__tests__/Input.test.d.ts.map +0 -1
  114. 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: {
@@ -2550,6 +2619,7 @@ const sizeClasses$4 = {
2550
2619
  };
2551
2620
  function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton = true, animation = 'scale', }) {
2552
2621
  const modalRef = React.useRef(null);
2622
+ const mouseDownOnBackdrop = React.useRef(false);
2553
2623
  const titleId = React.useId();
2554
2624
  // Handle escape key
2555
2625
  React.useEffect(() => {
@@ -2567,11 +2637,22 @@ function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton
2567
2637
  document.body.style.overflow = 'unset';
2568
2638
  };
2569
2639
  }, [isOpen, onClose]);
2570
- // Handle click outside
2571
- const handleBackdropClick = (e) => {
2640
+ // Track if mousedown originated on the backdrop
2641
+ const handleBackdropMouseDown = (e) => {
2572
2642
  if (e.target === e.currentTarget) {
2643
+ mouseDownOnBackdrop.current = true;
2644
+ }
2645
+ else {
2646
+ mouseDownOnBackdrop.current = false;
2647
+ }
2648
+ };
2649
+ // Handle click outside - only close if both mousedown and click happened on backdrop
2650
+ const handleBackdropClick = (e) => {
2651
+ if (e.target === e.currentTarget && mouseDownOnBackdrop.current) {
2573
2652
  onClose();
2574
2653
  }
2654
+ // Reset the flag after handling click
2655
+ mouseDownOnBackdrop.current = false;
2575
2656
  };
2576
2657
  const getAnimationClass = () => {
2577
2658
  switch (animation) {
@@ -2591,7 +2672,7 @@ function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton
2591
2672
  };
2592
2673
  if (!isOpen)
2593
2674
  return null;
2594
- return (jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-ink-900 bg-opacity-50 backdrop-blur-sm animate-fade-in", onClick: handleBackdropClick, children: jsxRuntime.jsxs("div", { ref: modalRef, className: `${sizeClasses$4[size]} w-full bg-white bg-subtle-grain rounded-xl shadow-2xl border border-paper-200 ${getAnimationClass()}`, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-paper-200", children: [jsxRuntime.jsx("h3", { id: titleId, className: "text-lg font-medium text-ink-900", children: title }), showCloseButton && (jsxRuntime.jsx("button", { onClick: onClose, className: "text-ink-400 hover:text-ink-600 transition-colors", "aria-label": "Close modal", children: jsxRuntime.jsx(lucideReact.X, { className: "h-5 w-5" }) }))] }), jsxRuntime.jsx("div", { className: "px-6 py-4", children: children })] }) }));
2675
+ return (jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-ink-900 bg-opacity-50 backdrop-blur-sm animate-fade-in", onMouseDown: handleBackdropMouseDown, onClick: handleBackdropClick, children: jsxRuntime.jsxs("div", { ref: modalRef, className: `${sizeClasses$4[size]} w-full bg-white bg-subtle-grain rounded-xl shadow-2xl border border-paper-200 ${getAnimationClass()}`, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-paper-200", children: [jsxRuntime.jsx("h3", { id: titleId, className: "text-lg font-medium text-ink-900", children: title }), showCloseButton && (jsxRuntime.jsx("button", { onClick: onClose, className: "text-ink-400 hover:text-ink-600 transition-colors", "aria-label": "Close modal", children: jsxRuntime.jsx(lucideReact.X, { className: "h-5 w-5" }) }))] }), jsxRuntime.jsx("div", { className: "px-6 py-4", children: children })] }) }));
2595
2676
  }
2596
2677
  function ModalFooter({ children }) {
2597
2678
  return (jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-paper-200 bg-paper-50", children: children }));
@@ -5976,19 +6057,19 @@ function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'und
5976
6057
  spacing: orientation === 'vertical' ? 'mt-8' : 'mt-8',
5977
6058
  },
5978
6059
  };
5979
- return (jsxRuntime.jsxs("div", { className: `w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`, children: [jsxRuntime.jsx("div", { className: `
5980
- flex ${orientation === 'vertical' ? 'flex-col' : ''}
6060
+ return (jsxRuntime.jsxs("div", { className: `w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`, children: [jsxRuntime.jsx("div", { className: `
6061
+ flex ${orientation === 'vertical' ? 'flex-col' : ''}
5981
6062
  ${variant === 'underline'
5982
6063
  ? orientation === 'vertical'
5983
6064
  ? `border-r border-paper-200 ${sizeClasses[size].gap} pr-6`
5984
6065
  : `border-b border-paper-200 ${sizeClasses[size].gap}`
5985
- : `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`}
5986
- ${sizeClasses[size].minWidth}
6066
+ : `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`}
6067
+ ${sizeClasses[size].minWidth}
5987
6068
  `, role: "tablist", children: tabs.map((tab) => {
5988
6069
  const isActive = activeTab === tab.id;
5989
- return (jsxRuntime.jsxs("button", { role: "tab", "aria-selected": isActive, "aria-controls": `panel-${tab.id}`, disabled: tab.disabled, onClick: () => !tab.disabled && handleTabChange(tab.id), className: `
5990
- flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
5991
- ${orientation === 'vertical' ? 'w-full justify-start' : ''}
6070
+ return (jsxRuntime.jsxs("button", { role: "tab", "aria-selected": isActive, "aria-controls": `panel-${tab.id}`, disabled: tab.disabled, onClick: () => !tab.disabled && handleTabChange(tab.id), className: `
6071
+ flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
6072
+ ${orientation === 'vertical' ? 'w-full justify-start' : ''}
5992
6073
  ${variant === 'underline'
5993
6074
  ? isActive
5994
6075
  ? orientation === 'vertical'
@@ -5999,8 +6080,8 @@ function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'und
5999
6080
  : 'text-ink-600 hover:text-ink-900 border-b-2 border-transparent'
6000
6081
  : isActive
6001
6082
  ? 'bg-white text-accent-900 rounded-md shadow-xs'
6002
- : 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'}
6003
- ${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
6083
+ : 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'}
6084
+ ${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
6004
6085
  `, children: [tab.icon && jsxRuntime.jsx("span", { className: `flex-shrink-0 ${sizeClasses[size].icon}`, children: tab.icon }), jsxRuntime.jsx("span", { children: tab.label })] }, tab.id));
6005
6086
  }) }), jsxRuntime.jsx("div", { className: `${orientation === 'vertical' ? 'flex-1' : sizeClasses[size].spacing}`, children: tabs.map((tab) => (jsxRuntime.jsx("div", { id: `panel-${tab.id}`, role: "tabpanel", "aria-labelledby": tab.id, hidden: activeTab !== tab.id, className: activeTab === tab.id ? 'animate-fade-in' : '', children: activeTab === tab.id && tab.content }, tab.id))) })] }));
6006
6087
  }
@@ -6076,99 +6157,6 @@ function StepIndicator({ steps, currentStep, variant = 'horizontal', onStepClick
6076
6157
  }) }) }));
6077
6158
  }
6078
6159
 
6079
- function Table$1({ data, columns, keyExtractor, selectable = false, expandable = false, onRowSelect, renderExpandedRow, emptyState, className = '', onSort, sortColumn: externalSortColumn, sortDirection: externalSortDirection, }) {
6080
- const [internalSortColumn, setInternalSortColumn] = React.useState(null);
6081
- const [internalSortDirection, setInternalSortDirection] = React.useState(null);
6082
- // Use external sort state if provided, otherwise use internal state
6083
- const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
6084
- const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
6085
- const [selectedRows, setSelectedRows] = React.useState(new Set());
6086
- const [expandedRows, setExpandedRows] = React.useState(new Set());
6087
- // Handle sorting
6088
- const handleSort = (columnKey) => {
6089
- let newDirection;
6090
- if (sortColumn === columnKey) {
6091
- if (sortDirection === 'asc') {
6092
- newDirection = 'desc';
6093
- }
6094
- else if (sortDirection === 'desc') {
6095
- newDirection = null;
6096
- }
6097
- else {
6098
- newDirection = 'asc';
6099
- }
6100
- }
6101
- else {
6102
- newDirection = 'asc';
6103
- }
6104
- // If using external sort control, call the callback
6105
- if (onSort) {
6106
- onSort(columnKey, newDirection);
6107
- }
6108
- else {
6109
- // Otherwise update internal state
6110
- setInternalSortColumn(newDirection === null ? null : columnKey);
6111
- setInternalSortDirection(newDirection);
6112
- }
6113
- };
6114
- // Handle row selection
6115
- const handleRowSelect = (rowKey) => {
6116
- const newSelected = new Set(selectedRows);
6117
- if (newSelected.has(rowKey)) {
6118
- newSelected.delete(rowKey);
6119
- }
6120
- else {
6121
- newSelected.add(rowKey);
6122
- }
6123
- setSelectedRows(newSelected);
6124
- onRowSelect?.(Array.from(newSelected));
6125
- };
6126
- // Handle select all
6127
- const handleSelectAll = () => {
6128
- if (selectedRows.size === data.length) {
6129
- setSelectedRows(new Set());
6130
- onRowSelect?.([]);
6131
- }
6132
- else {
6133
- const allKeys = new Set(data.map(keyExtractor));
6134
- setSelectedRows(allKeys);
6135
- onRowSelect?.(Array.from(allKeys));
6136
- }
6137
- };
6138
- // Handle row expansion
6139
- const handleRowExpand = (rowKey) => {
6140
- const newExpanded = new Set(expandedRows);
6141
- if (newExpanded.has(rowKey)) {
6142
- newExpanded.delete(rowKey);
6143
- }
6144
- else {
6145
- newExpanded.add(rowKey);
6146
- }
6147
- setExpandedRows(newExpanded);
6148
- };
6149
- const getSortIcon = (columnKey) => {
6150
- if (sortColumn !== columnKey) {
6151
- return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6152
- }
6153
- if (sortDirection === 'asc') {
6154
- return jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4 text-accent-600" });
6155
- }
6156
- if (sortDirection === 'desc') {
6157
- return jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-4 w-4 text-accent-600" });
6158
- }
6159
- return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6160
- };
6161
- if (data.length === 0 && emptyState) {
6162
- return jsxRuntime.jsx("div", { children: emptyState });
6163
- }
6164
- 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) => {
6165
- const rowKey = keyExtractor(row);
6166
- const isSelected = selectedRows.has(rowKey);
6167
- const isExpanded = expandedRows.has(rowKey);
6168
- 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));
6169
- }) })] }) }));
6170
- }
6171
-
6172
6160
  function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, }) {
6173
6161
  const variantStyles = {
6174
6162
  success: 'bg-success-50 text-success-700 border-success-200',
@@ -6276,8 +6264,8 @@ const Avatar = ({ firstName, lastName, fallbackText = 'U', imageUrl, size = 'md'
6276
6264
  `, style: { textShadow: '0 1px 2px rgba(0,0,0,0.3)' }, children: getInitials() }) }));
6277
6265
  };
6278
6266
 
6279
- function EmptyState({ icon, title, description, action, secondaryAction, }) {
6280
- 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 }))] }))] }));
6281
6269
  }
6282
6270
 
6283
6271
  /**
@@ -6928,8 +6916,35 @@ const TwoColumnContent = ({ sidebar, children, className = '', }) => {
6928
6916
  * </PageLayout>
6929
6917
  * ```
6930
6918
  */
6931
- const Page = ({ children, maxWidth: _maxWidth = '7xl', className = '', padding: _padding = 'normal' }) => {
6932
- return (jsxRuntime.jsx("div", { className: "min-h-screen bg-paper-100", children: jsxRuntime.jsx("div", { className: `notebook-page notebook-margin notebook-ruled ${className}`, children: children }) }));
6919
+ const Page = ({ children, maxWidth = '7xl', className = '', padding = 'normal', fixed = false }) => {
6920
+ // Max width classes
6921
+ const maxWidthClasses = {
6922
+ '4xl': 'max-w-4xl',
6923
+ '5xl': 'max-w-5xl',
6924
+ '6xl': 'max-w-6xl',
6925
+ '7xl': 'max-w-7xl',
6926
+ 'full': 'max-w-full',
6927
+ };
6928
+ // Padding classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
6929
+ const paddingClasses = {
6930
+ none: fixed ? 'p-0' : 'pt-0 pl-0 pr-0 pb-0',
6931
+ sm: fixed ? 'p-4' : 'pt-4 pl-4 pr-4 pb-4 sm:pr-6 md:pr-8 sm:pb-6 md:pb-8',
6932
+ normal: fixed ? 'pt-12 pl-20 pr-16 pb-12' : 'pt-12 pl-20 pr-4 pb-4 sm:pr-8 md:pr-12 lg:pr-16 sm:pb-8 md:pb-12 lg:pb-16',
6933
+ lg: fixed ? 'pt-16 pl-24 pr-20 pb-16' : 'pt-16 pl-24 pr-6 pb-6 sm:pr-12 md:pr-16 lg:pr-20 sm:pb-12 md:pb-16 lg:pb-20',
6934
+ };
6935
+ // Margin classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
6936
+ const marginClasses = fixed
6937
+ ? 'mt-4 ml-4 mr-4 mb-4'
6938
+ : 'mt-4 ml-4 mr-4 mb-4 sm:mr-6 md:mr-8 lg:mr-auto sm:mb-6 md:mb-8';
6939
+ return (jsxRuntime.jsx("div", { className: "min-h-screen bg-paper-100", children: jsxRuntime.jsx("div", { className: `
6940
+ bg-white bg-subtle-grain rounded-sm shadow-lg border-l-4 border-paper-300
6941
+ min-h-[calc(100vh-2rem)] relative
6942
+ notebook-margin notebook-ruled
6943
+ ${maxWidthClasses[maxWidth]}
6944
+ ${paddingClasses[padding]}
6945
+ ${marginClasses}
6946
+ ${className}
6947
+ `.trim().replace(/\s+/g, ' '), children: children }) }));
6933
6948
  };
6934
6949
 
6935
6950
  /**
@@ -7264,9 +7279,11 @@ function getColumnStyle(column, dynamicWidth) {
7264
7279
  * />
7265
7280
  * ```
7266
7281
  */
7267
- function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
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,
7268
7283
  // Visual customization props
7269
- 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, }) {
7270
7287
  // Column resizing state
7271
7288
  const [columnWidths, setColumnWidths] = React.useState({});
7272
7289
  const [resizingColumn, setResizingColumn] = React.useState(null);
@@ -7281,6 +7298,12 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7281
7298
  const tableContainerRef = React.useRef(null);
7282
7299
  // Row hover state (for coordinating primary + secondary row highlighting)
7283
7300
  const [hoveredRowKey, setHoveredRowKey] = React.useState(null);
7301
+ // Context menu state
7302
+ const [contextMenuState, setContextMenuState] = React.useState({
7303
+ isOpen: false,
7304
+ position: { x: 0, y: 0 },
7305
+ item: null,
7306
+ });
7284
7307
  // Filter columns based on hiddenColumns
7285
7308
  const baseVisibleColumns = columns.filter(col => !hiddenColumns.includes(String(col.key)));
7286
7309
  // Initialize column order on mount or when columns change
@@ -7493,16 +7516,52 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7493
7516
  }
7494
7517
  });
7495
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;
7496
7522
  if (onDelete) {
7497
- builtInActions.push({
7523
+ deleteAction = {
7498
7524
  label: 'Delete',
7499
7525
  icon: lucideReact.Trash,
7500
7526
  onClick: onDelete,
7501
7527
  variant: 'danger',
7502
7528
  tooltip: 'Delete item'
7503
- });
7529
+ };
7504
7530
  }
7505
- 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
+ ];
7543
+ // Convert actions to menu items for context menu
7544
+ const convertActionsToMenuItems = (item) => {
7545
+ const visibleActions = allActions.filter(action => !action.show || action.show(item));
7546
+ return visibleActions.map((action, idx) => {
7547
+ let iconElement = null;
7548
+ if (action.icon) {
7549
+ if (React.isValidElement(action.icon)) {
7550
+ iconElement = action.icon;
7551
+ }
7552
+ else {
7553
+ iconElement = React.createElement(action.icon, { className: 'h-4 w-4' });
7554
+ }
7555
+ }
7556
+ return {
7557
+ id: `action-${idx}`,
7558
+ label: action.label,
7559
+ icon: iconElement,
7560
+ onClick: () => action.onClick(item),
7561
+ danger: action.variant === 'danger',
7562
+ };
7563
+ });
7564
+ };
7506
7565
  // Selection state management
7507
7566
  const [internalSelectedRows, setInternalSelectedRows] = React.useState(new Set());
7508
7567
  // Expansion state management
@@ -7660,7 +7719,19 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7660
7719
  // Hover state for row pair (primary + secondary)
7661
7720
  const isHovered = hoveredRowKey === rowKey;
7662
7721
  const hoverClass = disableHover ? '' : (isHovered ? 'bg-paper-100' : '');
7663
- return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { className: `table-row-stable ${onRowDoubleClick || onRowClick || onEdit || expandedRowConfig?.edit || expandedRowConfig?.details || expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length ? 'cursor-pointer' : ''} ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : hoverClass || rowBgClass} ${borderClass}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), onClick: () => onRowClick?.(item), onDoubleClick: () => {
7722
+ return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { className: `table-row-stable ${onRowDoubleClick || onRowClick || onEdit || expandedRowConfig?.edit || expandedRowConfig?.details || expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length ? 'cursor-pointer' : ''} ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : hoverClass || rowBgClass} ${borderClass}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), onClick: () => onRowClick?.(item), onContextMenu: (e) => {
7723
+ if (enableContextMenu && allActions.length > 0) {
7724
+ e.preventDefault();
7725
+ e.stopPropagation();
7726
+ const x = e.clientX;
7727
+ const y = e.clientY;
7728
+ setContextMenuState({
7729
+ isOpen: true,
7730
+ position: { x, y },
7731
+ item,
7732
+ });
7733
+ }
7734
+ }, onDoubleClick: () => {
7664
7735
  // Priority 1: If there's an onEdit handler (legacy), trigger it
7665
7736
  if (onEdit) {
7666
7737
  onEdit(item);
@@ -7816,10 +7887,23 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7816
7887
  }, children: jsxRuntime.jsx("div", { className: "absolute right-0 top-0 bottom-0 w-1 bg-paper-300 group-hover:bg-accent-400 transition-colors" }) }))] }, columnKey));
7817
7888
  })] }) }), jsxRuntime.jsx("tbody", { className: "bg-white table-loading transition-opacity duration-200", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
7818
7889
  // Wrap in scrollable container if virtualized
7819
- if (virtualized) {
7820
- return (jsxRuntime.jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent }));
7821
- }
7822
- return tableContent;
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
+ };
7905
+ // Render with context menu
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 }) }))] }));
7823
7907
  }
7824
7908
 
7825
7909
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -11631,12 +11715,12 @@ var bessel$1 = {};
11631
11715
 
11632
11716
  /* bessel.js (C) 2013-present SheetJS -- http://sheetjs.com */
11633
11717
 
11634
- (function (exports) {
11718
+ (function (exports$1) {
11635
11719
  (function (factory) {
11636
11720
  /*jshint ignore:start */
11637
11721
  if(typeof DO_NOT_EXPORT_BESSEL === 'undefined') {
11638
11722
  {
11639
- factory(exports);
11723
+ factory(exports$1);
11640
11724
  }
11641
11725
  } else {
11642
11726
  factory({});
@@ -11870,7 +11954,7 @@ var bessel$1 = {};
11870
11954
 
11871
11955
  var jstat = {exports: {}};
11872
11956
 
11873
- (function (module, exports) {
11957
+ (function (module, exports$1) {
11874
11958
  (function (window, factory) {
11875
11959
  {
11876
11960
  module.exports = factory();
@@ -30527,7 +30611,7 @@ var hasRequiredScheduler_production;
30527
30611
  function requireScheduler_production () {
30528
30612
  if (hasRequiredScheduler_production) return scheduler_production;
30529
30613
  hasRequiredScheduler_production = 1;
30530
- (function (exports) {
30614
+ (function (exports$1) {
30531
30615
  function push(heap, node) {
30532
30616
  var index = heap.length;
30533
30617
  heap.push(node);
@@ -30576,16 +30660,16 @@ function requireScheduler_production () {
30576
30660
  var diff = a.sortIndex - b.sortIndex;
30577
30661
  return 0 !== diff ? diff : a.id - b.id;
30578
30662
  }
30579
- exports.unstable_now = void 0;
30663
+ exports$1.unstable_now = void 0;
30580
30664
  if ("object" === typeof performance && "function" === typeof performance.now) {
30581
30665
  var localPerformance = performance;
30582
- exports.unstable_now = function () {
30666
+ exports$1.unstable_now = function () {
30583
30667
  return localPerformance.now();
30584
30668
  };
30585
30669
  } else {
30586
30670
  var localDate = Date,
30587
30671
  initialTime = localDate.now();
30588
- exports.unstable_now = function () {
30672
+ exports$1.unstable_now = function () {
30589
30673
  return localDate.now() - initialTime;
30590
30674
  };
30591
30675
  }
@@ -30633,14 +30717,14 @@ function requireScheduler_production () {
30633
30717
  function shouldYieldToHost() {
30634
30718
  return needsPaint
30635
30719
  ? true
30636
- : exports.unstable_now() - startTime < frameInterval
30720
+ : exports$1.unstable_now() - startTime < frameInterval
30637
30721
  ? false
30638
30722
  : true;
30639
30723
  }
30640
30724
  function performWorkUntilDeadline() {
30641
30725
  needsPaint = false;
30642
30726
  if (isMessageLoopRunning) {
30643
- var currentTime = exports.unstable_now();
30727
+ var currentTime = exports$1.unstable_now();
30644
30728
  startTime = currentTime;
30645
30729
  var hasMoreWork = true;
30646
30730
  try {
@@ -30670,7 +30754,7 @@ function requireScheduler_production () {
30670
30754
  var continuationCallback = callback(
30671
30755
  currentTask.expirationTime <= currentTime
30672
30756
  );
30673
- currentTime = exports.unstable_now();
30757
+ currentTime = exports$1.unstable_now();
30674
30758
  if ("function" === typeof continuationCallback) {
30675
30759
  currentTask.callback = continuationCallback;
30676
30760
  advanceTimers(currentTime);
@@ -30726,29 +30810,29 @@ function requireScheduler_production () {
30726
30810
  };
30727
30811
  function requestHostTimeout(callback, ms) {
30728
30812
  taskTimeoutID = localSetTimeout(function () {
30729
- callback(exports.unstable_now());
30813
+ callback(exports$1.unstable_now());
30730
30814
  }, ms);
30731
30815
  }
30732
- exports.unstable_IdlePriority = 5;
30733
- exports.unstable_ImmediatePriority = 1;
30734
- exports.unstable_LowPriority = 4;
30735
- exports.unstable_NormalPriority = 3;
30736
- exports.unstable_Profiling = null;
30737
- exports.unstable_UserBlockingPriority = 2;
30738
- exports.unstable_cancelCallback = function (task) {
30816
+ exports$1.unstable_IdlePriority = 5;
30817
+ exports$1.unstable_ImmediatePriority = 1;
30818
+ exports$1.unstable_LowPriority = 4;
30819
+ exports$1.unstable_NormalPriority = 3;
30820
+ exports$1.unstable_Profiling = null;
30821
+ exports$1.unstable_UserBlockingPriority = 2;
30822
+ exports$1.unstable_cancelCallback = function (task) {
30739
30823
  task.callback = null;
30740
30824
  };
30741
- exports.unstable_forceFrameRate = function (fps) {
30825
+ exports$1.unstable_forceFrameRate = function (fps) {
30742
30826
  0 > fps || 125 < fps
30743
30827
  ? console.error(
30744
30828
  "forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"
30745
30829
  )
30746
30830
  : (frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5);
30747
30831
  };
30748
- exports.unstable_getCurrentPriorityLevel = function () {
30832
+ exports$1.unstable_getCurrentPriorityLevel = function () {
30749
30833
  return currentPriorityLevel;
30750
30834
  };
30751
- exports.unstable_next = function (eventHandler) {
30835
+ exports$1.unstable_next = function (eventHandler) {
30752
30836
  switch (currentPriorityLevel) {
30753
30837
  case 1:
30754
30838
  case 2:
@@ -30766,10 +30850,10 @@ function requireScheduler_production () {
30766
30850
  currentPriorityLevel = previousPriorityLevel;
30767
30851
  }
30768
30852
  };
30769
- exports.unstable_requestPaint = function () {
30853
+ exports$1.unstable_requestPaint = function () {
30770
30854
  needsPaint = true;
30771
30855
  };
30772
- exports.unstable_runWithPriority = function (priorityLevel, eventHandler) {
30856
+ exports$1.unstable_runWithPriority = function (priorityLevel, eventHandler) {
30773
30857
  switch (priorityLevel) {
30774
30858
  case 1:
30775
30859
  case 2:
@@ -30788,12 +30872,12 @@ function requireScheduler_production () {
30788
30872
  currentPriorityLevel = previousPriorityLevel;
30789
30873
  }
30790
30874
  };
30791
- exports.unstable_scheduleCallback = function (
30875
+ exports$1.unstable_scheduleCallback = function (
30792
30876
  priorityLevel,
30793
30877
  callback,
30794
30878
  options
30795
30879
  ) {
30796
- var currentTime = exports.unstable_now();
30880
+ var currentTime = exports$1.unstable_now();
30797
30881
  "object" === typeof options && null !== options
30798
30882
  ? ((options = options.delay),
30799
30883
  (options =
@@ -30844,8 +30928,8 @@ function requireScheduler_production () {
30844
30928
  ((isMessageLoopRunning = true), schedulePerformWorkUntilDeadline())));
30845
30929
  return priorityLevel;
30846
30930
  };
30847
- exports.unstable_shouldYield = shouldYieldToHost;
30848
- exports.unstable_wrapCallback = function (callback) {
30931
+ exports$1.unstable_shouldYield = shouldYieldToHost;
30932
+ exports$1.unstable_wrapCallback = function (callback) {
30849
30933
  var parentPriorityLevel = currentPriorityLevel;
30850
30934
  return function () {
30851
30935
  var previousPriorityLevel = currentPriorityLevel;
@@ -30878,13 +30962,13 @@ var hasRequiredScheduler_development;
30878
30962
  function requireScheduler_development () {
30879
30963
  if (hasRequiredScheduler_development) return scheduler_development;
30880
30964
  hasRequiredScheduler_development = 1;
30881
- (function (exports) {
30965
+ (function (exports$1) {
30882
30966
  "production" !== process.env.NODE_ENV &&
30883
30967
  (function () {
30884
30968
  function performWorkUntilDeadline() {
30885
30969
  needsPaint = false;
30886
30970
  if (isMessageLoopRunning) {
30887
- var currentTime = exports.unstable_now();
30971
+ var currentTime = exports$1.unstable_now();
30888
30972
  startTime = currentTime;
30889
30973
  var hasMoreWork = true;
30890
30974
  try {
@@ -30915,7 +30999,7 @@ function requireScheduler_development () {
30915
30999
  var continuationCallback = callback(
30916
31000
  currentTask.expirationTime <= currentTime
30917
31001
  );
30918
- currentTime = exports.unstable_now();
31002
+ currentTime = exports$1.unstable_now();
30919
31003
  if ("function" === typeof continuationCallback) {
30920
31004
  currentTask.callback = continuationCallback;
30921
31005
  advanceTimers(currentTime);
@@ -31036,32 +31120,32 @@ function requireScheduler_development () {
31036
31120
  function shouldYieldToHost() {
31037
31121
  return needsPaint
31038
31122
  ? true
31039
- : exports.unstable_now() - startTime < frameInterval
31123
+ : exports$1.unstable_now() - startTime < frameInterval
31040
31124
  ? false
31041
31125
  : true;
31042
31126
  }
31043
31127
  function requestHostTimeout(callback, ms) {
31044
31128
  taskTimeoutID = localSetTimeout(function () {
31045
- callback(exports.unstable_now());
31129
+ callback(exports$1.unstable_now());
31046
31130
  }, ms);
31047
31131
  }
31048
31132
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
31049
31133
  "function" ===
31050
31134
  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
31051
31135
  __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
31052
- exports.unstable_now = void 0;
31136
+ exports$1.unstable_now = void 0;
31053
31137
  if (
31054
31138
  "object" === typeof performance &&
31055
31139
  "function" === typeof performance.now
31056
31140
  ) {
31057
31141
  var localPerformance = performance;
31058
- exports.unstable_now = function () {
31142
+ exports$1.unstable_now = function () {
31059
31143
  return localPerformance.now();
31060
31144
  };
31061
31145
  } else {
31062
31146
  var localDate = Date,
31063
31147
  initialTime = localDate.now();
31064
- exports.unstable_now = function () {
31148
+ exports$1.unstable_now = function () {
31065
31149
  return localDate.now() - initialTime;
31066
31150
  };
31067
31151
  }
@@ -31098,26 +31182,26 @@ function requireScheduler_development () {
31098
31182
  schedulePerformWorkUntilDeadline = function () {
31099
31183
  localSetTimeout(performWorkUntilDeadline, 0);
31100
31184
  };
31101
- exports.unstable_IdlePriority = 5;
31102
- exports.unstable_ImmediatePriority = 1;
31103
- exports.unstable_LowPriority = 4;
31104
- exports.unstable_NormalPriority = 3;
31105
- exports.unstable_Profiling = null;
31106
- exports.unstable_UserBlockingPriority = 2;
31107
- exports.unstable_cancelCallback = function (task) {
31185
+ exports$1.unstable_IdlePriority = 5;
31186
+ exports$1.unstable_ImmediatePriority = 1;
31187
+ exports$1.unstable_LowPriority = 4;
31188
+ exports$1.unstable_NormalPriority = 3;
31189
+ exports$1.unstable_Profiling = null;
31190
+ exports$1.unstable_UserBlockingPriority = 2;
31191
+ exports$1.unstable_cancelCallback = function (task) {
31108
31192
  task.callback = null;
31109
31193
  };
31110
- exports.unstable_forceFrameRate = function (fps) {
31194
+ exports$1.unstable_forceFrameRate = function (fps) {
31111
31195
  0 > fps || 125 < fps
31112
31196
  ? console.error(
31113
31197
  "forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"
31114
31198
  )
31115
31199
  : (frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5);
31116
31200
  };
31117
- exports.unstable_getCurrentPriorityLevel = function () {
31201
+ exports$1.unstable_getCurrentPriorityLevel = function () {
31118
31202
  return currentPriorityLevel;
31119
31203
  };
31120
- exports.unstable_next = function (eventHandler) {
31204
+ exports$1.unstable_next = function (eventHandler) {
31121
31205
  switch (currentPriorityLevel) {
31122
31206
  case 1:
31123
31207
  case 2:
@@ -31135,10 +31219,10 @@ function requireScheduler_development () {
31135
31219
  currentPriorityLevel = previousPriorityLevel;
31136
31220
  }
31137
31221
  };
31138
- exports.unstable_requestPaint = function () {
31222
+ exports$1.unstable_requestPaint = function () {
31139
31223
  needsPaint = true;
31140
31224
  };
31141
- exports.unstable_runWithPriority = function (priorityLevel, eventHandler) {
31225
+ exports$1.unstable_runWithPriority = function (priorityLevel, eventHandler) {
31142
31226
  switch (priorityLevel) {
31143
31227
  case 1:
31144
31228
  case 2:
@@ -31157,12 +31241,12 @@ function requireScheduler_development () {
31157
31241
  currentPriorityLevel = previousPriorityLevel;
31158
31242
  }
31159
31243
  };
31160
- exports.unstable_scheduleCallback = function (
31244
+ exports$1.unstable_scheduleCallback = function (
31161
31245
  priorityLevel,
31162
31246
  callback,
31163
31247
  options
31164
31248
  ) {
31165
- var currentTime = exports.unstable_now();
31249
+ var currentTime = exports$1.unstable_now();
31166
31250
  "object" === typeof options && null !== options
31167
31251
  ? ((options = options.delay),
31168
31252
  (options =
@@ -31214,8 +31298,8 @@ function requireScheduler_development () {
31214
31298
  schedulePerformWorkUntilDeadline())));
31215
31299
  return priorityLevel;
31216
31300
  };
31217
- exports.unstable_shouldYield = shouldYieldToHost;
31218
- exports.unstable_wrapCallback = function (callback) {
31301
+ exports$1.unstable_shouldYield = shouldYieldToHost;
31302
+ exports$1.unstable_wrapCallback = function (callback) {
31219
31303
  var parentPriorityLevel = currentPriorityLevel;
31220
31304
  return function () {
31221
31305
  var previousPriorityLevel = currentPriorityLevel;
@@ -35476,8 +35560,8 @@ return CRC32;
35476
35560
  })();
35477
35561
  /* [MS-CFB] v20171201 */
35478
35562
  var CFB = /*#__PURE__*/(function _CFB(){
35479
- var exports = {};
35480
- exports.version = '1.2.1';
35563
+ var exports$1 = {};
35564
+ exports$1.version = '1.2.1';
35481
35565
  /* [MS-CFB] 2.6.4 */
35482
35566
  function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
35483
35567
  var L = l.split("/"), R = r.split("/");
@@ -37149,12 +37233,12 @@ function cfb_mov(cfb/*:CFBContainer*/, old_name/*:string*/, new_name/*:string*/)
37149
37233
 
37150
37234
  function cfb_gc(cfb/*:CFBContainer*/)/*:void*/ { rebuild_cfb(cfb, true); }
37151
37235
 
37152
- exports.find = find;
37153
- exports.read = read;
37154
- exports.parse = parse;
37155
- exports.write = write;
37156
- exports.writeFile = write_file;
37157
- exports.utils = {
37236
+ exports$1.find = find;
37237
+ exports$1.read = read;
37238
+ exports$1.parse = parse;
37239
+ exports$1.write = write;
37240
+ exports$1.writeFile = write_file;
37241
+ exports$1.utils = {
37158
37242
  cfb_new: cfb_new,
37159
37243
  cfb_add: cfb_add,
37160
37244
  cfb_del: cfb_del,
@@ -37170,7 +37254,7 @@ exports.utils = {
37170
37254
  consts: consts
37171
37255
  };
37172
37256
 
37173
- return exports;
37257
+ return exports$1;
37174
37258
  })();
37175
37259
 
37176
37260
  /* normalize data for blob ctor */
@@ -58633,6 +58717,137 @@ function CurrencyDisplay({ amount, currency = 'USD', locale = 'en-US', className
58633
58717
  return (jsxRuntime.jsx("span", { className: combinedClasses, title: `${currency} ${safeAmount.toFixed(precision)}`, children: displayValue }));
58634
58718
  }
58635
58719
 
58720
+ /**
58721
+ * CurrencyInput - Specialized input for monetary values
58722
+ *
58723
+ * Automatically formats currency values with proper symbols and thousands separators.
58724
+ * Handles parsing and validation of numeric currency input.
58725
+ *
58726
+ * @example Basic usage
58727
+ * ```tsx
58728
+ * <CurrencyInput
58729
+ * label="Price"
58730
+ * value={price}
58731
+ * onChange={setPrice}
58732
+ * currency="USD"
58733
+ * />
58734
+ * ```
58735
+ *
58736
+ * @example With validation
58737
+ * ```tsx
58738
+ * <CurrencyInput
58739
+ * label="Budget"
58740
+ * value={budget}
58741
+ * onChange={setBudget}
58742
+ * min={0}
58743
+ * max={10000}
58744
+ * validationState={budget > 10000 ? 'error' : null}
58745
+ * validationMessage={budget > 10000 ? 'Exceeds maximum budget' : ''}
58746
+ * />
58747
+ * ```
58748
+ */
58749
+ const CurrencyInput = React.forwardRef(({ value, onChange, currency = 'USD', locale = 'en-US', precision = 2, allowNegative = false, min, max, onBlur, onFocus, ...props }, ref) => {
58750
+ const [displayValue, setDisplayValue] = React.useState('');
58751
+ const [isFocused, setIsFocused] = React.useState(false);
58752
+ // Get currency symbol
58753
+ const getCurrencySymbol = () => {
58754
+ const formatter = new Intl.NumberFormat(locale, {
58755
+ style: 'currency',
58756
+ currency,
58757
+ });
58758
+ const parts = formatter.formatToParts(0);
58759
+ const symbolPart = parts.find(part => part.type === 'currency');
58760
+ return symbolPart?.value || '$';
58761
+ };
58762
+ const currencySymbol = getCurrencySymbol();
58763
+ // Format number as currency
58764
+ const formatCurrency = (num) => {
58765
+ const formatter = new Intl.NumberFormat(locale, {
58766
+ minimumFractionDigits: isFocused ? 0 : precision,
58767
+ maximumFractionDigits: precision,
58768
+ });
58769
+ return formatter.format(num);
58770
+ };
58771
+ // Parse display value to number
58772
+ const parseValue = (str) => {
58773
+ if (!str || str === '')
58774
+ return null;
58775
+ // Remove all non-numeric characters except decimal point and minus sign
58776
+ let cleaned = str.replace(/[^\d.-]/g, '');
58777
+ // Handle multiple decimal points
58778
+ const parts = cleaned.split('.');
58779
+ if (parts.length > 2) {
58780
+ cleaned = parts[0] + '.' + parts.slice(1).join('');
58781
+ }
58782
+ // Handle multiple minus signs (keep only first)
58783
+ const minusCount = (cleaned.match(/-/g) || []).length;
58784
+ if (minusCount > 1) {
58785
+ const hasLeadingMinus = cleaned.startsWith('-');
58786
+ cleaned = cleaned.replace(/-/g, '');
58787
+ if (hasLeadingMinus)
58788
+ cleaned = '-' + cleaned;
58789
+ }
58790
+ // Parse to float
58791
+ const num = parseFloat(cleaned);
58792
+ if (isNaN(num))
58793
+ return null;
58794
+ // Apply precision
58795
+ return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
58796
+ };
58797
+ // Update display value when external value changes
58798
+ React.useEffect(() => {
58799
+ if (value === undefined || value === null || value === '') {
58800
+ setDisplayValue('');
58801
+ }
58802
+ else {
58803
+ const numValue = typeof value === 'string' ? parseFloat(value) : value;
58804
+ if (!isNaN(numValue)) {
58805
+ setDisplayValue(formatCurrency(numValue));
58806
+ }
58807
+ }
58808
+ }, [value, isFocused]);
58809
+ const handleChange = (e) => {
58810
+ const inputValue = e.target.value;
58811
+ setDisplayValue(inputValue);
58812
+ const numValue = parseValue(inputValue);
58813
+ // Validate constraints
58814
+ if (numValue !== null) {
58815
+ if (!allowNegative && numValue < 0)
58816
+ return;
58817
+ if (min !== undefined && numValue < min)
58818
+ return;
58819
+ if (max !== undefined && numValue > max)
58820
+ return;
58821
+ }
58822
+ onChange?.(numValue);
58823
+ };
58824
+ const handleFocus = (e) => {
58825
+ setIsFocused(true);
58826
+ // Remove formatting when focused for easier editing
58827
+ if (value !== undefined && value !== null && value !== '') {
58828
+ const numValue = typeof value === 'string' ? parseFloat(value) : value;
58829
+ if (!isNaN(numValue)) {
58830
+ setDisplayValue(numValue.toString());
58831
+ }
58832
+ }
58833
+ onFocus?.(e);
58834
+ };
58835
+ const handleBlur = (e) => {
58836
+ setIsFocused(false);
58837
+ // Reformat on blur
58838
+ const numValue = parseValue(displayValue);
58839
+ if (numValue !== null) {
58840
+ setDisplayValue(formatCurrency(numValue));
58841
+ }
58842
+ else if (displayValue === '') {
58843
+ setDisplayValue('');
58844
+ }
58845
+ onBlur?.(e);
58846
+ };
58847
+ return (jsxRuntime.jsx(Input, { ref: ref, type: "text", value: displayValue, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, prefix: currencySymbol, ...props }));
58848
+ });
58849
+ CurrencyInput.displayName = 'CurrencyInput';
58850
+
58636
58851
  const formatOptions = {
58637
58852
  short: {
58638
58853
  year: 'numeric',
@@ -59543,8 +59758,19 @@ const AppLayout = ({ children, toolbarSections = [], className = '', showToolbar
59543
59758
  * </Layout>
59544
59759
  * ```
59545
59760
  */
59546
- function PageLayout({ title, description, children, className = '', headerContent }) {
59547
- return (jsxRuntime.jsxs(Page, { children: [headerContent, jsxRuntime.jsxs("div", { className: `p-6 max-w-7xl mx-auto pb-20 ${className}`, children: [jsxRuntime.jsxs("div", { className: "mb-8", children: [jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-ink-900 mb-2", children: title }), description && (jsxRuntime.jsx("p", { className: "text-ink-600", children: description }))] }), children] })] }));
59761
+ function PageLayout({ title, description, children, className = '', headerContent, maxWidth = '7xl', fixed = false }) {
59762
+ // Responsive padding classes - fixed left/top, responsive right/bottom
59763
+ const paddingClasses = fixed
59764
+ ? 'p-6 pb-20'
59765
+ : 'pt-6 pl-6 pr-2 pb-8 sm:pr-4 md:pr-6 sm:pb-12 md:pb-16 lg:pb-20';
59766
+ const maxWidthClasses = {
59767
+ '4xl': 'max-w-4xl',
59768
+ '5xl': 'max-w-5xl',
59769
+ '6xl': 'max-w-6xl',
59770
+ '7xl': 'max-w-7xl',
59771
+ 'full': 'max-w-full',
59772
+ };
59773
+ return (jsxRuntime.jsxs(Page, { padding: "none", maxWidth: maxWidth, fixed: fixed, children: [headerContent, jsxRuntime.jsxs("div", { className: `${paddingClasses} ${maxWidthClasses[maxWidth]} mx-auto ${className}`, children: [jsxRuntime.jsxs("div", { className: "mb-8", children: [jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-ink-900 mb-2", children: title }), description && (jsxRuntime.jsx("p", { className: "text-ink-600", children: description }))] }), children] })] }));
59548
59774
  }
59549
59775
 
59550
59776
  const sizeClasses = {
@@ -59916,6 +60142,113 @@ function loadColumnOrder(tableId) {
59916
60142
  }
59917
60143
  }
59918
60144
 
60145
+ /**
60146
+ * Export data to Excel file
60147
+ *
60148
+ * A standalone utility for exporting any data array to Excel format.
60149
+ * Works independently of the Spreadsheet component.
60150
+ *
60151
+ * **Features:**
60152
+ * - Export arrays of objects to Excel
60153
+ * - Custom column headers and ordering
60154
+ * - Value formatting with custom functions
60155
+ * - Multi-sheet support
60156
+ * - Automatic type handling
60157
+ *
60158
+ * @example
60159
+ * ```typescript
60160
+ * // Simple export - uses object keys as headers
60161
+ * const data = [
60162
+ * { id: 1, name: 'Product A', price: 29.99 },
60163
+ * { id: 2, name: 'Product B', price: 49.99 },
60164
+ * ];
60165
+ * exportToExcel({ data, filename: 'products.xlsx' });
60166
+ *
60167
+ * // Custom columns with formatting
60168
+ * exportToExcel({
60169
+ * data: users,
60170
+ * filename: 'users.xlsx',
60171
+ * columns: [
60172
+ * { key: 'id', label: 'ID' },
60173
+ * { key: 'name', label: 'Full Name' },
60174
+ * { key: 'email', label: 'Email Address' },
60175
+ * { key: 'createdAt', label: 'Joined', format: (date) => new Date(date).toLocaleDateString() },
60176
+ * { key: 'isActive', label: 'Status', format: (active) => active ? 'Active' : 'Inactive' },
60177
+ * ],
60178
+ * });
60179
+ *
60180
+ * // Multi-sheet export
60181
+ * const wb = utils.book_new();
60182
+ * exportToExcel({ data: products, sheetName: 'Products', workbook: wb });
60183
+ * exportToExcel({ data: orders, sheetName: 'Orders', workbook: wb });
60184
+ * writeFile(wb, 'multi-sheet.xlsx');
60185
+ * ```
60186
+ *
60187
+ * @param options - Export configuration options
60188
+ * @returns WorkBook if workbook option provided, otherwise void (auto-downloads)
60189
+ */
60190
+ function exportToExcel({ data, filename = 'export.xlsx', sheetName = 'Sheet1', columns, includeHeaders = true, workbook, }) {
60191
+ if (!data || data.length === 0) {
60192
+ throw new Error('No data provided for export');
60193
+ }
60194
+ let worksheetData;
60195
+ if (columns) {
60196
+ // Use custom columns with specific ordering and formatting
60197
+ const headers = columns.map((col) => col.label);
60198
+ const rows = data.map((row) => columns.map((col) => {
60199
+ const value = row[col.key];
60200
+ return col.format ? col.format(value) : value ?? '';
60201
+ }));
60202
+ worksheetData = includeHeaders ? [headers, ...rows] : rows;
60203
+ }
60204
+ else {
60205
+ // Auto-generate from object keys
60206
+ if (includeHeaders) {
60207
+ const headers = Object.keys(data[0]);
60208
+ const rows = data.map((row) => headers.map((key) => row[key] ?? ''));
60209
+ worksheetData = [headers, ...rows];
60210
+ }
60211
+ else {
60212
+ const headers = Object.keys(data[0]);
60213
+ worksheetData = data.map((row) => headers.map((key) => row[key] ?? ''));
60214
+ }
60215
+ }
60216
+ const worksheet = utils.aoa_to_sheet(worksheetData);
60217
+ // If workbook provided, add sheet and return (for multi-sheet exports)
60218
+ if (workbook) {
60219
+ utils.book_append_sheet(workbook, worksheet, sheetName);
60220
+ return workbook;
60221
+ }
60222
+ // Otherwise, create workbook and download
60223
+ const newWorkbook = utils.book_new();
60224
+ utils.book_append_sheet(newWorkbook, worksheet, sheetName);
60225
+ writeFileSync(newWorkbook, filename);
60226
+ }
60227
+ function exportDataTableToExcel({ data, columns, filename = 'export.xlsx', sheetName = 'Sheet1', }) {
60228
+ const excelColumns = columns.map((col) => ({
60229
+ key: col.key,
60230
+ label: col.header,
60231
+ }));
60232
+ exportToExcel({
60233
+ data,
60234
+ columns: excelColumns,
60235
+ filename,
60236
+ sheetName,
60237
+ });
60238
+ }
60239
+ function createMultiSheetExcel({ filename, sheets }) {
60240
+ const workbook = utils.book_new();
60241
+ sheets.forEach((sheet) => {
60242
+ exportToExcel({
60243
+ data: sheet.data,
60244
+ sheetName: sheet.name,
60245
+ columns: sheet.columns,
60246
+ workbook,
60247
+ });
60248
+ });
60249
+ writeFileSync(workbook, filename);
60250
+ }
60251
+
59919
60252
  function useColumnResize(options = {}) {
59920
60253
  const { tableId, persist = false } = options;
59921
60254
  const [columnWidths, setColumnWidths] = React.useState({});
@@ -60066,6 +60399,7 @@ exports.ConfirmDialog = ConfirmDialog;
60066
60399
  exports.ContextMenu = ContextMenu;
60067
60400
  exports.ControlBar = ControlBar;
60068
60401
  exports.CurrencyDisplay = CurrencyDisplay;
60402
+ exports.CurrencyInput = CurrencyInput;
60069
60403
  exports.Dashboard = Dashboard;
60070
60404
  exports.DashboardContent = DashboardContent;
60071
60405
  exports.DashboardHeader = DashboardHeader;
@@ -60148,7 +60482,6 @@ exports.StatusBar = StatusBar;
60148
60482
  exports.StepIndicator = StepIndicator;
60149
60483
  exports.Stepper = Stepper;
60150
60484
  exports.Switch = Switch;
60151
- exports.Table = Table$1;
60152
60485
  exports.Tabs = Tabs;
60153
60486
  exports.Text = Text;
60154
60487
  exports.Textarea = Textarea;
@@ -60169,8 +60502,11 @@ exports.addWarningMessage = addWarningMessage;
60169
60502
  exports.calculateColumnWidth = calculateColumnWidth;
60170
60503
  exports.createActionsSection = createActionsSection;
60171
60504
  exports.createFiltersSection = createFiltersSection;
60505
+ exports.createMultiSheetExcel = createMultiSheetExcel;
60172
60506
  exports.createPageControlsSection = createPageControlsSection;
60173
60507
  exports.createQueryDetailsSection = createQueryDetailsSection;
60508
+ exports.exportDataTableToExcel = exportDataTableToExcel;
60509
+ exports.exportToExcel = exportToExcel;
60174
60510
  exports.formatStatisticValue = formatStatisticValue;
60175
60511
  exports.formatStatistics = formatStatistics;
60176
60512
  exports.loadColumnOrder = loadColumnOrder;