@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.esm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
- import { Loader2, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Check, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Info, Trash2, Circle, ChevronsRight, ChevronsLeft, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, Home, ArrowUpDown, ArrowUp, ArrowDown, FileText, Image, File as File$1, User, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Download, Save, XCircle, Filter, BarChart3, MessageSquare } from 'lucide-react';
3
2
  import * as React from 'react';
4
3
  import React__default, { forwardRef, useState, useRef, useId, useImperativeHandle, useEffect, useCallback, useMemo, cloneElement, isValidElement, Component, createContext as createContext$1, useLayoutEffect, createElement, useContext, useReducer } from 'react';
4
+ import { Loader2, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Check, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Info, Trash2, Circle, ChevronsRight, ChevronsLeft, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, Home, FileText, Image, File as File$1, User, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Download, Save, XCircle, Filter, BarChart3, MessageSquare } from 'lucide-react';
5
5
  import { createPortal } from 'react-dom';
6
6
  import { Link as Link$1 } from 'react-router-dom';
7
7
 
@@ -11,6 +11,8 @@ import { Link as Link$1 } from 'react-router-dom';
11
11
  * A versatile button component that supports multiple visual styles, sizes, icons,
12
12
  * loading states, and notification badges.
13
13
  *
14
+ * Supports ref forwarding for DOM access.
15
+ *
14
16
  * @example Basic usage
15
17
  * ```tsx
16
18
  * <Button variant="primary">Click me</Button>
@@ -37,8 +39,14 @@ import { Link as Link$1 } from 'react-router-dom';
37
39
  * <Bell />
38
40
  * </Button>
39
41
  * ```
42
+ *
43
+ * @example With ref
44
+ * ```tsx
45
+ * const buttonRef = useRef<HTMLButtonElement>(null);
46
+ * <Button ref={buttonRef}>Focusable</Button>
47
+ * ```
40
48
  */
41
- function Button({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }) {
49
+ const Button = forwardRef(({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }, ref) => {
42
50
  const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-400 disabled:opacity-40 disabled:cursor-not-allowed';
43
51
  const variantStyles = {
44
52
  primary: 'bg-accent-500 text-white border-accent-500 hover:bg-accent-600 hover:shadow-sm active:scale-[0.98]',
@@ -69,7 +77,7 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
69
77
  md: 'min-w-[18px] h-[18px] text-[11px] px-1.5',
70
78
  lg: 'min-w-[20px] h-5 text-xs px-1.5',
71
79
  };
72
- const buttonElement = (jsxs("button", { className: `
80
+ const buttonElement = (jsxs("button", { ref: ref, className: `
73
81
  ${baseStyles}
74
82
  ${variantStyles[variant]}
75
83
  ${sizeStyles[size]}
@@ -92,7 +100,8 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
92
100
  shadow-sm
93
101
  pointer-events-none
94
102
  `, "aria-label": `${badgeContent} notifications`, children: badgeContent })] }));
95
- }
103
+ });
104
+ Button.displayName = 'Button';
96
105
 
97
106
  /**
98
107
  * ButtonGroup component - Toggle button group for single or multiple selection.
@@ -239,7 +248,7 @@ function ButtonGroup({ options, value, values = [], onChange, onChangeMultiple,
239
248
  * />
240
249
  * ```
241
250
  */
242
- const Input = forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
251
+ const Input = forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, loading = false, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
243
252
  const inputId = id || `input-${Math.random().toString(36).substring(2, 9)}`;
244
253
  const [showPassword, setShowPassword] = useState(false);
245
254
  // Handle clear button click
@@ -311,7 +320,7 @@ const Input = forwardRef(({ label, helperText, validationState, validationMessag
311
320
  ${validationState && !suffix && !suffixIcon && !showPasswordToggle ? 'pr-10' : ''}
312
321
  ${(showPasswordToggle && type === 'password') || validationState || suffix || suffixIcon ? 'pr-20' : ''}
313
322
  ${className}
314
- `, ...props }), suffix && (jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && (jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsx(X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsx(EyeOff, { className: "h-5 w-5" }) : jsx(Eye, { className: "h-5 w-5" }) })), validationState && (jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
323
+ `, ...props }), suffix && (jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [loading && (jsx("div", { className: "pointer-events-none text-ink-400", children: jsx(Loader2, { className: "h-5 w-5 animate-spin" }) })), suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && !loading && (jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsx(X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsx(EyeOff, { className: "h-5 w-5" }) : jsx(Eye, { className: "h-5 w-5" }) })), validationState && (jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
315
324
  });
316
325
  Input.displayName = 'Input';
317
326
 
@@ -518,11 +527,18 @@ const Select = forwardRef((props, ref) => {
518
527
  });
519
528
  Select.displayName = 'Select';
520
529
 
521
- function MultiSelect({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, 'aria-label': ariaLabel, }) {
530
+ const MultiSelect = forwardRef(({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, loading = false, 'aria-label': ariaLabel, }, ref) => {
522
531
  const [isOpen, setIsOpen] = useState(false);
523
532
  const [searchQuery, setSearchQuery] = useState('');
524
533
  const selectRef = useRef(null);
525
534
  const searchInputRef = useRef(null);
535
+ const triggerRef = useRef(null);
536
+ // Expose imperative methods
537
+ useImperativeHandle(ref, () => ({
538
+ focus: () => triggerRef.current?.focus(),
539
+ open: () => !disabled && setIsOpen(true),
540
+ close: () => setIsOpen(false),
541
+ }));
526
542
  const selectedOptions = options.filter(opt => value.includes(opt.value));
527
543
  const hasReachedMax = maxSelections ? value.length >= maxSelections : false;
528
544
  const filteredOptions = searchable && searchQuery
@@ -569,11 +585,11 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
569
585
  e.stopPropagation();
570
586
  onChange?.([]);
571
587
  };
572
- return (jsxs("div", { className: "w-full", children: [label && (jsx("label", { className: "label", children: label })), jsxs("div", { ref: selectRef, className: "relative", children: [jsxs("button", { type: "button", onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, className: `
588
+ return (jsxs("div", { className: "w-full", children: [label && (jsx("label", { className: "label", children: label })), jsxs("div", { ref: selectRef, className: "relative", children: [jsxs("button", { ref: triggerRef, type: "button", onClick: () => !disabled && !loading && setIsOpen(!isOpen), disabled: disabled || loading, className: `
573
589
  input w-full flex items-center justify-between min-h-[42px]
574
590
  ${error ? 'border-error-400 focus:border-error-400 focus:ring-error-400' : ''}
575
- ${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
576
- `, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsx("span", { className: "text-xs", children: option.icon }), option.label, jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsx(X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxs("div", { className: "flex items-center gap-2 ml-2", children: [selectedOptions.length > 0 && !disabled && (jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsx(X, { className: "h-4 w-4" }) })), jsx(ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` })] })] }), isOpen && (jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsx("div", { className: "p-2 border-b border-paper-200", children: jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
591
+ ${disabled || loading ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
592
+ `, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsx("span", { className: "text-xs", children: option.icon }), option.label, jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsx(X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxs("div", { className: "flex items-center gap-2 ml-2", children: [loading && (jsx(Loader2, { className: "h-4 w-4 text-ink-400 animate-spin" })), !loading && selectedOptions.length > 0 && !disabled && (jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsx(X, { className: "h-4 w-4" }) })), !loading && (jsx(ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` }))] })] }), isOpen && (jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsx("div", { className: "p-2 border-b border-paper-200", children: jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
577
593
  const isSelected = value.includes(option.value);
578
594
  const isDisabled = option.disabled || (hasReachedMax && !isSelected);
579
595
  return (jsx("button", { type: "button", onClick: () => !isDisabled && handleToggle(option.value), disabled: isDisabled, className: `
@@ -585,7 +601,8 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
585
601
  ${isSelected ? 'bg-accent-600 border-accent-600' : 'border-paper-300'}
586
602
  `, children: isSelected && jsx(Check, { className: "h-3 w-3 text-white" }) }), option.icon && jsx("span", { children: option.icon }), option.label] }) }, option.value));
587
603
  })) })] }))] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || error) && (jsx("p", { className: `text-xs ${error ? 'text-error-600' : 'text-ink-600'}`, children: error || helperText })), maxSelections && (jsxs("p", { className: `text-xs ml-auto ${hasReachedMax ? 'text-warning-600 font-medium' : 'text-ink-500'}`, children: [value.length, " / ", maxSelections, " selected"] }))] })] }));
588
- }
604
+ });
605
+ MultiSelect.displayName = 'MultiSelect';
589
606
 
590
607
  const Switch = forwardRef(({ checked, onChange, label, description, disabled = false, size = 'md', loading = false, }, ref) => {
591
608
  // Generate unique IDs for ARIA
@@ -632,7 +649,7 @@ const Switch = forwardRef(({ checked, onChange, label, description, disabled = f
632
649
  });
633
650
  Switch.displayName = 'Switch';
634
651
 
635
- const Textarea = forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', className = '', id, value, rows = 4, ...props }, ref) => {
652
+ const Textarea = forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', loading = false, className = '', id, value, rows = 4, ...props }, ref) => {
636
653
  const textareaId = id || `textarea-${Math.random().toString(36).substring(2, 9)}`;
637
654
  const currentLength = typeof value === 'string' ? value.length : 0;
638
655
  const internalRef = useRef(null);
@@ -707,14 +724,15 @@ const Textarea = forwardRef(({ label, helperText, validationState, validationMes
707
724
  return 'text-ink-600';
708
725
  }
709
726
  };
710
- return (jsxs("div", { className: "w-full", children: [label && (jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
711
- block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
712
- bg-white bg-subtle-grain transition-all duration-200
713
- focus:outline-none focus:ring-2 ${getResizeClass()}
714
- disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
715
- ${getValidationClasses()}
716
- ${className}
717
- `, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
727
+ return (jsxs("div", { className: "w-full", children: [label && (jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxs("div", { className: "relative", children: [jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
728
+ block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
729
+ bg-white bg-subtle-grain transition-all duration-200
730
+ focus:outline-none focus:ring-2 ${getResizeClass()}
731
+ disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
732
+ ${getValidationClasses()}
733
+ ${loading ? 'pr-10' : ''}
734
+ ${className}
735
+ `, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), loading && (jsx("div", { className: "absolute top-3 right-3 pointer-events-none", children: jsx(Loader2, { className: "h-5 w-5 text-ink-400 animate-spin" }) }))] }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
718
736
  });
719
737
  Textarea.displayName = 'Textarea';
720
738
 
@@ -1930,6 +1948,8 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
1930
1948
  /**
1931
1949
  * Card - Container component with paper aesthetic and subtle shadow
1932
1950
  *
1951
+ * Supports ref forwarding for DOM access.
1952
+ *
1933
1953
  * A content container with paper texture, border, and shadow effects. Supports
1934
1954
  * different sizes, variants (padding/shadow levels), and loading states.
1935
1955
  *
@@ -1959,8 +1979,14 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
1959
1979
  * <p>Content</p>
1960
1980
  * </Card>
1961
1981
  * ```
1982
+ *
1983
+ * @example With ref
1984
+ * ```tsx
1985
+ * const cardRef = useRef<HTMLDivElement>(null);
1986
+ * <Card ref={cardRef}>Content</Card>
1987
+ * ```
1962
1988
  */
1963
- function Card({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, }) {
1989
+ const Card = forwardRef(({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, ...htmlProps }, ref) => {
1964
1990
  const baseStyles = 'bg-white bg-subtle-grain border-2 border-paper-300 transition-shadow duration-200';
1965
1991
  const variantStyles = {
1966
1992
  default: 'rounded-xl shadow-lg p-8',
@@ -1976,8 +2002,9 @@ function Card({ children, variant = 'default', width = 'auto', className = '', o
1976
2002
  full: 'w-full',
1977
2003
  };
1978
2004
  const interactiveStyles = onClick || hoverable ? 'cursor-pointer hover:shadow-md' : '';
1979
- return (jsx("div", { className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxs("div", { className: "space-y-4", children: [jsx(Skeleton, { className: "h-6 w-3/4" }), jsx(Skeleton, { className: "h-4 w-full" }), jsx(Skeleton, { className: "h-4 w-5/6" }), jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
1980
- }
2005
+ return (jsx("div", { ref: ref, ...htmlProps, className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxs("div", { className: "space-y-4", children: [jsx(Skeleton, { className: "h-6 w-3/4" }), jsx(Skeleton, { className: "h-4 w-full" }), jsx(Skeleton, { className: "h-4 w-5/6" }), jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
2006
+ });
2007
+ Card.displayName = 'Card';
1981
2008
  /**
1982
2009
  * CardHeader - Header section for Card component
1983
2010
  *
@@ -2075,15 +2102,34 @@ function Separator({ orientation = 'horizontal', className = '', spacing = 'md',
2075
2102
  /**
2076
2103
  * Stack component for arranging children vertically or horizontally with consistent spacing.
2077
2104
  *
2078
- * Spacing scale:
2105
+ * Supports ref forwarding for DOM access.
2106
+ *
2107
+ * Spacing scale (use either `spacing` or `gap` prop - they're aliases):
2079
2108
  * - none: 0
2080
2109
  * - xs: 0.5rem (2)
2081
2110
  * - sm: 0.75rem (3)
2082
2111
  * - md: 1.5rem (6)
2083
2112
  * - lg: 2rem (8)
2084
2113
  * - xl: 3rem (12)
2114
+ *
2115
+ * @example
2116
+ * ```tsx
2117
+ * // Using spacing prop
2118
+ * <Stack spacing="md">
2119
+ * <Card>Item 1</Card>
2120
+ * <Card>Item 2</Card>
2121
+ * </Stack>
2122
+ *
2123
+ * // Using gap prop (alias)
2124
+ * <Stack gap="md">
2125
+ * <Card>Item 1</Card>
2126
+ * <Card>Item 2</Card>
2127
+ * </Stack>
2128
+ * ```
2085
2129
  */
2086
- const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stretch', justify = 'start', wrap = false, className = '', }) => {
2130
+ const Stack = forwardRef(({ children, direction = 'vertical', spacing, gap, align = 'stretch', justify = 'start', wrap = false, className = '', ...htmlProps }, ref) => {
2131
+ // Use gap as alias for spacing (spacing takes precedence if both provided)
2132
+ const effectiveSpacing = spacing ?? gap ?? 'md';
2087
2133
  const spacingClasses = {
2088
2134
  vertical: {
2089
2135
  none: '',
@@ -2115,20 +2161,23 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
2115
2161
  between: 'justify-between',
2116
2162
  around: 'justify-around',
2117
2163
  };
2118
- return (jsx("div", { className: `
2164
+ return (jsx("div", { ref: ref, ...htmlProps, className: `
2119
2165
  flex
2120
2166
  ${direction === 'vertical' ? 'flex-col' : 'flex-row'}
2121
2167
  ${wrap ? 'flex-wrap' : ''}
2122
- ${spacingClasses[direction][spacing]}
2168
+ ${spacingClasses[direction][effectiveSpacing]}
2123
2169
  ${alignClasses[align]}
2124
2170
  ${justifyClasses[justify]}
2125
2171
  ${className}
2126
2172
  `, children: children }));
2127
- };
2173
+ });
2174
+ Stack.displayName = 'Stack';
2128
2175
 
2129
2176
  /**
2130
2177
  * Grid component for arranging children in a CSS grid layout.
2131
2178
  *
2179
+ * Supports ref forwarding for DOM access.
2180
+ *
2132
2181
  * Column options: 1, 2, 3, 4, 6, 12
2133
2182
  *
2134
2183
  * Responsive breakpoints (mobile-first):
@@ -2153,7 +2202,7 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
2153
2202
  * <Card>Item 2</Card>
2154
2203
  * </Grid>
2155
2204
  */
2156
- const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', }) => {
2205
+ const Grid = forwardRef(({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', ...htmlProps }, ref) => {
2157
2206
  // Base column classes
2158
2207
  const baseColumnClasses = {
2159
2208
  1: 'grid-cols-1',
@@ -2212,18 +2261,20 @@ const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '
2212
2261
  lg ? lgColumnClasses[lg] : '',
2213
2262
  xl ? xlColumnClasses[xl] : '',
2214
2263
  ].filter(Boolean).join(' ');
2215
- return (jsx("div", { className: `
2264
+ return (jsx("div", { ref: ref, ...htmlProps, className: `
2216
2265
  grid
2217
2266
  ${columnClassList}
2218
2267
  ${gapClasses[gap]}
2219
2268
  ${className}
2220
2269
  `, children: children }));
2221
- };
2270
+ });
2271
+ Grid.displayName = 'Grid';
2222
2272
 
2223
2273
  /**
2224
2274
  * Box component for generic containers with design system spacing and borders.
2275
+ * Supports ref forwarding for DOM access.
2225
2276
  */
2226
- const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }) => {
2277
+ const Box = forwardRef(({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }, ref) => {
2227
2278
  const spacingMap = {
2228
2279
  none: '0',
2229
2280
  xs: '2',
@@ -2308,7 +2359,7 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
2308
2359
  };
2309
2360
  return roundedClasses[rounded];
2310
2361
  };
2311
- return (jsx("div", { ...htmlProps, className: `
2362
+ return (jsx("div", { ref: ref, ...htmlProps, className: `
2312
2363
  ${getPaddingClass()}
2313
2364
  ${getMarginClass()}
2314
2365
  ${borderClasses[border]}
@@ -2318,7 +2369,8 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
2318
2369
  ${getHeightClass()}
2319
2370
  ${className}
2320
2371
  `, children: children }));
2321
- };
2372
+ });
2373
+ Box.displayName = 'Box';
2322
2374
 
2323
2375
  /**
2324
2376
  * GridItem component for items within a Grid layout.
@@ -2363,6 +2415,8 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
2363
2415
  /**
2364
2416
  * Text component for consistent typography across the application.
2365
2417
  *
2418
+ * Supports ref forwarding for DOM access.
2419
+ *
2366
2420
  * Size scale:
2367
2421
  * - xs: 0.75rem (12px)
2368
2422
  * - sm: 0.875rem (14px)
@@ -2370,8 +2424,21 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
2370
2424
  * - lg: 1.125rem (18px)
2371
2425
  * - xl: 1.25rem (20px)
2372
2426
  * - 2xl: 1.5rem (24px)
2427
+ *
2428
+ * @example
2429
+ * ```tsx
2430
+ * <Text size="lg" weight="semibold" color="primary">
2431
+ * Hello World
2432
+ * </Text>
2433
+ *
2434
+ * <Text color="warning">Warning message</Text>
2435
+ *
2436
+ * // With ref
2437
+ * const textRef = useRef<HTMLParagraphElement>(null);
2438
+ * <Text ref={textRef}>Measurable text</Text>
2439
+ * ```
2373
2440
  */
2374
- const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', }) => {
2441
+ const Text = forwardRef(({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', ...htmlProps }, ref) => {
2375
2442
  const sizeClasses = {
2376
2443
  xs: 'text-xs',
2377
2444
  sm: 'text-sm',
@@ -2393,6 +2460,7 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
2393
2460
  accent: 'text-primary-600',
2394
2461
  error: 'text-error-600',
2395
2462
  success: 'text-success-600',
2463
+ warning: 'text-warning-600',
2396
2464
  };
2397
2465
  const alignClasses = {
2398
2466
  left: 'text-left',
@@ -2424,8 +2492,9 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
2424
2492
  lineClamp ? lineClampClasses[lineClamp] : '',
2425
2493
  className,
2426
2494
  ].filter(Boolean).join(' ');
2427
- return (jsx(Component, { className: classes, children: children }));
2428
- };
2495
+ return (jsx(Component, { ref: ref, className: classes, ...htmlProps, children: children }));
2496
+ });
2497
+ Text.displayName = 'Text';
2429
2498
 
2430
2499
  const toastStyles = {
2431
2500
  success: {
@@ -2530,6 +2599,7 @@ const sizeClasses$4 = {
2530
2599
  };
2531
2600
  function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton = true, animation = 'scale', }) {
2532
2601
  const modalRef = useRef(null);
2602
+ const mouseDownOnBackdrop = useRef(false);
2533
2603
  const titleId = useId();
2534
2604
  // Handle escape key
2535
2605
  useEffect(() => {
@@ -2547,11 +2617,22 @@ function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton
2547
2617
  document.body.style.overflow = 'unset';
2548
2618
  };
2549
2619
  }, [isOpen, onClose]);
2550
- // Handle click outside
2551
- const handleBackdropClick = (e) => {
2620
+ // Track if mousedown originated on the backdrop
2621
+ const handleBackdropMouseDown = (e) => {
2552
2622
  if (e.target === e.currentTarget) {
2623
+ mouseDownOnBackdrop.current = true;
2624
+ }
2625
+ else {
2626
+ mouseDownOnBackdrop.current = false;
2627
+ }
2628
+ };
2629
+ // Handle click outside - only close if both mousedown and click happened on backdrop
2630
+ const handleBackdropClick = (e) => {
2631
+ if (e.target === e.currentTarget && mouseDownOnBackdrop.current) {
2553
2632
  onClose();
2554
2633
  }
2634
+ // Reset the flag after handling click
2635
+ mouseDownOnBackdrop.current = false;
2555
2636
  };
2556
2637
  const getAnimationClass = () => {
2557
2638
  switch (animation) {
@@ -2571,7 +2652,7 @@ function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton
2571
2652
  };
2572
2653
  if (!isOpen)
2573
2654
  return null;
2574
- return (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: 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: [jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-paper-200", children: [jsx("h3", { id: titleId, className: "text-lg font-medium text-ink-900", children: title }), showCloseButton && (jsx("button", { onClick: onClose, className: "text-ink-400 hover:text-ink-600 transition-colors", "aria-label": "Close modal", children: jsx(X, { className: "h-5 w-5" }) }))] }), jsx("div", { className: "px-6 py-4", children: children })] }) }));
2655
+ return (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: 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: [jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-paper-200", children: [jsx("h3", { id: titleId, className: "text-lg font-medium text-ink-900", children: title }), showCloseButton && (jsx("button", { onClick: onClose, className: "text-ink-400 hover:text-ink-600 transition-colors", "aria-label": "Close modal", children: jsx(X, { className: "h-5 w-5" }) }))] }), jsx("div", { className: "px-6 py-4", children: children })] }) }));
2575
2656
  }
2576
2657
  function ModalFooter({ children }) {
2577
2658
  return (jsx("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-paper-200 bg-paper-50", children: children }));
@@ -5956,19 +6037,19 @@ function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'und
5956
6037
  spacing: orientation === 'vertical' ? 'mt-8' : 'mt-8',
5957
6038
  },
5958
6039
  };
5959
- return (jsxs("div", { className: `w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`, children: [jsx("div", { className: `
5960
- flex ${orientation === 'vertical' ? 'flex-col' : ''}
6040
+ return (jsxs("div", { className: `w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`, children: [jsx("div", { className: `
6041
+ flex ${orientation === 'vertical' ? 'flex-col' : ''}
5961
6042
  ${variant === 'underline'
5962
6043
  ? orientation === 'vertical'
5963
6044
  ? `border-r border-paper-200 ${sizeClasses[size].gap} pr-6`
5964
6045
  : `border-b border-paper-200 ${sizeClasses[size].gap}`
5965
- : `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`}
5966
- ${sizeClasses[size].minWidth}
6046
+ : `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`}
6047
+ ${sizeClasses[size].minWidth}
5967
6048
  `, role: "tablist", children: tabs.map((tab) => {
5968
6049
  const isActive = activeTab === tab.id;
5969
- return (jsxs("button", { role: "tab", "aria-selected": isActive, "aria-controls": `panel-${tab.id}`, disabled: tab.disabled, onClick: () => !tab.disabled && handleTabChange(tab.id), className: `
5970
- flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
5971
- ${orientation === 'vertical' ? 'w-full justify-start' : ''}
6050
+ return (jsxs("button", { role: "tab", "aria-selected": isActive, "aria-controls": `panel-${tab.id}`, disabled: tab.disabled, onClick: () => !tab.disabled && handleTabChange(tab.id), className: `
6051
+ flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
6052
+ ${orientation === 'vertical' ? 'w-full justify-start' : ''}
5972
6053
  ${variant === 'underline'
5973
6054
  ? isActive
5974
6055
  ? orientation === 'vertical'
@@ -5979,8 +6060,8 @@ function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'und
5979
6060
  : 'text-ink-600 hover:text-ink-900 border-b-2 border-transparent'
5980
6061
  : isActive
5981
6062
  ? 'bg-white text-accent-900 rounded-md shadow-xs'
5982
- : 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'}
5983
- ${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
6063
+ : 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'}
6064
+ ${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
5984
6065
  `, children: [tab.icon && jsx("span", { className: `flex-shrink-0 ${sizeClasses[size].icon}`, children: tab.icon }), jsx("span", { children: tab.label })] }, tab.id));
5985
6066
  }) }), jsx("div", { className: `${orientation === 'vertical' ? 'flex-1' : sizeClasses[size].spacing}`, children: tabs.map((tab) => (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))) })] }));
5986
6067
  }
@@ -6056,99 +6137,6 @@ function StepIndicator({ steps, currentStep, variant = 'horizontal', onStepClick
6056
6137
  }) }) }));
6057
6138
  }
6058
6139
 
6059
- function Table$1({ data, columns, keyExtractor, selectable = false, expandable = false, onRowSelect, renderExpandedRow, emptyState, className = '', onSort, sortColumn: externalSortColumn, sortDirection: externalSortDirection, }) {
6060
- const [internalSortColumn, setInternalSortColumn] = useState(null);
6061
- const [internalSortDirection, setInternalSortDirection] = useState(null);
6062
- // Use external sort state if provided, otherwise use internal state
6063
- const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
6064
- const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
6065
- const [selectedRows, setSelectedRows] = useState(new Set());
6066
- const [expandedRows, setExpandedRows] = useState(new Set());
6067
- // Handle sorting
6068
- const handleSort = (columnKey) => {
6069
- let newDirection;
6070
- if (sortColumn === columnKey) {
6071
- if (sortDirection === 'asc') {
6072
- newDirection = 'desc';
6073
- }
6074
- else if (sortDirection === 'desc') {
6075
- newDirection = null;
6076
- }
6077
- else {
6078
- newDirection = 'asc';
6079
- }
6080
- }
6081
- else {
6082
- newDirection = 'asc';
6083
- }
6084
- // If using external sort control, call the callback
6085
- if (onSort) {
6086
- onSort(columnKey, newDirection);
6087
- }
6088
- else {
6089
- // Otherwise update internal state
6090
- setInternalSortColumn(newDirection === null ? null : columnKey);
6091
- setInternalSortDirection(newDirection);
6092
- }
6093
- };
6094
- // Handle row selection
6095
- const handleRowSelect = (rowKey) => {
6096
- const newSelected = new Set(selectedRows);
6097
- if (newSelected.has(rowKey)) {
6098
- newSelected.delete(rowKey);
6099
- }
6100
- else {
6101
- newSelected.add(rowKey);
6102
- }
6103
- setSelectedRows(newSelected);
6104
- onRowSelect?.(Array.from(newSelected));
6105
- };
6106
- // Handle select all
6107
- const handleSelectAll = () => {
6108
- if (selectedRows.size === data.length) {
6109
- setSelectedRows(new Set());
6110
- onRowSelect?.([]);
6111
- }
6112
- else {
6113
- const allKeys = new Set(data.map(keyExtractor));
6114
- setSelectedRows(allKeys);
6115
- onRowSelect?.(Array.from(allKeys));
6116
- }
6117
- };
6118
- // Handle row expansion
6119
- const handleRowExpand = (rowKey) => {
6120
- const newExpanded = new Set(expandedRows);
6121
- if (newExpanded.has(rowKey)) {
6122
- newExpanded.delete(rowKey);
6123
- }
6124
- else {
6125
- newExpanded.add(rowKey);
6126
- }
6127
- setExpandedRows(newExpanded);
6128
- };
6129
- const getSortIcon = (columnKey) => {
6130
- if (sortColumn !== columnKey) {
6131
- return jsx(ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6132
- }
6133
- if (sortDirection === 'asc') {
6134
- return jsx(ArrowUp, { className: "h-4 w-4 text-accent-600" });
6135
- }
6136
- if (sortDirection === 'desc') {
6137
- return jsx(ArrowDown, { className: "h-4 w-4 text-accent-600" });
6138
- }
6139
- return jsx(ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
6140
- };
6141
- if (data.length === 0 && emptyState) {
6142
- return jsx("div", { children: emptyState });
6143
- }
6144
- return (jsx("div", { className: `overflow-x-auto ${className}`, children: jsxs("table", { className: "table", children: [jsx("thead", { className: "table-header", children: jsxs("tr", { children: [selectable && (jsx("th", { className: "table-header-cell w-12", children: jsx("input", { type: "checkbox", checked: selectedRows.size === data.length && data.length > 0, onChange: handleSelectAll, className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": "Select all rows" }) })), expandable && jsx("th", { className: "table-header-cell w-12" }), columns.map((column) => (jsx("th", { className: "table-header-cell", style: { width: column.width }, children: column.sortable ? (jsxs("button", { onClick: () => handleSort(column.key), className: "group inline-flex items-center gap-2 hover:text-ink-900 transition-colors", children: [jsx("span", { children: column.header }), getSortIcon(column.key)] })) : (column.header) }, column.key)))] }) }), jsx("tbody", { children: data.map((row) => {
6145
- const rowKey = keyExtractor(row);
6146
- const isSelected = selectedRows.has(rowKey);
6147
- const isExpanded = expandedRows.has(rowKey);
6148
- return (jsxs(React__default.Fragment, { children: [jsxs("tr", { className: `table-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : ''}`, children: [selectable && (jsx("td", { className: "table-cell", children: jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleRowSelect(rowKey), className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": `Select row ${rowKey}` }) })), expandable && (jsx("td", { className: "table-cell", children: jsx("button", { onClick: () => handleRowExpand(rowKey), className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded ? 'Collapse row' : 'Expand row', children: isExpanded ? (jsx(ChevronDown, { className: "h-4 w-4" })) : (jsx(ChevronRight, { className: "h-4 w-4" })) }) })), columns.map((column) => (jsx("td", { className: "table-cell", children: column.accessor ? column.accessor(row) : row[column.key] }, column.key)))] }), expandable && isExpanded && renderExpandedRow && (jsx("tr", { children: jsx("td", { colSpan: columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0), className: "px-6 py-4 bg-paper-50", children: renderExpandedRow(row) }) }))] }, rowKey));
6149
- }) })] }) }));
6150
- }
6151
-
6152
6140
  function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, }) {
6153
6141
  const variantStyles = {
6154
6142
  success: 'bg-success-50 text-success-700 border-success-200',
@@ -6256,8 +6244,8 @@ const Avatar = ({ firstName, lastName, fallbackText = 'U', imageUrl, size = 'md'
6256
6244
  `, style: { textShadow: '0 1px 2px rgba(0,0,0,0.3)' }, children: getInitials() }) }));
6257
6245
  };
6258
6246
 
6259
- function EmptyState({ icon, title, description, action, secondaryAction, }) {
6260
- return (jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), (action || secondaryAction) && (jsxs("div", { className: "flex items-center gap-3", children: [action && (jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
6247
+ function EmptyState({ icon, title, description, action, secondaryAction, children, }) {
6248
+ return (jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), children && (jsx("div", { className: "mb-8 w-full max-w-md", children: children })), (action || secondaryAction) && (jsxs("div", { className: "flex items-center gap-3", children: [action && (jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
6261
6249
  }
6262
6250
 
6263
6251
  /**
@@ -6908,8 +6896,35 @@ const TwoColumnContent = ({ sidebar, children, className = '', }) => {
6908
6896
  * </PageLayout>
6909
6897
  * ```
6910
6898
  */
6911
- const Page = ({ children, maxWidth: _maxWidth = '7xl', className = '', padding: _padding = 'normal' }) => {
6912
- return (jsx("div", { className: "min-h-screen bg-paper-100", children: jsx("div", { className: `notebook-page notebook-margin notebook-ruled ${className}`, children: children }) }));
6899
+ const Page = ({ children, maxWidth = '7xl', className = '', padding = 'normal', fixed = false }) => {
6900
+ // Max width classes
6901
+ const maxWidthClasses = {
6902
+ '4xl': 'max-w-4xl',
6903
+ '5xl': 'max-w-5xl',
6904
+ '6xl': 'max-w-6xl',
6905
+ '7xl': 'max-w-7xl',
6906
+ 'full': 'max-w-full',
6907
+ };
6908
+ // Padding classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
6909
+ const paddingClasses = {
6910
+ none: fixed ? 'p-0' : 'pt-0 pl-0 pr-0 pb-0',
6911
+ sm: fixed ? 'p-4' : 'pt-4 pl-4 pr-4 pb-4 sm:pr-6 md:pr-8 sm:pb-6 md:pb-8',
6912
+ 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',
6913
+ 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',
6914
+ };
6915
+ // Margin classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
6916
+ const marginClasses = fixed
6917
+ ? 'mt-4 ml-4 mr-4 mb-4'
6918
+ : 'mt-4 ml-4 mr-4 mb-4 sm:mr-6 md:mr-8 lg:mr-auto sm:mb-6 md:mb-8';
6919
+ return (jsx("div", { className: "min-h-screen bg-paper-100", children: jsx("div", { className: `
6920
+ bg-white bg-subtle-grain rounded-sm shadow-lg border-l-4 border-paper-300
6921
+ min-h-[calc(100vh-2rem)] relative
6922
+ notebook-margin notebook-ruled
6923
+ ${maxWidthClasses[maxWidth]}
6924
+ ${paddingClasses[padding]}
6925
+ ${marginClasses}
6926
+ ${className}
6927
+ `.trim().replace(/\s+/g, ' '), children: children }) }));
6913
6928
  };
6914
6929
 
6915
6930
  /**
@@ -7244,9 +7259,11 @@ function getColumnStyle(column, dynamicWidth) {
7244
7259
  * />
7245
7260
  * ```
7246
7261
  */
7247
- 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,
7262
+ function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], enableContextMenu = true, onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
7248
7263
  // Visual customization props
7249
- striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60, }) {
7264
+ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
7265
+ // Pagination props
7266
+ paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true, }) {
7250
7267
  // Column resizing state
7251
7268
  const [columnWidths, setColumnWidths] = useState({});
7252
7269
  const [resizingColumn, setResizingColumn] = useState(null);
@@ -7261,6 +7278,12 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7261
7278
  const tableContainerRef = useRef(null);
7262
7279
  // Row hover state (for coordinating primary + secondary row highlighting)
7263
7280
  const [hoveredRowKey, setHoveredRowKey] = useState(null);
7281
+ // Context menu state
7282
+ const [contextMenuState, setContextMenuState] = useState({
7283
+ isOpen: false,
7284
+ position: { x: 0, y: 0 },
7285
+ item: null,
7286
+ });
7264
7287
  // Filter columns based on hiddenColumns
7265
7288
  const baseVisibleColumns = columns.filter(col => !hiddenColumns.includes(String(col.key)));
7266
7289
  // Initialize column order on mount or when columns change
@@ -7473,16 +7496,52 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7473
7496
  }
7474
7497
  });
7475
7498
  }
7499
+ // Combine all actions: built-in first, then custom actions, then delete last
7500
+ // Delete is stored separately to ensure it's always last
7501
+ let deleteAction = null;
7476
7502
  if (onDelete) {
7477
- builtInActions.push({
7503
+ deleteAction = {
7478
7504
  label: 'Delete',
7479
7505
  icon: Trash,
7480
7506
  onClick: onDelete,
7481
7507
  variant: 'danger',
7482
7508
  tooltip: 'Delete item'
7483
- });
7509
+ };
7484
7510
  }
7485
- const allActions = [...builtInActions, ...actions];
7511
+ // Build final actions array with consistent ordering:
7512
+ // 1. Edit (first - most common action)
7513
+ // 2. View Details
7514
+ // 3. Add Related actions
7515
+ // 4. Manage Related actions
7516
+ // 5. Custom actions (from actions prop)
7517
+ // 6. Delete (always last - destructive action)
7518
+ const allActions = [
7519
+ ...builtInActions,
7520
+ ...actions,
7521
+ ...(deleteAction ? [deleteAction] : [])
7522
+ ];
7523
+ // Convert actions to menu items for context menu
7524
+ const convertActionsToMenuItems = (item) => {
7525
+ const visibleActions = allActions.filter(action => !action.show || action.show(item));
7526
+ return visibleActions.map((action, idx) => {
7527
+ let iconElement = null;
7528
+ if (action.icon) {
7529
+ if (React__default.isValidElement(action.icon)) {
7530
+ iconElement = action.icon;
7531
+ }
7532
+ else {
7533
+ iconElement = React__default.createElement(action.icon, { className: 'h-4 w-4' });
7534
+ }
7535
+ }
7536
+ return {
7537
+ id: `action-${idx}`,
7538
+ label: action.label,
7539
+ icon: iconElement,
7540
+ onClick: () => action.onClick(item),
7541
+ danger: action.variant === 'danger',
7542
+ };
7543
+ });
7544
+ };
7486
7545
  // Selection state management
7487
7546
  const [internalSelectedRows, setInternalSelectedRows] = useState(new Set());
7488
7547
  // Expansion state management
@@ -7640,7 +7699,19 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7640
7699
  // Hover state for row pair (primary + secondary)
7641
7700
  const isHovered = hoveredRowKey === rowKey;
7642
7701
  const hoverClass = disableHover ? '' : (isHovered ? 'bg-paper-100' : '');
7643
- return (jsxs(React__default.Fragment, { children: [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: () => {
7702
+ return (jsxs(React__default.Fragment, { children: [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) => {
7703
+ if (enableContextMenu && allActions.length > 0) {
7704
+ e.preventDefault();
7705
+ e.stopPropagation();
7706
+ const x = e.clientX;
7707
+ const y = e.clientY;
7708
+ setContextMenuState({
7709
+ isOpen: true,
7710
+ position: { x, y },
7711
+ item,
7712
+ });
7713
+ }
7714
+ }, onDoubleClick: () => {
7644
7715
  // Priority 1: If there's an onEdit handler (legacy), trigger it
7645
7716
  if (onEdit) {
7646
7717
  onEdit(item);
@@ -7796,10 +7867,23 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
7796
7867
  }, children: jsx("div", { className: "absolute right-0 top-0 bottom-0 w-1 bg-paper-300 group-hover:bg-accent-400 transition-colors" }) }))] }, columnKey));
7797
7868
  })] }) }), jsx("tbody", { className: "bg-white table-loading transition-opacity duration-200", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
7798
7869
  // Wrap in scrollable container if virtualized
7799
- if (virtualized) {
7800
- return (jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent }));
7801
- }
7802
- return tableContent;
7870
+ const finalContent = virtualized ? (jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent })) : tableContent;
7871
+ // Calculate pagination values
7872
+ const effectiveTotalItems = totalItems ?? data.length;
7873
+ const totalPages = Math.ceil(effectiveTotalItems / pageSize);
7874
+ // Page size selector options
7875
+ const pageSizeSelectOptions = pageSizeOptions.map(size => ({
7876
+ value: String(size),
7877
+ label: `${size} per page`,
7878
+ }));
7879
+ // Render pagination controls
7880
+ const renderPaginationControls = () => {
7881
+ if (!paginated)
7882
+ return null;
7883
+ return (jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxs(Fragment, { children: ["Showing ", ((currentPage - 1) * pageSize) + 1, " - ", Math.min(currentPage * pageSize, effectiveTotalItems), " of ", effectiveTotalItems] })) : ('No items') })] }), totalPages > 1 && onPageChange && (jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
7884
+ };
7885
+ // Render with context menu
7886
+ return (jsxs(Fragment, { children: [renderPaginationControls(), finalContent, contextMenuState.isOpen && contextMenuState.item && (jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
7803
7887
  }
7804
7888
 
7805
7889
  var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
@@ -11611,12 +11695,12 @@ var bessel$1 = {};
11611
11695
 
11612
11696
  /* bessel.js (C) 2013-present SheetJS -- http://sheetjs.com */
11613
11697
 
11614
- (function (exports) {
11698
+ (function (exports$1) {
11615
11699
  (function (factory) {
11616
11700
  /*jshint ignore:start */
11617
11701
  if(typeof DO_NOT_EXPORT_BESSEL === 'undefined') {
11618
11702
  {
11619
- factory(exports);
11703
+ factory(exports$1);
11620
11704
  }
11621
11705
  } else {
11622
11706
  factory({});
@@ -11850,7 +11934,7 @@ var bessel$1 = {};
11850
11934
 
11851
11935
  var jstat = {exports: {}};
11852
11936
 
11853
- (function (module, exports) {
11937
+ (function (module, exports$1) {
11854
11938
  (function (window, factory) {
11855
11939
  {
11856
11940
  module.exports = factory();
@@ -30467,7 +30551,7 @@ var hooks = {
30467
30551
  DepParser: DepParser$1,
30468
30552
  };
30469
30553
 
30470
- const {FormulaParser} = hooks$1;
30554
+ const {FormulaParser: FormulaParser$1} = hooks$1;
30471
30555
  const {DepParser} = hooks;
30472
30556
  const SSF = ssf$1;
30473
30557
  const FormulaError = requireError();
@@ -30477,16 +30561,16 @@ const FormulaError = requireError();
30477
30561
  // `\nTotal: ${funs.length}/477, ${funs.length/477*100}% implemented.`);
30478
30562
 
30479
30563
 
30480
- Object.assign(FormulaParser, {
30564
+ Object.assign(FormulaParser$1, {
30481
30565
  MAX_ROW: 1048576,
30482
30566
  MAX_COLUMN: 16384,
30483
30567
  SSF,
30484
30568
  DepParser,
30485
30569
  FormulaError, ...requireHelpers()
30486
30570
  });
30487
- var fastFormulaParser = FormulaParser;
30571
+ var fastFormulaParser = FormulaParser$1;
30488
30572
 
30489
- var FormulaParser$1 = /*@__PURE__*/getDefaultExportFromCjs(fastFormulaParser);
30573
+ var FormulaParser = /*@__PURE__*/getDefaultExportFromCjs(fastFormulaParser);
30490
30574
 
30491
30575
  var scheduler = {exports: {}};
30492
30576
 
@@ -30507,7 +30591,7 @@ var hasRequiredScheduler_production;
30507
30591
  function requireScheduler_production () {
30508
30592
  if (hasRequiredScheduler_production) return scheduler_production;
30509
30593
  hasRequiredScheduler_production = 1;
30510
- (function (exports) {
30594
+ (function (exports$1) {
30511
30595
  function push(heap, node) {
30512
30596
  var index = heap.length;
30513
30597
  heap.push(node);
@@ -30556,16 +30640,16 @@ function requireScheduler_production () {
30556
30640
  var diff = a.sortIndex - b.sortIndex;
30557
30641
  return 0 !== diff ? diff : a.id - b.id;
30558
30642
  }
30559
- exports.unstable_now = void 0;
30643
+ exports$1.unstable_now = void 0;
30560
30644
  if ("object" === typeof performance && "function" === typeof performance.now) {
30561
30645
  var localPerformance = performance;
30562
- exports.unstable_now = function () {
30646
+ exports$1.unstable_now = function () {
30563
30647
  return localPerformance.now();
30564
30648
  };
30565
30649
  } else {
30566
30650
  var localDate = Date,
30567
30651
  initialTime = localDate.now();
30568
- exports.unstable_now = function () {
30652
+ exports$1.unstable_now = function () {
30569
30653
  return localDate.now() - initialTime;
30570
30654
  };
30571
30655
  }
@@ -30613,14 +30697,14 @@ function requireScheduler_production () {
30613
30697
  function shouldYieldToHost() {
30614
30698
  return needsPaint
30615
30699
  ? true
30616
- : exports.unstable_now() - startTime < frameInterval
30700
+ : exports$1.unstable_now() - startTime < frameInterval
30617
30701
  ? false
30618
30702
  : true;
30619
30703
  }
30620
30704
  function performWorkUntilDeadline() {
30621
30705
  needsPaint = false;
30622
30706
  if (isMessageLoopRunning) {
30623
- var currentTime = exports.unstable_now();
30707
+ var currentTime = exports$1.unstable_now();
30624
30708
  startTime = currentTime;
30625
30709
  var hasMoreWork = true;
30626
30710
  try {
@@ -30650,7 +30734,7 @@ function requireScheduler_production () {
30650
30734
  var continuationCallback = callback(
30651
30735
  currentTask.expirationTime <= currentTime
30652
30736
  );
30653
- currentTime = exports.unstable_now();
30737
+ currentTime = exports$1.unstable_now();
30654
30738
  if ("function" === typeof continuationCallback) {
30655
30739
  currentTask.callback = continuationCallback;
30656
30740
  advanceTimers(currentTime);
@@ -30706,29 +30790,29 @@ function requireScheduler_production () {
30706
30790
  };
30707
30791
  function requestHostTimeout(callback, ms) {
30708
30792
  taskTimeoutID = localSetTimeout(function () {
30709
- callback(exports.unstable_now());
30793
+ callback(exports$1.unstable_now());
30710
30794
  }, ms);
30711
30795
  }
30712
- exports.unstable_IdlePriority = 5;
30713
- exports.unstable_ImmediatePriority = 1;
30714
- exports.unstable_LowPriority = 4;
30715
- exports.unstable_NormalPriority = 3;
30716
- exports.unstable_Profiling = null;
30717
- exports.unstable_UserBlockingPriority = 2;
30718
- exports.unstable_cancelCallback = function (task) {
30796
+ exports$1.unstable_IdlePriority = 5;
30797
+ exports$1.unstable_ImmediatePriority = 1;
30798
+ exports$1.unstable_LowPriority = 4;
30799
+ exports$1.unstable_NormalPriority = 3;
30800
+ exports$1.unstable_Profiling = null;
30801
+ exports$1.unstable_UserBlockingPriority = 2;
30802
+ exports$1.unstable_cancelCallback = function (task) {
30719
30803
  task.callback = null;
30720
30804
  };
30721
- exports.unstable_forceFrameRate = function (fps) {
30805
+ exports$1.unstable_forceFrameRate = function (fps) {
30722
30806
  0 > fps || 125 < fps
30723
30807
  ? console.error(
30724
30808
  "forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"
30725
30809
  )
30726
30810
  : (frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5);
30727
30811
  };
30728
- exports.unstable_getCurrentPriorityLevel = function () {
30812
+ exports$1.unstable_getCurrentPriorityLevel = function () {
30729
30813
  return currentPriorityLevel;
30730
30814
  };
30731
- exports.unstable_next = function (eventHandler) {
30815
+ exports$1.unstable_next = function (eventHandler) {
30732
30816
  switch (currentPriorityLevel) {
30733
30817
  case 1:
30734
30818
  case 2:
@@ -30746,10 +30830,10 @@ function requireScheduler_production () {
30746
30830
  currentPriorityLevel = previousPriorityLevel;
30747
30831
  }
30748
30832
  };
30749
- exports.unstable_requestPaint = function () {
30833
+ exports$1.unstable_requestPaint = function () {
30750
30834
  needsPaint = true;
30751
30835
  };
30752
- exports.unstable_runWithPriority = function (priorityLevel, eventHandler) {
30836
+ exports$1.unstable_runWithPriority = function (priorityLevel, eventHandler) {
30753
30837
  switch (priorityLevel) {
30754
30838
  case 1:
30755
30839
  case 2:
@@ -30768,12 +30852,12 @@ function requireScheduler_production () {
30768
30852
  currentPriorityLevel = previousPriorityLevel;
30769
30853
  }
30770
30854
  };
30771
- exports.unstable_scheduleCallback = function (
30855
+ exports$1.unstable_scheduleCallback = function (
30772
30856
  priorityLevel,
30773
30857
  callback,
30774
30858
  options
30775
30859
  ) {
30776
- var currentTime = exports.unstable_now();
30860
+ var currentTime = exports$1.unstable_now();
30777
30861
  "object" === typeof options && null !== options
30778
30862
  ? ((options = options.delay),
30779
30863
  (options =
@@ -30824,8 +30908,8 @@ function requireScheduler_production () {
30824
30908
  ((isMessageLoopRunning = true), schedulePerformWorkUntilDeadline())));
30825
30909
  return priorityLevel;
30826
30910
  };
30827
- exports.unstable_shouldYield = shouldYieldToHost;
30828
- exports.unstable_wrapCallback = function (callback) {
30911
+ exports$1.unstable_shouldYield = shouldYieldToHost;
30912
+ exports$1.unstable_wrapCallback = function (callback) {
30829
30913
  var parentPriorityLevel = currentPriorityLevel;
30830
30914
  return function () {
30831
30915
  var previousPriorityLevel = currentPriorityLevel;
@@ -30858,13 +30942,13 @@ var hasRequiredScheduler_development;
30858
30942
  function requireScheduler_development () {
30859
30943
  if (hasRequiredScheduler_development) return scheduler_development;
30860
30944
  hasRequiredScheduler_development = 1;
30861
- (function (exports) {
30945
+ (function (exports$1) {
30862
30946
  "production" !== process.env.NODE_ENV &&
30863
30947
  (function () {
30864
30948
  function performWorkUntilDeadline() {
30865
30949
  needsPaint = false;
30866
30950
  if (isMessageLoopRunning) {
30867
- var currentTime = exports.unstable_now();
30951
+ var currentTime = exports$1.unstable_now();
30868
30952
  startTime = currentTime;
30869
30953
  var hasMoreWork = true;
30870
30954
  try {
@@ -30895,7 +30979,7 @@ function requireScheduler_development () {
30895
30979
  var continuationCallback = callback(
30896
30980
  currentTask.expirationTime <= currentTime
30897
30981
  );
30898
- currentTime = exports.unstable_now();
30982
+ currentTime = exports$1.unstable_now();
30899
30983
  if ("function" === typeof continuationCallback) {
30900
30984
  currentTask.callback = continuationCallback;
30901
30985
  advanceTimers(currentTime);
@@ -31016,32 +31100,32 @@ function requireScheduler_development () {
31016
31100
  function shouldYieldToHost() {
31017
31101
  return needsPaint
31018
31102
  ? true
31019
- : exports.unstable_now() - startTime < frameInterval
31103
+ : exports$1.unstable_now() - startTime < frameInterval
31020
31104
  ? false
31021
31105
  : true;
31022
31106
  }
31023
31107
  function requestHostTimeout(callback, ms) {
31024
31108
  taskTimeoutID = localSetTimeout(function () {
31025
- callback(exports.unstable_now());
31109
+ callback(exports$1.unstable_now());
31026
31110
  }, ms);
31027
31111
  }
31028
31112
  "undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
31029
31113
  "function" ===
31030
31114
  typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
31031
31115
  __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
31032
- exports.unstable_now = void 0;
31116
+ exports$1.unstable_now = void 0;
31033
31117
  if (
31034
31118
  "object" === typeof performance &&
31035
31119
  "function" === typeof performance.now
31036
31120
  ) {
31037
31121
  var localPerformance = performance;
31038
- exports.unstable_now = function () {
31122
+ exports$1.unstable_now = function () {
31039
31123
  return localPerformance.now();
31040
31124
  };
31041
31125
  } else {
31042
31126
  var localDate = Date,
31043
31127
  initialTime = localDate.now();
31044
- exports.unstable_now = function () {
31128
+ exports$1.unstable_now = function () {
31045
31129
  return localDate.now() - initialTime;
31046
31130
  };
31047
31131
  }
@@ -31078,26 +31162,26 @@ function requireScheduler_development () {
31078
31162
  schedulePerformWorkUntilDeadline = function () {
31079
31163
  localSetTimeout(performWorkUntilDeadline, 0);
31080
31164
  };
31081
- exports.unstable_IdlePriority = 5;
31082
- exports.unstable_ImmediatePriority = 1;
31083
- exports.unstable_LowPriority = 4;
31084
- exports.unstable_NormalPriority = 3;
31085
- exports.unstable_Profiling = null;
31086
- exports.unstable_UserBlockingPriority = 2;
31087
- exports.unstable_cancelCallback = function (task) {
31165
+ exports$1.unstable_IdlePriority = 5;
31166
+ exports$1.unstable_ImmediatePriority = 1;
31167
+ exports$1.unstable_LowPriority = 4;
31168
+ exports$1.unstable_NormalPriority = 3;
31169
+ exports$1.unstable_Profiling = null;
31170
+ exports$1.unstable_UserBlockingPriority = 2;
31171
+ exports$1.unstable_cancelCallback = function (task) {
31088
31172
  task.callback = null;
31089
31173
  };
31090
- exports.unstable_forceFrameRate = function (fps) {
31174
+ exports$1.unstable_forceFrameRate = function (fps) {
31091
31175
  0 > fps || 125 < fps
31092
31176
  ? console.error(
31093
31177
  "forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"
31094
31178
  )
31095
31179
  : (frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5);
31096
31180
  };
31097
- exports.unstable_getCurrentPriorityLevel = function () {
31181
+ exports$1.unstable_getCurrentPriorityLevel = function () {
31098
31182
  return currentPriorityLevel;
31099
31183
  };
31100
- exports.unstable_next = function (eventHandler) {
31184
+ exports$1.unstable_next = function (eventHandler) {
31101
31185
  switch (currentPriorityLevel) {
31102
31186
  case 1:
31103
31187
  case 2:
@@ -31115,10 +31199,10 @@ function requireScheduler_development () {
31115
31199
  currentPriorityLevel = previousPriorityLevel;
31116
31200
  }
31117
31201
  };
31118
- exports.unstable_requestPaint = function () {
31202
+ exports$1.unstable_requestPaint = function () {
31119
31203
  needsPaint = true;
31120
31204
  };
31121
- exports.unstable_runWithPriority = function (priorityLevel, eventHandler) {
31205
+ exports$1.unstable_runWithPriority = function (priorityLevel, eventHandler) {
31122
31206
  switch (priorityLevel) {
31123
31207
  case 1:
31124
31208
  case 2:
@@ -31137,12 +31221,12 @@ function requireScheduler_development () {
31137
31221
  currentPriorityLevel = previousPriorityLevel;
31138
31222
  }
31139
31223
  };
31140
- exports.unstable_scheduleCallback = function (
31224
+ exports$1.unstable_scheduleCallback = function (
31141
31225
  priorityLevel,
31142
31226
  callback,
31143
31227
  options
31144
31228
  ) {
31145
- var currentTime = exports.unstable_now();
31229
+ var currentTime = exports$1.unstable_now();
31146
31230
  "object" === typeof options && null !== options
31147
31231
  ? ((options = options.delay),
31148
31232
  (options =
@@ -31194,8 +31278,8 @@ function requireScheduler_development () {
31194
31278
  schedulePerformWorkUntilDeadline())));
31195
31279
  return priorityLevel;
31196
31280
  };
31197
- exports.unstable_shouldYield = shouldYieldToHost;
31198
- exports.unstable_wrapCallback = function (callback) {
31281
+ exports$1.unstable_shouldYield = shouldYieldToHost;
31282
+ exports$1.unstable_wrapCallback = function (callback) {
31199
31283
  var parentPriorityLevel = currentPriorityLevel;
31200
31284
  return function () {
31201
31285
  var previousPriorityLevel = currentPriorityLevel;
@@ -32450,7 +32534,7 @@ function extractFormula(value) {
32450
32534
  return value.slice(1);
32451
32535
  }
32452
32536
  function createFormulaParser(data, config) {
32453
- return new FormulaParser$1(__assign(__assign({}, config), { onCell: function (ref) {
32537
+ return new FormulaParser(__assign(__assign({}, config), { onCell: function (ref) {
32454
32538
  var point = {
32455
32539
  row: ref.row - 1,
32456
32540
  column: ref.col - 1,
@@ -35456,8 +35540,8 @@ return CRC32;
35456
35540
  })();
35457
35541
  /* [MS-CFB] v20171201 */
35458
35542
  var CFB = /*#__PURE__*/(function _CFB(){
35459
- var exports = {};
35460
- exports.version = '1.2.1';
35543
+ var exports$1 = {};
35544
+ exports$1.version = '1.2.1';
35461
35545
  /* [MS-CFB] 2.6.4 */
35462
35546
  function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
35463
35547
  var L = l.split("/"), R = r.split("/");
@@ -37129,12 +37213,12 @@ function cfb_mov(cfb/*:CFBContainer*/, old_name/*:string*/, new_name/*:string*/)
37129
37213
 
37130
37214
  function cfb_gc(cfb/*:CFBContainer*/)/*:void*/ { rebuild_cfb(cfb, true); }
37131
37215
 
37132
- exports.find = find;
37133
- exports.read = read;
37134
- exports.parse = parse;
37135
- exports.write = write;
37136
- exports.writeFile = write_file;
37137
- exports.utils = {
37216
+ exports$1.find = find;
37217
+ exports$1.read = read;
37218
+ exports$1.parse = parse;
37219
+ exports$1.write = write;
37220
+ exports$1.writeFile = write_file;
37221
+ exports$1.utils = {
37138
37222
  cfb_new: cfb_new,
37139
37223
  cfb_add: cfb_add,
37140
37224
  cfb_del: cfb_del,
@@ -37150,7 +37234,7 @@ exports.utils = {
37150
37234
  consts: consts
37151
37235
  };
37152
37236
 
37153
- return exports;
37237
+ return exports$1;
37154
37238
  })();
37155
37239
 
37156
37240
  /* normalize data for blob ctor */
@@ -58613,6 +58697,137 @@ function CurrencyDisplay({ amount, currency = 'USD', locale = 'en-US', className
58613
58697
  return (jsx("span", { className: combinedClasses, title: `${currency} ${safeAmount.toFixed(precision)}`, children: displayValue }));
58614
58698
  }
58615
58699
 
58700
+ /**
58701
+ * CurrencyInput - Specialized input for monetary values
58702
+ *
58703
+ * Automatically formats currency values with proper symbols and thousands separators.
58704
+ * Handles parsing and validation of numeric currency input.
58705
+ *
58706
+ * @example Basic usage
58707
+ * ```tsx
58708
+ * <CurrencyInput
58709
+ * label="Price"
58710
+ * value={price}
58711
+ * onChange={setPrice}
58712
+ * currency="USD"
58713
+ * />
58714
+ * ```
58715
+ *
58716
+ * @example With validation
58717
+ * ```tsx
58718
+ * <CurrencyInput
58719
+ * label="Budget"
58720
+ * value={budget}
58721
+ * onChange={setBudget}
58722
+ * min={0}
58723
+ * max={10000}
58724
+ * validationState={budget > 10000 ? 'error' : null}
58725
+ * validationMessage={budget > 10000 ? 'Exceeds maximum budget' : ''}
58726
+ * />
58727
+ * ```
58728
+ */
58729
+ const CurrencyInput = forwardRef(({ value, onChange, currency = 'USD', locale = 'en-US', precision = 2, allowNegative = false, min, max, onBlur, onFocus, ...props }, ref) => {
58730
+ const [displayValue, setDisplayValue] = useState('');
58731
+ const [isFocused, setIsFocused] = useState(false);
58732
+ // Get currency symbol
58733
+ const getCurrencySymbol = () => {
58734
+ const formatter = new Intl.NumberFormat(locale, {
58735
+ style: 'currency',
58736
+ currency,
58737
+ });
58738
+ const parts = formatter.formatToParts(0);
58739
+ const symbolPart = parts.find(part => part.type === 'currency');
58740
+ return symbolPart?.value || '$';
58741
+ };
58742
+ const currencySymbol = getCurrencySymbol();
58743
+ // Format number as currency
58744
+ const formatCurrency = (num) => {
58745
+ const formatter = new Intl.NumberFormat(locale, {
58746
+ minimumFractionDigits: isFocused ? 0 : precision,
58747
+ maximumFractionDigits: precision,
58748
+ });
58749
+ return formatter.format(num);
58750
+ };
58751
+ // Parse display value to number
58752
+ const parseValue = (str) => {
58753
+ if (!str || str === '')
58754
+ return null;
58755
+ // Remove all non-numeric characters except decimal point and minus sign
58756
+ let cleaned = str.replace(/[^\d.-]/g, '');
58757
+ // Handle multiple decimal points
58758
+ const parts = cleaned.split('.');
58759
+ if (parts.length > 2) {
58760
+ cleaned = parts[0] + '.' + parts.slice(1).join('');
58761
+ }
58762
+ // Handle multiple minus signs (keep only first)
58763
+ const minusCount = (cleaned.match(/-/g) || []).length;
58764
+ if (minusCount > 1) {
58765
+ const hasLeadingMinus = cleaned.startsWith('-');
58766
+ cleaned = cleaned.replace(/-/g, '');
58767
+ if (hasLeadingMinus)
58768
+ cleaned = '-' + cleaned;
58769
+ }
58770
+ // Parse to float
58771
+ const num = parseFloat(cleaned);
58772
+ if (isNaN(num))
58773
+ return null;
58774
+ // Apply precision
58775
+ return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
58776
+ };
58777
+ // Update display value when external value changes
58778
+ useEffect(() => {
58779
+ if (value === undefined || value === null || value === '') {
58780
+ setDisplayValue('');
58781
+ }
58782
+ else {
58783
+ const numValue = typeof value === 'string' ? parseFloat(value) : value;
58784
+ if (!isNaN(numValue)) {
58785
+ setDisplayValue(formatCurrency(numValue));
58786
+ }
58787
+ }
58788
+ }, [value, isFocused]);
58789
+ const handleChange = (e) => {
58790
+ const inputValue = e.target.value;
58791
+ setDisplayValue(inputValue);
58792
+ const numValue = parseValue(inputValue);
58793
+ // Validate constraints
58794
+ if (numValue !== null) {
58795
+ if (!allowNegative && numValue < 0)
58796
+ return;
58797
+ if (min !== undefined && numValue < min)
58798
+ return;
58799
+ if (max !== undefined && numValue > max)
58800
+ return;
58801
+ }
58802
+ onChange?.(numValue);
58803
+ };
58804
+ const handleFocus = (e) => {
58805
+ setIsFocused(true);
58806
+ // Remove formatting when focused for easier editing
58807
+ if (value !== undefined && value !== null && value !== '') {
58808
+ const numValue = typeof value === 'string' ? parseFloat(value) : value;
58809
+ if (!isNaN(numValue)) {
58810
+ setDisplayValue(numValue.toString());
58811
+ }
58812
+ }
58813
+ onFocus?.(e);
58814
+ };
58815
+ const handleBlur = (e) => {
58816
+ setIsFocused(false);
58817
+ // Reformat on blur
58818
+ const numValue = parseValue(displayValue);
58819
+ if (numValue !== null) {
58820
+ setDisplayValue(formatCurrency(numValue));
58821
+ }
58822
+ else if (displayValue === '') {
58823
+ setDisplayValue('');
58824
+ }
58825
+ onBlur?.(e);
58826
+ };
58827
+ return (jsx(Input, { ref: ref, type: "text", value: displayValue, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, prefix: currencySymbol, ...props }));
58828
+ });
58829
+ CurrencyInput.displayName = 'CurrencyInput';
58830
+
58616
58831
  const formatOptions = {
58617
58832
  short: {
58618
58833
  year: 'numeric',
@@ -59523,8 +59738,19 @@ const AppLayout = ({ children, toolbarSections = [], className = '', showToolbar
59523
59738
  * </Layout>
59524
59739
  * ```
59525
59740
  */
59526
- function PageLayout({ title, description, children, className = '', headerContent }) {
59527
- return (jsxs(Page, { children: [headerContent, jsxs("div", { className: `p-6 max-w-7xl mx-auto pb-20 ${className}`, children: [jsxs("div", { className: "mb-8", children: [jsx("h1", { className: "text-3xl font-bold text-ink-900 mb-2", children: title }), description && (jsx("p", { className: "text-ink-600", children: description }))] }), children] })] }));
59741
+ function PageLayout({ title, description, children, className = '', headerContent, maxWidth = '7xl', fixed = false }) {
59742
+ // Responsive padding classes - fixed left/top, responsive right/bottom
59743
+ const paddingClasses = fixed
59744
+ ? 'p-6 pb-20'
59745
+ : 'pt-6 pl-6 pr-2 pb-8 sm:pr-4 md:pr-6 sm:pb-12 md:pb-16 lg:pb-20';
59746
+ const maxWidthClasses = {
59747
+ '4xl': 'max-w-4xl',
59748
+ '5xl': 'max-w-5xl',
59749
+ '6xl': 'max-w-6xl',
59750
+ '7xl': 'max-w-7xl',
59751
+ 'full': 'max-w-full',
59752
+ };
59753
+ return (jsxs(Page, { padding: "none", maxWidth: maxWidth, fixed: fixed, children: [headerContent, jsxs("div", { className: `${paddingClasses} ${maxWidthClasses[maxWidth]} mx-auto ${className}`, children: [jsxs("div", { className: "mb-8", children: [jsx("h1", { className: "text-3xl font-bold text-ink-900 mb-2", children: title }), description && (jsx("p", { className: "text-ink-600", children: description }))] }), children] })] }));
59528
59754
  }
59529
59755
 
59530
59756
  const sizeClasses = {
@@ -59896,6 +60122,113 @@ function loadColumnOrder(tableId) {
59896
60122
  }
59897
60123
  }
59898
60124
 
60125
+ /**
60126
+ * Export data to Excel file
60127
+ *
60128
+ * A standalone utility for exporting any data array to Excel format.
60129
+ * Works independently of the Spreadsheet component.
60130
+ *
60131
+ * **Features:**
60132
+ * - Export arrays of objects to Excel
60133
+ * - Custom column headers and ordering
60134
+ * - Value formatting with custom functions
60135
+ * - Multi-sheet support
60136
+ * - Automatic type handling
60137
+ *
60138
+ * @example
60139
+ * ```typescript
60140
+ * // Simple export - uses object keys as headers
60141
+ * const data = [
60142
+ * { id: 1, name: 'Product A', price: 29.99 },
60143
+ * { id: 2, name: 'Product B', price: 49.99 },
60144
+ * ];
60145
+ * exportToExcel({ data, filename: 'products.xlsx' });
60146
+ *
60147
+ * // Custom columns with formatting
60148
+ * exportToExcel({
60149
+ * data: users,
60150
+ * filename: 'users.xlsx',
60151
+ * columns: [
60152
+ * { key: 'id', label: 'ID' },
60153
+ * { key: 'name', label: 'Full Name' },
60154
+ * { key: 'email', label: 'Email Address' },
60155
+ * { key: 'createdAt', label: 'Joined', format: (date) => new Date(date).toLocaleDateString() },
60156
+ * { key: 'isActive', label: 'Status', format: (active) => active ? 'Active' : 'Inactive' },
60157
+ * ],
60158
+ * });
60159
+ *
60160
+ * // Multi-sheet export
60161
+ * const wb = utils.book_new();
60162
+ * exportToExcel({ data: products, sheetName: 'Products', workbook: wb });
60163
+ * exportToExcel({ data: orders, sheetName: 'Orders', workbook: wb });
60164
+ * writeFile(wb, 'multi-sheet.xlsx');
60165
+ * ```
60166
+ *
60167
+ * @param options - Export configuration options
60168
+ * @returns WorkBook if workbook option provided, otherwise void (auto-downloads)
60169
+ */
60170
+ function exportToExcel({ data, filename = 'export.xlsx', sheetName = 'Sheet1', columns, includeHeaders = true, workbook, }) {
60171
+ if (!data || data.length === 0) {
60172
+ throw new Error('No data provided for export');
60173
+ }
60174
+ let worksheetData;
60175
+ if (columns) {
60176
+ // Use custom columns with specific ordering and formatting
60177
+ const headers = columns.map((col) => col.label);
60178
+ const rows = data.map((row) => columns.map((col) => {
60179
+ const value = row[col.key];
60180
+ return col.format ? col.format(value) : value ?? '';
60181
+ }));
60182
+ worksheetData = includeHeaders ? [headers, ...rows] : rows;
60183
+ }
60184
+ else {
60185
+ // Auto-generate from object keys
60186
+ if (includeHeaders) {
60187
+ const headers = Object.keys(data[0]);
60188
+ const rows = data.map((row) => headers.map((key) => row[key] ?? ''));
60189
+ worksheetData = [headers, ...rows];
60190
+ }
60191
+ else {
60192
+ const headers = Object.keys(data[0]);
60193
+ worksheetData = data.map((row) => headers.map((key) => row[key] ?? ''));
60194
+ }
60195
+ }
60196
+ const worksheet = utils.aoa_to_sheet(worksheetData);
60197
+ // If workbook provided, add sheet and return (for multi-sheet exports)
60198
+ if (workbook) {
60199
+ utils.book_append_sheet(workbook, worksheet, sheetName);
60200
+ return workbook;
60201
+ }
60202
+ // Otherwise, create workbook and download
60203
+ const newWorkbook = utils.book_new();
60204
+ utils.book_append_sheet(newWorkbook, worksheet, sheetName);
60205
+ writeFileSync(newWorkbook, filename);
60206
+ }
60207
+ function exportDataTableToExcel({ data, columns, filename = 'export.xlsx', sheetName = 'Sheet1', }) {
60208
+ const excelColumns = columns.map((col) => ({
60209
+ key: col.key,
60210
+ label: col.header,
60211
+ }));
60212
+ exportToExcel({
60213
+ data,
60214
+ columns: excelColumns,
60215
+ filename,
60216
+ sheetName,
60217
+ });
60218
+ }
60219
+ function createMultiSheetExcel({ filename, sheets }) {
60220
+ const workbook = utils.book_new();
60221
+ sheets.forEach((sheet) => {
60222
+ exportToExcel({
60223
+ data: sheet.data,
60224
+ sheetName: sheet.name,
60225
+ columns: sheet.columns,
60226
+ workbook,
60227
+ });
60228
+ });
60229
+ writeFileSync(workbook, filename);
60230
+ }
60231
+
59899
60232
  function useColumnResize(options = {}) {
59900
60233
  const { tableId, persist = false } = options;
59901
60234
  const [columnWidths, setColumnWidths] = useState({});
@@ -60012,5 +60345,5 @@ function useColumnReorder(initialColumns, options = {}) {
60012
60345
  };
60013
60346
  }
60014
60347
 
60015
- export { Accordion, ActionButton, AdminModal, Alert, AlertDialog, AppLayout, Autocomplete, Avatar, Badge, BottomSheet, Box, Breadcrumbs, Button, ButtonGroup, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Carousel, Checkbox, Chip, Collapsible, ColorPicker, Combobox, ComingSoon, CommandPalette, ConfirmDialog, ContextMenu, ControlBar, CurrencyDisplay, Dashboard, DashboardContent, DashboardHeader, DataTable, DateDisplay, DatePicker, DateRangePicker, DateTimePicker, Drawer, DrawerFooter, DropZone, Dropdown, DropdownTrigger, EmptyState, ErrorBoundary, ExpandableRowButton, ExpandableToolbar, ExpandedRowEditForm, ExportButton, FieldArray, FileUpload, FilterBar, FilterControls, FilterStatusBanner, Form, FormContext, FormControl, FormWizard, Grid, GridItem, Hide, HoverCard, InfiniteScroll, Input, KanbanBoard, Layout, Loading, LoadingOverlay, Logo, MarkdownEditor, MaskedInput, Menu, MenuDivider, Modal, ModalFooter, MultiSelect, NotificationBar, NotificationIndicator, NumberInput, Page, PageLayout, PageNavigation, Pagination, PasswordInput, Popover, Progress, QueryTransparency, RadioGroup, Rating, RichTextEditor, SearchBar, Select, Separator, Show, Sidebar, SidebarGroup, Skeleton, SkeletonCard, SkeletonTable, Slider, Spreadsheet, SpreadsheetReport, Stack, StatCard, StatItem, StatsCardGrid, StatsGrid, StatusBadge, StatusBar, StepIndicator, Stepper, Switch, Table$1 as Table, Tabs, Text, Textarea, ThemeToggle, TimePicker, Timeline, Toast, ToastContainer, Tooltip, Transfer, TreeView, TwoColumnContent, UserProfileButton, addErrorMessage, addInfoMessage, addSuccessMessage, addWarningMessage, calculateColumnWidth, createActionsSection, createFiltersSection, createPageControlsSection, createQueryDetailsSection, formatStatisticValue, formatStatistics, loadColumnOrder, loadColumnWidths, reorderArray, saveColumnOrder, saveColumnWidths, statusManager, useColumnReorder, useColumnResize, useCommandPalette, useConfirmDialog, useFormContext, useMediaQuery };
60348
+ export { Accordion, ActionButton, AdminModal, Alert, AlertDialog, AppLayout, Autocomplete, Avatar, Badge, BottomSheet, Box, Breadcrumbs, Button, ButtonGroup, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Carousel, Checkbox, Chip, Collapsible, ColorPicker, Combobox, ComingSoon, CommandPalette, ConfirmDialog, ContextMenu, ControlBar, CurrencyDisplay, CurrencyInput, Dashboard, DashboardContent, DashboardHeader, DataTable, DateDisplay, DatePicker, DateRangePicker, DateTimePicker, Drawer, DrawerFooter, DropZone, Dropdown, DropdownTrigger, EmptyState, ErrorBoundary, ExpandableRowButton, ExpandableToolbar, ExpandedRowEditForm, ExportButton, FieldArray, FileUpload, FilterBar, FilterControls, FilterStatusBanner, Form, FormContext, FormControl, FormWizard, Grid, GridItem, Hide, HoverCard, InfiniteScroll, Input, KanbanBoard, Layout, Loading, LoadingOverlay, Logo, MarkdownEditor, MaskedInput, Menu, MenuDivider, Modal, ModalFooter, MultiSelect, NotificationBar, NotificationIndicator, NumberInput, Page, PageLayout, PageNavigation, Pagination, PasswordInput, Popover, Progress, QueryTransparency, RadioGroup, Rating, RichTextEditor, SearchBar, Select, Separator, Show, Sidebar, SidebarGroup, Skeleton, SkeletonCard, SkeletonTable, Slider, Spreadsheet, SpreadsheetReport, Stack, StatCard, StatItem, StatsCardGrid, StatsGrid, StatusBadge, StatusBar, StepIndicator, Stepper, Switch, Tabs, Text, Textarea, ThemeToggle, TimePicker, Timeline, Toast, ToastContainer, Tooltip, Transfer, TreeView, TwoColumnContent, UserProfileButton, addErrorMessage, addInfoMessage, addSuccessMessage, addWarningMessage, calculateColumnWidth, createActionsSection, createFiltersSection, createMultiSheetExcel, createPageControlsSection, createQueryDetailsSection, exportDataTableToExcel, exportToExcel, formatStatisticValue, formatStatistics, loadColumnOrder, loadColumnWidths, reorderArray, saveColumnOrder, saveColumnWidths, statusManager, useColumnReorder, useColumnResize, useCommandPalette, useConfirmDialog, useFormContext, useMediaQuery };
60016
60349
  //# sourceMappingURL=index.esm.js.map