@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.
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/dist/components/Box.d.ts +2 -1
- package/dist/components/Box.d.ts.map +1 -1
- package/dist/components/Button.d.ts +10 -1
- package/dist/components/Button.d.ts.map +1 -1
- package/dist/components/Card.d.ts +11 -2
- package/dist/components/Card.d.ts.map +1 -1
- package/dist/components/CurrencyInput.d.ts +52 -0
- package/dist/components/CurrencyInput.d.ts.map +1 -0
- package/dist/components/DataTable.d.ts +19 -3
- package/dist/components/DataTable.d.ts.map +1 -1
- package/dist/components/EmptyState.d.ts +3 -1
- package/dist/components/EmptyState.d.ts.map +1 -1
- package/dist/components/Grid.d.ts +4 -2
- package/dist/components/Grid.d.ts.map +1 -1
- package/dist/components/Input.d.ts +2 -0
- package/dist/components/Input.d.ts.map +1 -1
- package/dist/components/Modal.d.ts.map +1 -1
- package/dist/components/MultiSelect.d.ts +13 -1
- package/dist/components/MultiSelect.d.ts.map +1 -1
- package/dist/components/Page.d.ts +2 -0
- package/dist/components/Page.d.ts.map +1 -1
- package/dist/components/PageLayout.d.ts +5 -1
- package/dist/components/PageLayout.d.ts.map +1 -1
- package/dist/components/Stack.d.ts +25 -5
- package/dist/components/Stack.d.ts.map +1 -1
- package/dist/components/Text.d.ts +20 -4
- package/dist/components/Text.d.ts.map +1 -1
- package/dist/components/Textarea.d.ts +2 -0
- package/dist/components/Textarea.d.ts.map +1 -1
- package/dist/components/index.d.ts +5 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +311 -49
- package/dist/index.esm.js +557 -224
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +555 -219
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2838 -2679
- package/dist/utils/excelExport.d.ts +143 -0
- package/dist/utils/excelExport.d.ts.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/components/AdminModal.css +49 -49
- package/src/components/Box.stories.tsx +377 -0
- package/src/components/Box.tsx +8 -4
- package/src/components/Button.tsx +23 -10
- package/src/components/Card.tsx +20 -5
- package/src/components/CurrencyInput.stories.tsx +290 -0
- package/src/components/CurrencyInput.tsx +193 -0
- package/src/components/DataTable.stories.tsx +36 -25
- package/src/components/DataTable.tsx +170 -16
- package/src/components/EmptyState.stories.tsx +124 -72
- package/src/components/EmptyState.tsx +10 -0
- package/src/components/Grid.stories.tsx +348 -0
- package/src/components/Grid.tsx +12 -5
- package/src/components/Input.tsx +12 -2
- package/src/components/Modal.stories.tsx +64 -0
- package/src/components/Modal.tsx +15 -2
- package/src/components/MultiSelect.tsx +41 -10
- package/src/components/Page.stories.tsx +76 -0
- package/src/components/Page.tsx +35 -3
- package/src/components/PageLayout.stories.tsx +75 -0
- package/src/components/PageLayout.tsx +28 -9
- package/src/components/RoleManager.css +10 -10
- package/src/components/Spreadsheet.css +216 -216
- package/src/components/Spreadsheet.stories.tsx +362 -362
- package/src/components/Spreadsheet.tsx +351 -351
- package/src/components/SpreadsheetSimple.stories.tsx +27 -27
- package/src/components/Stack.stories.tsx +24 -1
- package/src/components/Stack.tsx +40 -10
- package/src/components/Tabs.tsx +152 -152
- package/src/components/Text.stories.tsx +273 -0
- package/src/components/Text.tsx +33 -8
- package/src/components/Textarea.tsx +32 -21
- package/src/components/index.ts +6 -4
- package/src/styles/index.css +41 -4
- package/src/utils/excelExport.stories.tsx +535 -0
- package/src/utils/excelExport.ts +225 -0
- package/src/utils/index.ts +3 -0
- package/tailwind.config.js +253 -253
- package/dist/components/Button.stories.d.ts +0 -51
- package/dist/components/Button.stories.d.ts.map +0 -1
- package/dist/components/ChartVisualizationUI.d.ts +0 -21
- package/dist/components/ChartVisualizationUI.d.ts.map +0 -1
- package/dist/components/ChatUI.d.ts +0 -23
- package/dist/components/ChatUI.d.ts.map +0 -1
- package/dist/components/CommissionDashboardUI.d.ts +0 -25
- package/dist/components/CommissionDashboardUI.d.ts.map +0 -1
- package/dist/components/DataTable.stories.d.ts +0 -23
- package/dist/components/DataTable.stories.d.ts.map +0 -1
- package/dist/components/FormField.d.ts +0 -35
- package/dist/components/FormField.d.ts.map +0 -1
- package/dist/components/Input.stories.d.ts +0 -366
- package/dist/components/Input.stories.d.ts.map +0 -1
- package/dist/components/InsightsPanelUI.d.ts +0 -21
- package/dist/components/InsightsPanelUI.d.ts.map +0 -1
- package/dist/components/PaymentHistoryTimeline.d.ts +0 -34
- package/dist/components/PaymentHistoryTimeline.d.ts.map +0 -1
- package/dist/components/RelationshipManagerUI.d.ts +0 -60
- package/dist/components/RelationshipManagerUI.d.ts.map +0 -1
- package/dist/components/RoleManager.d.ts +0 -19
- package/dist/components/RoleManager.d.ts.map +0 -1
- package/dist/components/SplitCommissionBadge.d.ts +0 -18
- package/dist/components/SplitCommissionBadge.d.ts.map +0 -1
- package/dist/components/Spreadsheet.css +0 -216
- package/dist/components/Table.d.ts +0 -26
- package/dist/components/Table.d.ts.map +0 -1
- package/dist/components/__tests__/Button.test.d.ts +0 -2
- package/dist/components/__tests__/Button.test.d.ts.map +0 -1
- package/dist/components/__tests__/Input.test.d.ts +0 -2
- package/dist/components/__tests__/Input.test.d.ts.map +0 -1
- package/src/components/Table.tsx +0 -239
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
var jsxRuntime = require('react/jsx-runtime');
|
|
4
|
-
var lucideReact = require('lucide-react');
|
|
5
4
|
var React = require('react');
|
|
5
|
+
var lucideReact = require('lucide-react');
|
|
6
6
|
var reactDom = require('react-dom');
|
|
7
7
|
var reactRouterDom = require('react-router-dom');
|
|
8
8
|
|
|
@@ -31,6 +31,8 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
|
31
31
|
* A versatile button component that supports multiple visual styles, sizes, icons,
|
|
32
32
|
* loading states, and notification badges.
|
|
33
33
|
*
|
|
34
|
+
* Supports ref forwarding for DOM access.
|
|
35
|
+
*
|
|
34
36
|
* @example Basic usage
|
|
35
37
|
* ```tsx
|
|
36
38
|
* <Button variant="primary">Click me</Button>
|
|
@@ -57,8 +59,14 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
|
57
59
|
* <Bell />
|
|
58
60
|
* </Button>
|
|
59
61
|
* ```
|
|
62
|
+
*
|
|
63
|
+
* @example With ref
|
|
64
|
+
* ```tsx
|
|
65
|
+
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
66
|
+
* <Button ref={buttonRef}>Focusable</Button>
|
|
67
|
+
* ```
|
|
60
68
|
*/
|
|
61
|
-
|
|
69
|
+
const Button = React.forwardRef(({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }, ref) => {
|
|
62
70
|
const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-400 disabled:opacity-40 disabled:cursor-not-allowed';
|
|
63
71
|
const variantStyles = {
|
|
64
72
|
primary: 'bg-accent-500 text-white border-accent-500 hover:bg-accent-600 hover:shadow-sm active:scale-[0.98]',
|
|
@@ -89,7 +97,7 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
|
|
|
89
97
|
md: 'min-w-[18px] h-[18px] text-[11px] px-1.5',
|
|
90
98
|
lg: 'min-w-[20px] h-5 text-xs px-1.5',
|
|
91
99
|
};
|
|
92
|
-
const buttonElement = (jsxRuntime.jsxs("button", { className: `
|
|
100
|
+
const buttonElement = (jsxRuntime.jsxs("button", { ref: ref, className: `
|
|
93
101
|
${baseStyles}
|
|
94
102
|
${variantStyles[variant]}
|
|
95
103
|
${sizeStyles[size]}
|
|
@@ -112,7 +120,8 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
|
|
|
112
120
|
shadow-sm
|
|
113
121
|
pointer-events-none
|
|
114
122
|
`, "aria-label": `${badgeContent} notifications`, children: badgeContent })] }));
|
|
115
|
-
}
|
|
123
|
+
});
|
|
124
|
+
Button.displayName = 'Button';
|
|
116
125
|
|
|
117
126
|
/**
|
|
118
127
|
* ButtonGroup component - Toggle button group for single or multiple selection.
|
|
@@ -259,7 +268,7 @@ function ButtonGroup({ options, value, values = [], onChange, onChangeMultiple,
|
|
|
259
268
|
* />
|
|
260
269
|
* ```
|
|
261
270
|
*/
|
|
262
|
-
const Input = React.forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
|
|
271
|
+
const Input = React.forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, loading = false, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
|
|
263
272
|
const inputId = id || `input-${Math.random().toString(36).substring(2, 9)}`;
|
|
264
273
|
const [showPassword, setShowPassword] = React.useState(false);
|
|
265
274
|
// Handle clear button click
|
|
@@ -331,7 +340,7 @@ const Input = React.forwardRef(({ label, helperText, validationState, validation
|
|
|
331
340
|
${validationState && !suffix && !suffixIcon && !showPasswordToggle ? 'pr-10' : ''}
|
|
332
341
|
${(showPasswordToggle && type === 'password') || validationState || suffix || suffixIcon ? 'pr-20' : ''}
|
|
333
342
|
${className}
|
|
334
|
-
`, ...props }), suffix && (jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxRuntime.jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsxRuntime.jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsxRuntime.jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsxRuntime.jsx(lucideReact.EyeOff, { className: "h-5 w-5" }) : jsxRuntime.jsx(lucideReact.Eye, { className: "h-5 w-5" }) })), validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxRuntime.jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsxRuntime.jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxRuntime.jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
|
|
343
|
+
`, ...props }), suffix && (jsxRuntime.jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxRuntime.jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [loading && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: jsxRuntime.jsx(lucideReact.Loader2, { className: "h-5 w-5 animate-spin" }) })), suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && !loading && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsxRuntime.jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsxRuntime.jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsxRuntime.jsx(lucideReact.EyeOff, { className: "h-5 w-5" }) : jsxRuntime.jsx(lucideReact.Eye, { className: "h-5 w-5" }) })), validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsxRuntime.jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxRuntime.jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsxRuntime.jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxRuntime.jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
|
|
335
344
|
});
|
|
336
345
|
Input.displayName = 'Input';
|
|
337
346
|
|
|
@@ -538,11 +547,18 @@ const Select = React.forwardRef((props, ref) => {
|
|
|
538
547
|
});
|
|
539
548
|
Select.displayName = 'Select';
|
|
540
549
|
|
|
541
|
-
|
|
550
|
+
const MultiSelect = React.forwardRef(({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, loading = false, 'aria-label': ariaLabel, }, ref) => {
|
|
542
551
|
const [isOpen, setIsOpen] = React.useState(false);
|
|
543
552
|
const [searchQuery, setSearchQuery] = React.useState('');
|
|
544
553
|
const selectRef = React.useRef(null);
|
|
545
554
|
const searchInputRef = React.useRef(null);
|
|
555
|
+
const triggerRef = React.useRef(null);
|
|
556
|
+
// Expose imperative methods
|
|
557
|
+
React.useImperativeHandle(ref, () => ({
|
|
558
|
+
focus: () => triggerRef.current?.focus(),
|
|
559
|
+
open: () => !disabled && setIsOpen(true),
|
|
560
|
+
close: () => setIsOpen(false),
|
|
561
|
+
}));
|
|
546
562
|
const selectedOptions = options.filter(opt => value.includes(opt.value));
|
|
547
563
|
const hasReachedMax = maxSelections ? value.length >= maxSelections : false;
|
|
548
564
|
const filteredOptions = searchable && searchQuery
|
|
@@ -589,11 +605,11 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
|
|
|
589
605
|
e.stopPropagation();
|
|
590
606
|
onChange?.([]);
|
|
591
607
|
};
|
|
592
|
-
return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsx("label", { className: "label", children: label })), jsxRuntime.jsxs("div", { ref: selectRef, className: "relative", children: [jsxRuntime.jsxs("button", { type: "button", onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, className: `
|
|
608
|
+
return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsx("label", { className: "label", children: label })), jsxRuntime.jsxs("div", { ref: selectRef, className: "relative", children: [jsxRuntime.jsxs("button", { ref: triggerRef, type: "button", onClick: () => !disabled && !loading && setIsOpen(!isOpen), disabled: disabled || loading, className: `
|
|
593
609
|
input w-full flex items-center justify-between min-h-[42px]
|
|
594
610
|
${error ? 'border-error-400 focus:border-error-400 focus:ring-error-400' : ''}
|
|
595
|
-
${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
596
|
-
`, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsxRuntime.jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsxRuntime.jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsxRuntime.jsx("span", { className: "text-xs", children: option.icon }), option.label, jsxRuntime.jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ml-2", children: [selectedOptions.length > 0 && !disabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), jsxRuntime.jsx(lucideReact.ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` })] })] }), isOpen && (jsxRuntime.jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsxRuntime.jsx("div", { className: "p-2 border-b border-paper-200", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsxRuntime.jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsxRuntime.jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
|
|
611
|
+
${disabled || loading ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
612
|
+
`, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsxRuntime.jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsxRuntime.jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsxRuntime.jsx("span", { className: "text-xs", children: option.icon }), option.label, jsxRuntime.jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsxRuntime.jsx(lucideReact.X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 ml-2", children: [loading && (jsxRuntime.jsx(lucideReact.Loader2, { className: "h-4 w-4 text-ink-400 animate-spin" })), !loading && selectedOptions.length > 0 && !disabled && (jsxRuntime.jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsxRuntime.jsx(lucideReact.X, { className: "h-4 w-4" }) })), !loading && (jsxRuntime.jsx(lucideReact.ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` }))] })] }), isOpen && (jsxRuntime.jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsxRuntime.jsx("div", { className: "p-2 border-b border-paper-200", children: jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx(lucideReact.Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsxRuntime.jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsxRuntime.jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsxRuntime.jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
|
|
597
613
|
const isSelected = value.includes(option.value);
|
|
598
614
|
const isDisabled = option.disabled || (hasReachedMax && !isSelected);
|
|
599
615
|
return (jsxRuntime.jsx("button", { type: "button", onClick: () => !isDisabled && handleToggle(option.value), disabled: isDisabled, className: `
|
|
@@ -605,7 +621,8 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
|
|
|
605
621
|
${isSelected ? 'bg-accent-600 border-accent-600' : 'border-paper-300'}
|
|
606
622
|
`, children: isSelected && jsxRuntime.jsx(lucideReact.Check, { className: "h-3 w-3 text-white" }) }), option.icon && jsxRuntime.jsx("span", { children: option.icon }), option.label] }) }, option.value));
|
|
607
623
|
})) })] }))] }), jsxRuntime.jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || error) && (jsxRuntime.jsx("p", { className: `text-xs ${error ? 'text-error-600' : 'text-ink-600'}`, children: error || helperText })), maxSelections && (jsxRuntime.jsxs("p", { className: `text-xs ml-auto ${hasReachedMax ? 'text-warning-600 font-medium' : 'text-ink-500'}`, children: [value.length, " / ", maxSelections, " selected"] }))] })] }));
|
|
608
|
-
}
|
|
624
|
+
});
|
|
625
|
+
MultiSelect.displayName = 'MultiSelect';
|
|
609
626
|
|
|
610
627
|
const Switch = React.forwardRef(({ checked, onChange, label, description, disabled = false, size = 'md', loading = false, }, ref) => {
|
|
611
628
|
// Generate unique IDs for ARIA
|
|
@@ -652,7 +669,7 @@ const Switch = React.forwardRef(({ checked, onChange, label, description, disabl
|
|
|
652
669
|
});
|
|
653
670
|
Switch.displayName = 'Switch';
|
|
654
671
|
|
|
655
|
-
const Textarea = React.forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', className = '', id, value, rows = 4, ...props }, ref) => {
|
|
672
|
+
const Textarea = React.forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', loading = false, className = '', id, value, rows = 4, ...props }, ref) => {
|
|
656
673
|
const textareaId = id || `textarea-${Math.random().toString(36).substring(2, 9)}`;
|
|
657
674
|
const currentLength = typeof value === 'string' ? value.length : 0;
|
|
658
675
|
const internalRef = React.useRef(null);
|
|
@@ -727,14 +744,15 @@ const Textarea = React.forwardRef(({ label, helperText, validationState, validat
|
|
|
727
744
|
return 'text-ink-600';
|
|
728
745
|
}
|
|
729
746
|
};
|
|
730
|
-
return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsxRuntime.jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxRuntime.jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
747
|
+
return (jsxRuntime.jsxs("div", { className: "w-full", children: [label && (jsxRuntime.jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsxRuntime.jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxRuntime.jsxs("div", { className: "relative", children: [jsxRuntime.jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
|
|
748
|
+
block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
|
|
749
|
+
bg-white bg-subtle-grain transition-all duration-200
|
|
750
|
+
focus:outline-none focus:ring-2 ${getResizeClass()}
|
|
751
|
+
disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
|
|
752
|
+
${getValidationClasses()}
|
|
753
|
+
${loading ? 'pr-10' : ''}
|
|
754
|
+
${className}
|
|
755
|
+
`, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), loading && (jsxRuntime.jsx("div", { className: "absolute top-3 right-3 pointer-events-none", children: jsxRuntime.jsx(lucideReact.Loader2, { className: "h-5 w-5 text-ink-400 animate-spin" }) }))] }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxRuntime.jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsxRuntime.jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxRuntime.jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
|
|
738
756
|
});
|
|
739
757
|
Textarea.displayName = 'Textarea';
|
|
740
758
|
|
|
@@ -1950,6 +1968,8 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
|
|
|
1950
1968
|
/**
|
|
1951
1969
|
* Card - Container component with paper aesthetic and subtle shadow
|
|
1952
1970
|
*
|
|
1971
|
+
* Supports ref forwarding for DOM access.
|
|
1972
|
+
*
|
|
1953
1973
|
* A content container with paper texture, border, and shadow effects. Supports
|
|
1954
1974
|
* different sizes, variants (padding/shadow levels), and loading states.
|
|
1955
1975
|
*
|
|
@@ -1979,8 +1999,14 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
|
|
|
1979
1999
|
* <p>Content</p>
|
|
1980
2000
|
* </Card>
|
|
1981
2001
|
* ```
|
|
2002
|
+
*
|
|
2003
|
+
* @example With ref
|
|
2004
|
+
* ```tsx
|
|
2005
|
+
* const cardRef = useRef<HTMLDivElement>(null);
|
|
2006
|
+
* <Card ref={cardRef}>Content</Card>
|
|
2007
|
+
* ```
|
|
1982
2008
|
*/
|
|
1983
|
-
|
|
2009
|
+
const Card = React.forwardRef(({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, ...htmlProps }, ref) => {
|
|
1984
2010
|
const baseStyles = 'bg-white bg-subtle-grain border-2 border-paper-300 transition-shadow duration-200';
|
|
1985
2011
|
const variantStyles = {
|
|
1986
2012
|
default: 'rounded-xl shadow-lg p-8',
|
|
@@ -1996,8 +2022,9 @@ function Card({ children, variant = 'default', width = 'auto', className = '', o
|
|
|
1996
2022
|
full: 'w-full',
|
|
1997
2023
|
};
|
|
1998
2024
|
const interactiveStyles = onClick || hoverable ? 'cursor-pointer hover:shadow-md' : '';
|
|
1999
|
-
return (jsxRuntime.jsx("div", { className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx(Skeleton, { className: "h-6 w-3/4" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-full" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-5/6" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
|
|
2000
|
-
}
|
|
2025
|
+
return (jsxRuntime.jsx("div", { ref: ref, ...htmlProps, className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxRuntime.jsxs("div", { className: "space-y-4", children: [jsxRuntime.jsx(Skeleton, { className: "h-6 w-3/4" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-full" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-5/6" }), jsxRuntime.jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
|
|
2026
|
+
});
|
|
2027
|
+
Card.displayName = 'Card';
|
|
2001
2028
|
/**
|
|
2002
2029
|
* CardHeader - Header section for Card component
|
|
2003
2030
|
*
|
|
@@ -2095,15 +2122,34 @@ function Separator({ orientation = 'horizontal', className = '', spacing = 'md',
|
|
|
2095
2122
|
/**
|
|
2096
2123
|
* Stack component for arranging children vertically or horizontally with consistent spacing.
|
|
2097
2124
|
*
|
|
2098
|
-
*
|
|
2125
|
+
* Supports ref forwarding for DOM access.
|
|
2126
|
+
*
|
|
2127
|
+
* Spacing scale (use either `spacing` or `gap` prop - they're aliases):
|
|
2099
2128
|
* - none: 0
|
|
2100
2129
|
* - xs: 0.5rem (2)
|
|
2101
2130
|
* - sm: 0.75rem (3)
|
|
2102
2131
|
* - md: 1.5rem (6)
|
|
2103
2132
|
* - lg: 2rem (8)
|
|
2104
2133
|
* - xl: 3rem (12)
|
|
2134
|
+
*
|
|
2135
|
+
* @example
|
|
2136
|
+
* ```tsx
|
|
2137
|
+
* // Using spacing prop
|
|
2138
|
+
* <Stack spacing="md">
|
|
2139
|
+
* <Card>Item 1</Card>
|
|
2140
|
+
* <Card>Item 2</Card>
|
|
2141
|
+
* </Stack>
|
|
2142
|
+
*
|
|
2143
|
+
* // Using gap prop (alias)
|
|
2144
|
+
* <Stack gap="md">
|
|
2145
|
+
* <Card>Item 1</Card>
|
|
2146
|
+
* <Card>Item 2</Card>
|
|
2147
|
+
* </Stack>
|
|
2148
|
+
* ```
|
|
2105
2149
|
*/
|
|
2106
|
-
const Stack = ({ children, direction = 'vertical', spacing
|
|
2150
|
+
const Stack = React.forwardRef(({ children, direction = 'vertical', spacing, gap, align = 'stretch', justify = 'start', wrap = false, className = '', ...htmlProps }, ref) => {
|
|
2151
|
+
// Use gap as alias for spacing (spacing takes precedence if both provided)
|
|
2152
|
+
const effectiveSpacing = spacing ?? gap ?? 'md';
|
|
2107
2153
|
const spacingClasses = {
|
|
2108
2154
|
vertical: {
|
|
2109
2155
|
none: '',
|
|
@@ -2135,20 +2181,23 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
|
|
|
2135
2181
|
between: 'justify-between',
|
|
2136
2182
|
around: 'justify-around',
|
|
2137
2183
|
};
|
|
2138
|
-
return (jsxRuntime.jsx("div", { className: `
|
|
2184
|
+
return (jsxRuntime.jsx("div", { ref: ref, ...htmlProps, className: `
|
|
2139
2185
|
flex
|
|
2140
2186
|
${direction === 'vertical' ? 'flex-col' : 'flex-row'}
|
|
2141
2187
|
${wrap ? 'flex-wrap' : ''}
|
|
2142
|
-
${spacingClasses[direction][
|
|
2188
|
+
${spacingClasses[direction][effectiveSpacing]}
|
|
2143
2189
|
${alignClasses[align]}
|
|
2144
2190
|
${justifyClasses[justify]}
|
|
2145
2191
|
${className}
|
|
2146
2192
|
`, children: children }));
|
|
2147
|
-
};
|
|
2193
|
+
});
|
|
2194
|
+
Stack.displayName = 'Stack';
|
|
2148
2195
|
|
|
2149
2196
|
/**
|
|
2150
2197
|
* Grid component for arranging children in a CSS grid layout.
|
|
2151
2198
|
*
|
|
2199
|
+
* Supports ref forwarding for DOM access.
|
|
2200
|
+
*
|
|
2152
2201
|
* Column options: 1, 2, 3, 4, 6, 12
|
|
2153
2202
|
*
|
|
2154
2203
|
* Responsive breakpoints (mobile-first):
|
|
@@ -2173,7 +2222,7 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
|
|
|
2173
2222
|
* <Card>Item 2</Card>
|
|
2174
2223
|
* </Grid>
|
|
2175
2224
|
*/
|
|
2176
|
-
const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', }) => {
|
|
2225
|
+
const Grid = React.forwardRef(({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', ...htmlProps }, ref) => {
|
|
2177
2226
|
// Base column classes
|
|
2178
2227
|
const baseColumnClasses = {
|
|
2179
2228
|
1: 'grid-cols-1',
|
|
@@ -2232,18 +2281,20 @@ const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '
|
|
|
2232
2281
|
lg ? lgColumnClasses[lg] : '',
|
|
2233
2282
|
xl ? xlColumnClasses[xl] : '',
|
|
2234
2283
|
].filter(Boolean).join(' ');
|
|
2235
|
-
return (jsxRuntime.jsx("div", { className: `
|
|
2284
|
+
return (jsxRuntime.jsx("div", { ref: ref, ...htmlProps, className: `
|
|
2236
2285
|
grid
|
|
2237
2286
|
${columnClassList}
|
|
2238
2287
|
${gapClasses[gap]}
|
|
2239
2288
|
${className}
|
|
2240
2289
|
`, children: children }));
|
|
2241
|
-
};
|
|
2290
|
+
});
|
|
2291
|
+
Grid.displayName = 'Grid';
|
|
2242
2292
|
|
|
2243
2293
|
/**
|
|
2244
2294
|
* Box component for generic containers with design system spacing and borders.
|
|
2295
|
+
* Supports ref forwarding for DOM access.
|
|
2245
2296
|
*/
|
|
2246
|
-
const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }) => {
|
|
2297
|
+
const Box = React.forwardRef(({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }, ref) => {
|
|
2247
2298
|
const spacingMap = {
|
|
2248
2299
|
none: '0',
|
|
2249
2300
|
xs: '2',
|
|
@@ -2328,7 +2379,7 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
|
|
|
2328
2379
|
};
|
|
2329
2380
|
return roundedClasses[rounded];
|
|
2330
2381
|
};
|
|
2331
|
-
return (jsxRuntime.jsx("div", { ...htmlProps, className: `
|
|
2382
|
+
return (jsxRuntime.jsx("div", { ref: ref, ...htmlProps, className: `
|
|
2332
2383
|
${getPaddingClass()}
|
|
2333
2384
|
${getMarginClass()}
|
|
2334
2385
|
${borderClasses[border]}
|
|
@@ -2338,7 +2389,8 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
|
|
|
2338
2389
|
${getHeightClass()}
|
|
2339
2390
|
${className}
|
|
2340
2391
|
`, children: children }));
|
|
2341
|
-
};
|
|
2392
|
+
});
|
|
2393
|
+
Box.displayName = 'Box';
|
|
2342
2394
|
|
|
2343
2395
|
/**
|
|
2344
2396
|
* GridItem component for items within a Grid layout.
|
|
@@ -2383,6 +2435,8 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
|
|
|
2383
2435
|
/**
|
|
2384
2436
|
* Text component for consistent typography across the application.
|
|
2385
2437
|
*
|
|
2438
|
+
* Supports ref forwarding for DOM access.
|
|
2439
|
+
*
|
|
2386
2440
|
* Size scale:
|
|
2387
2441
|
* - xs: 0.75rem (12px)
|
|
2388
2442
|
* - sm: 0.875rem (14px)
|
|
@@ -2390,8 +2444,21 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
|
|
|
2390
2444
|
* - lg: 1.125rem (18px)
|
|
2391
2445
|
* - xl: 1.25rem (20px)
|
|
2392
2446
|
* - 2xl: 1.5rem (24px)
|
|
2447
|
+
*
|
|
2448
|
+
* @example
|
|
2449
|
+
* ```tsx
|
|
2450
|
+
* <Text size="lg" weight="semibold" color="primary">
|
|
2451
|
+
* Hello World
|
|
2452
|
+
* </Text>
|
|
2453
|
+
*
|
|
2454
|
+
* <Text color="warning">Warning message</Text>
|
|
2455
|
+
*
|
|
2456
|
+
* // With ref
|
|
2457
|
+
* const textRef = useRef<HTMLParagraphElement>(null);
|
|
2458
|
+
* <Text ref={textRef}>Measurable text</Text>
|
|
2459
|
+
* ```
|
|
2393
2460
|
*/
|
|
2394
|
-
const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', }) => {
|
|
2461
|
+
const Text = React.forwardRef(({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', ...htmlProps }, ref) => {
|
|
2395
2462
|
const sizeClasses = {
|
|
2396
2463
|
xs: 'text-xs',
|
|
2397
2464
|
sm: 'text-sm',
|
|
@@ -2413,6 +2480,7 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
|
|
|
2413
2480
|
accent: 'text-primary-600',
|
|
2414
2481
|
error: 'text-error-600',
|
|
2415
2482
|
success: 'text-success-600',
|
|
2483
|
+
warning: 'text-warning-600',
|
|
2416
2484
|
};
|
|
2417
2485
|
const alignClasses = {
|
|
2418
2486
|
left: 'text-left',
|
|
@@ -2444,8 +2512,9 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
|
|
|
2444
2512
|
lineClamp ? lineClampClasses[lineClamp] : '',
|
|
2445
2513
|
className,
|
|
2446
2514
|
].filter(Boolean).join(' ');
|
|
2447
|
-
return (jsxRuntime.jsx(Component, { className: classes, children: children }));
|
|
2448
|
-
};
|
|
2515
|
+
return (jsxRuntime.jsx(Component, { ref: ref, className: classes, ...htmlProps, children: children }));
|
|
2516
|
+
});
|
|
2517
|
+
Text.displayName = 'Text';
|
|
2449
2518
|
|
|
2450
2519
|
const toastStyles = {
|
|
2451
2520
|
success: {
|
|
@@ -2550,6 +2619,7 @@ const sizeClasses$4 = {
|
|
|
2550
2619
|
};
|
|
2551
2620
|
function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton = true, animation = 'scale', }) {
|
|
2552
2621
|
const modalRef = React.useRef(null);
|
|
2622
|
+
const mouseDownOnBackdrop = React.useRef(false);
|
|
2553
2623
|
const titleId = React.useId();
|
|
2554
2624
|
// Handle escape key
|
|
2555
2625
|
React.useEffect(() => {
|
|
@@ -2567,11 +2637,22 @@ function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton
|
|
|
2567
2637
|
document.body.style.overflow = 'unset';
|
|
2568
2638
|
};
|
|
2569
2639
|
}, [isOpen, onClose]);
|
|
2570
|
-
//
|
|
2571
|
-
const
|
|
2640
|
+
// Track if mousedown originated on the backdrop
|
|
2641
|
+
const handleBackdropMouseDown = (e) => {
|
|
2572
2642
|
if (e.target === e.currentTarget) {
|
|
2643
|
+
mouseDownOnBackdrop.current = true;
|
|
2644
|
+
}
|
|
2645
|
+
else {
|
|
2646
|
+
mouseDownOnBackdrop.current = false;
|
|
2647
|
+
}
|
|
2648
|
+
};
|
|
2649
|
+
// Handle click outside - only close if both mousedown and click happened on backdrop
|
|
2650
|
+
const handleBackdropClick = (e) => {
|
|
2651
|
+
if (e.target === e.currentTarget && mouseDownOnBackdrop.current) {
|
|
2573
2652
|
onClose();
|
|
2574
2653
|
}
|
|
2654
|
+
// Reset the flag after handling click
|
|
2655
|
+
mouseDownOnBackdrop.current = false;
|
|
2575
2656
|
};
|
|
2576
2657
|
const getAnimationClass = () => {
|
|
2577
2658
|
switch (animation) {
|
|
@@ -2591,7 +2672,7 @@ function Modal({ isOpen, onClose, title, children, size = 'md', showCloseButton
|
|
|
2591
2672
|
};
|
|
2592
2673
|
if (!isOpen)
|
|
2593
2674
|
return null;
|
|
2594
|
-
return (jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-ink-900 bg-opacity-50 backdrop-blur-sm animate-fade-in", onClick: handleBackdropClick, children: jsxRuntime.jsxs("div", { ref: modalRef, className: `${sizeClasses$4[size]} w-full bg-white bg-subtle-grain rounded-xl shadow-2xl border border-paper-200 ${getAnimationClass()}`, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-paper-200", children: [jsxRuntime.jsx("h3", { id: titleId, className: "text-lg font-medium text-ink-900", children: title }), showCloseButton && (jsxRuntime.jsx("button", { onClick: onClose, className: "text-ink-400 hover:text-ink-600 transition-colors", "aria-label": "Close modal", children: jsxRuntime.jsx(lucideReact.X, { className: "h-5 w-5" }) }))] }), jsxRuntime.jsx("div", { className: "px-6 py-4", children: children })] }) }));
|
|
2675
|
+
return (jsxRuntime.jsx("div", { className: "fixed inset-0 z-50 flex items-center justify-center p-4 bg-ink-900 bg-opacity-50 backdrop-blur-sm animate-fade-in", onMouseDown: handleBackdropMouseDown, onClick: handleBackdropClick, children: jsxRuntime.jsxs("div", { ref: modalRef, className: `${sizeClasses$4[size]} w-full bg-white bg-subtle-grain rounded-xl shadow-2xl border border-paper-200 ${getAnimationClass()}`, role: "dialog", "aria-modal": "true", "aria-labelledby": titleId, children: [jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4 border-b border-paper-200", children: [jsxRuntime.jsx("h3", { id: titleId, className: "text-lg font-medium text-ink-900", children: title }), showCloseButton && (jsxRuntime.jsx("button", { onClick: onClose, className: "text-ink-400 hover:text-ink-600 transition-colors", "aria-label": "Close modal", children: jsxRuntime.jsx(lucideReact.X, { className: "h-5 w-5" }) }))] }), jsxRuntime.jsx("div", { className: "px-6 py-4", children: children })] }) }));
|
|
2595
2676
|
}
|
|
2596
2677
|
function ModalFooter({ children }) {
|
|
2597
2678
|
return (jsxRuntime.jsx("div", { className: "flex items-center justify-end gap-3 px-6 py-4 border-t border-paper-200 bg-paper-50", children: children }));
|
|
@@ -5976,19 +6057,19 @@ function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'und
|
|
|
5976
6057
|
spacing: orientation === 'vertical' ? 'mt-8' : 'mt-8',
|
|
5977
6058
|
},
|
|
5978
6059
|
};
|
|
5979
|
-
return (jsxRuntime.jsxs("div", { className: `w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`, children: [jsxRuntime.jsx("div", { className: `
|
|
5980
|
-
flex ${orientation === 'vertical' ? 'flex-col' : ''}
|
|
6060
|
+
return (jsxRuntime.jsxs("div", { className: `w-full ${orientation === 'vertical' ? `flex ${sizeClasses[size].gap}` : ''}`, children: [jsxRuntime.jsx("div", { className: `
|
|
6061
|
+
flex ${orientation === 'vertical' ? 'flex-col' : ''}
|
|
5981
6062
|
${variant === 'underline'
|
|
5982
6063
|
? orientation === 'vertical'
|
|
5983
6064
|
? `border-r border-paper-200 ${sizeClasses[size].gap} pr-6`
|
|
5984
6065
|
: `border-b border-paper-200 ${sizeClasses[size].gap}`
|
|
5985
|
-
: `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`}
|
|
5986
|
-
${sizeClasses[size].minWidth}
|
|
6066
|
+
: `${sizeClasses[size].gap} p-1 bg-paper-50 rounded-lg`}
|
|
6067
|
+
${sizeClasses[size].minWidth}
|
|
5987
6068
|
`, role: "tablist", children: tabs.map((tab) => {
|
|
5988
6069
|
const isActive = activeTab === tab.id;
|
|
5989
|
-
return (jsxRuntime.jsxs("button", { role: "tab", "aria-selected": isActive, "aria-controls": `panel-${tab.id}`, disabled: tab.disabled, onClick: () => !tab.disabled && handleTabChange(tab.id), className: `
|
|
5990
|
-
flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
|
|
5991
|
-
${orientation === 'vertical' ? 'w-full justify-start' : ''}
|
|
6070
|
+
return (jsxRuntime.jsxs("button", { role: "tab", "aria-selected": isActive, "aria-controls": `panel-${tab.id}`, disabled: tab.disabled, onClick: () => !tab.disabled && handleTabChange(tab.id), className: `
|
|
6071
|
+
flex items-center gap-2 ${sizeClasses[size].padding} ${sizeClasses[size].text} font-medium transition-all duration-200
|
|
6072
|
+
${orientation === 'vertical' ? 'w-full justify-start' : ''}
|
|
5992
6073
|
${variant === 'underline'
|
|
5993
6074
|
? isActive
|
|
5994
6075
|
? orientation === 'vertical'
|
|
@@ -5999,8 +6080,8 @@ function Tabs({ tabs, activeTab: controlledActiveTab, defaultTab, variant = 'und
|
|
|
5999
6080
|
: 'text-ink-600 hover:text-ink-900 border-b-2 border-transparent'
|
|
6000
6081
|
: isActive
|
|
6001
6082
|
? 'bg-white text-accent-900 rounded-md shadow-xs'
|
|
6002
|
-
: 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'}
|
|
6003
|
-
${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
6083
|
+
: 'text-ink-600 hover:text-ink-900 hover:bg-white/50 rounded-md'}
|
|
6084
|
+
${tab.disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
6004
6085
|
`, children: [tab.icon && jsxRuntime.jsx("span", { className: `flex-shrink-0 ${sizeClasses[size].icon}`, children: tab.icon }), jsxRuntime.jsx("span", { children: tab.label })] }, tab.id));
|
|
6005
6086
|
}) }), jsxRuntime.jsx("div", { className: `${orientation === 'vertical' ? 'flex-1' : sizeClasses[size].spacing}`, children: tabs.map((tab) => (jsxRuntime.jsx("div", { id: `panel-${tab.id}`, role: "tabpanel", "aria-labelledby": tab.id, hidden: activeTab !== tab.id, className: activeTab === tab.id ? 'animate-fade-in' : '', children: activeTab === tab.id && tab.content }, tab.id))) })] }));
|
|
6006
6087
|
}
|
|
@@ -6076,99 +6157,6 @@ function StepIndicator({ steps, currentStep, variant = 'horizontal', onStepClick
|
|
|
6076
6157
|
}) }) }));
|
|
6077
6158
|
}
|
|
6078
6159
|
|
|
6079
|
-
function Table$1({ data, columns, keyExtractor, selectable = false, expandable = false, onRowSelect, renderExpandedRow, emptyState, className = '', onSort, sortColumn: externalSortColumn, sortDirection: externalSortDirection, }) {
|
|
6080
|
-
const [internalSortColumn, setInternalSortColumn] = React.useState(null);
|
|
6081
|
-
const [internalSortDirection, setInternalSortDirection] = React.useState(null);
|
|
6082
|
-
// Use external sort state if provided, otherwise use internal state
|
|
6083
|
-
const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
|
|
6084
|
-
const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
|
|
6085
|
-
const [selectedRows, setSelectedRows] = React.useState(new Set());
|
|
6086
|
-
const [expandedRows, setExpandedRows] = React.useState(new Set());
|
|
6087
|
-
// Handle sorting
|
|
6088
|
-
const handleSort = (columnKey) => {
|
|
6089
|
-
let newDirection;
|
|
6090
|
-
if (sortColumn === columnKey) {
|
|
6091
|
-
if (sortDirection === 'asc') {
|
|
6092
|
-
newDirection = 'desc';
|
|
6093
|
-
}
|
|
6094
|
-
else if (sortDirection === 'desc') {
|
|
6095
|
-
newDirection = null;
|
|
6096
|
-
}
|
|
6097
|
-
else {
|
|
6098
|
-
newDirection = 'asc';
|
|
6099
|
-
}
|
|
6100
|
-
}
|
|
6101
|
-
else {
|
|
6102
|
-
newDirection = 'asc';
|
|
6103
|
-
}
|
|
6104
|
-
// If using external sort control, call the callback
|
|
6105
|
-
if (onSort) {
|
|
6106
|
-
onSort(columnKey, newDirection);
|
|
6107
|
-
}
|
|
6108
|
-
else {
|
|
6109
|
-
// Otherwise update internal state
|
|
6110
|
-
setInternalSortColumn(newDirection === null ? null : columnKey);
|
|
6111
|
-
setInternalSortDirection(newDirection);
|
|
6112
|
-
}
|
|
6113
|
-
};
|
|
6114
|
-
// Handle row selection
|
|
6115
|
-
const handleRowSelect = (rowKey) => {
|
|
6116
|
-
const newSelected = new Set(selectedRows);
|
|
6117
|
-
if (newSelected.has(rowKey)) {
|
|
6118
|
-
newSelected.delete(rowKey);
|
|
6119
|
-
}
|
|
6120
|
-
else {
|
|
6121
|
-
newSelected.add(rowKey);
|
|
6122
|
-
}
|
|
6123
|
-
setSelectedRows(newSelected);
|
|
6124
|
-
onRowSelect?.(Array.from(newSelected));
|
|
6125
|
-
};
|
|
6126
|
-
// Handle select all
|
|
6127
|
-
const handleSelectAll = () => {
|
|
6128
|
-
if (selectedRows.size === data.length) {
|
|
6129
|
-
setSelectedRows(new Set());
|
|
6130
|
-
onRowSelect?.([]);
|
|
6131
|
-
}
|
|
6132
|
-
else {
|
|
6133
|
-
const allKeys = new Set(data.map(keyExtractor));
|
|
6134
|
-
setSelectedRows(allKeys);
|
|
6135
|
-
onRowSelect?.(Array.from(allKeys));
|
|
6136
|
-
}
|
|
6137
|
-
};
|
|
6138
|
-
// Handle row expansion
|
|
6139
|
-
const handleRowExpand = (rowKey) => {
|
|
6140
|
-
const newExpanded = new Set(expandedRows);
|
|
6141
|
-
if (newExpanded.has(rowKey)) {
|
|
6142
|
-
newExpanded.delete(rowKey);
|
|
6143
|
-
}
|
|
6144
|
-
else {
|
|
6145
|
-
newExpanded.add(rowKey);
|
|
6146
|
-
}
|
|
6147
|
-
setExpandedRows(newExpanded);
|
|
6148
|
-
};
|
|
6149
|
-
const getSortIcon = (columnKey) => {
|
|
6150
|
-
if (sortColumn !== columnKey) {
|
|
6151
|
-
return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
|
|
6152
|
-
}
|
|
6153
|
-
if (sortDirection === 'asc') {
|
|
6154
|
-
return jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4 text-accent-600" });
|
|
6155
|
-
}
|
|
6156
|
-
if (sortDirection === 'desc') {
|
|
6157
|
-
return jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-4 w-4 text-accent-600" });
|
|
6158
|
-
}
|
|
6159
|
-
return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
|
|
6160
|
-
};
|
|
6161
|
-
if (data.length === 0 && emptyState) {
|
|
6162
|
-
return jsxRuntime.jsx("div", { children: emptyState });
|
|
6163
|
-
}
|
|
6164
|
-
return (jsxRuntime.jsx("div", { className: `overflow-x-auto ${className}`, children: jsxRuntime.jsxs("table", { className: "table", children: [jsxRuntime.jsx("thead", { className: "table-header", children: jsxRuntime.jsxs("tr", { children: [selectable && (jsxRuntime.jsx("th", { className: "table-header-cell w-12", children: jsxRuntime.jsx("input", { type: "checkbox", checked: selectedRows.size === data.length && data.length > 0, onChange: handleSelectAll, className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": "Select all rows" }) })), expandable && jsxRuntime.jsx("th", { className: "table-header-cell w-12" }), columns.map((column) => (jsxRuntime.jsx("th", { className: "table-header-cell", style: { width: column.width }, children: column.sortable ? (jsxRuntime.jsxs("button", { onClick: () => handleSort(column.key), className: "group inline-flex items-center gap-2 hover:text-ink-900 transition-colors", children: [jsxRuntime.jsx("span", { children: column.header }), getSortIcon(column.key)] })) : (column.header) }, column.key)))] }) }), jsxRuntime.jsx("tbody", { children: data.map((row) => {
|
|
6165
|
-
const rowKey = keyExtractor(row);
|
|
6166
|
-
const isSelected = selectedRows.has(rowKey);
|
|
6167
|
-
const isExpanded = expandedRows.has(rowKey);
|
|
6168
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { className: `table-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : ''}`, children: [selectable && (jsxRuntime.jsx("td", { className: "table-cell", children: jsxRuntime.jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleRowSelect(rowKey), className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": `Select row ${rowKey}` }) })), expandable && (jsxRuntime.jsx("td", { className: "table-cell", children: jsxRuntime.jsx("button", { onClick: () => handleRowExpand(rowKey), className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded ? 'Collapse row' : 'Expand row', children: isExpanded ? (jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" })) : (jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })) }) })), columns.map((column) => (jsxRuntime.jsx("td", { className: "table-cell", children: column.accessor ? column.accessor(row) : row[column.key] }, column.key)))] }), expandable && isExpanded && renderExpandedRow && (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0), className: "px-6 py-4 bg-paper-50", children: renderExpandedRow(row) }) }))] }, rowKey));
|
|
6169
|
-
}) })] }) }));
|
|
6170
|
-
}
|
|
6171
|
-
|
|
6172
6160
|
function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, }) {
|
|
6173
6161
|
const variantStyles = {
|
|
6174
6162
|
success: 'bg-success-50 text-success-700 border-success-200',
|
|
@@ -6276,8 +6264,8 @@ const Avatar = ({ firstName, lastName, fallbackText = 'U', imageUrl, size = 'md'
|
|
|
6276
6264
|
`, style: { textShadow: '0 1px 2px rgba(0,0,0,0.3)' }, children: getInitials() }) }));
|
|
6277
6265
|
};
|
|
6278
6266
|
|
|
6279
|
-
function EmptyState({ icon, title, description, action, secondaryAction, }) {
|
|
6280
|
-
return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsxRuntime.jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsxRuntime.jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsxRuntime.jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), (action || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [action && (jsxRuntime.jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsxRuntime.jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
|
|
6267
|
+
function EmptyState({ icon, title, description, action, secondaryAction, children, }) {
|
|
6268
|
+
return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsxRuntime.jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsxRuntime.jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsxRuntime.jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), children && (jsxRuntime.jsx("div", { className: "mb-8 w-full max-w-md", children: children })), (action || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [action && (jsxRuntime.jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsxRuntime.jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
|
|
6281
6269
|
}
|
|
6282
6270
|
|
|
6283
6271
|
/**
|
|
@@ -6928,8 +6916,35 @@ const TwoColumnContent = ({ sidebar, children, className = '', }) => {
|
|
|
6928
6916
|
* </PageLayout>
|
|
6929
6917
|
* ```
|
|
6930
6918
|
*/
|
|
6931
|
-
const Page = ({ children, maxWidth
|
|
6932
|
-
|
|
6919
|
+
const Page = ({ children, maxWidth = '7xl', className = '', padding = 'normal', fixed = false }) => {
|
|
6920
|
+
// Max width classes
|
|
6921
|
+
const maxWidthClasses = {
|
|
6922
|
+
'4xl': 'max-w-4xl',
|
|
6923
|
+
'5xl': 'max-w-5xl',
|
|
6924
|
+
'6xl': 'max-w-6xl',
|
|
6925
|
+
'7xl': 'max-w-7xl',
|
|
6926
|
+
'full': 'max-w-full',
|
|
6927
|
+
};
|
|
6928
|
+
// Padding classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
|
|
6929
|
+
const paddingClasses = {
|
|
6930
|
+
none: fixed ? 'p-0' : 'pt-0 pl-0 pr-0 pb-0',
|
|
6931
|
+
sm: fixed ? 'p-4' : 'pt-4 pl-4 pr-4 pb-4 sm:pr-6 md:pr-8 sm:pb-6 md:pb-8',
|
|
6932
|
+
normal: fixed ? 'pt-12 pl-20 pr-16 pb-12' : 'pt-12 pl-20 pr-4 pb-4 sm:pr-8 md:pr-12 lg:pr-16 sm:pb-8 md:pb-12 lg:pb-16',
|
|
6933
|
+
lg: fixed ? 'pt-16 pl-24 pr-20 pb-16' : 'pt-16 pl-24 pr-6 pb-6 sm:pr-12 md:pr-16 lg:pr-20 sm:pb-12 md:pb-16 lg:pb-20',
|
|
6934
|
+
};
|
|
6935
|
+
// Margin classes - responsive (fixed left/top, responsive right/bottom) vs all fixed
|
|
6936
|
+
const marginClasses = fixed
|
|
6937
|
+
? 'mt-4 ml-4 mr-4 mb-4'
|
|
6938
|
+
: 'mt-4 ml-4 mr-4 mb-4 sm:mr-6 md:mr-8 lg:mr-auto sm:mb-6 md:mb-8';
|
|
6939
|
+
return (jsxRuntime.jsx("div", { className: "min-h-screen bg-paper-100", children: jsxRuntime.jsx("div", { className: `
|
|
6940
|
+
bg-white bg-subtle-grain rounded-sm shadow-lg border-l-4 border-paper-300
|
|
6941
|
+
min-h-[calc(100vh-2rem)] relative
|
|
6942
|
+
notebook-margin notebook-ruled
|
|
6943
|
+
${maxWidthClasses[maxWidth]}
|
|
6944
|
+
${paddingClasses[padding]}
|
|
6945
|
+
${marginClasses}
|
|
6946
|
+
${className}
|
|
6947
|
+
`.trim().replace(/\s+/g, ' '), children: children }) }));
|
|
6933
6948
|
};
|
|
6934
6949
|
|
|
6935
6950
|
/**
|
|
@@ -7264,9 +7279,11 @@ function getColumnStyle(column, dynamicWidth) {
|
|
|
7264
7279
|
* />
|
|
7265
7280
|
* ```
|
|
7266
7281
|
*/
|
|
7267
|
-
function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
|
|
7282
|
+
function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], enableContextMenu = true, onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
|
|
7268
7283
|
// Visual customization props
|
|
7269
|
-
striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
|
|
7284
|
+
striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
|
|
7285
|
+
// Pagination props
|
|
7286
|
+
paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true, }) {
|
|
7270
7287
|
// Column resizing state
|
|
7271
7288
|
const [columnWidths, setColumnWidths] = React.useState({});
|
|
7272
7289
|
const [resizingColumn, setResizingColumn] = React.useState(null);
|
|
@@ -7281,6 +7298,12 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7281
7298
|
const tableContainerRef = React.useRef(null);
|
|
7282
7299
|
// Row hover state (for coordinating primary + secondary row highlighting)
|
|
7283
7300
|
const [hoveredRowKey, setHoveredRowKey] = React.useState(null);
|
|
7301
|
+
// Context menu state
|
|
7302
|
+
const [contextMenuState, setContextMenuState] = React.useState({
|
|
7303
|
+
isOpen: false,
|
|
7304
|
+
position: { x: 0, y: 0 },
|
|
7305
|
+
item: null,
|
|
7306
|
+
});
|
|
7284
7307
|
// Filter columns based on hiddenColumns
|
|
7285
7308
|
const baseVisibleColumns = columns.filter(col => !hiddenColumns.includes(String(col.key)));
|
|
7286
7309
|
// Initialize column order on mount or when columns change
|
|
@@ -7493,16 +7516,52 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7493
7516
|
}
|
|
7494
7517
|
});
|
|
7495
7518
|
}
|
|
7519
|
+
// Combine all actions: built-in first, then custom actions, then delete last
|
|
7520
|
+
// Delete is stored separately to ensure it's always last
|
|
7521
|
+
let deleteAction = null;
|
|
7496
7522
|
if (onDelete) {
|
|
7497
|
-
|
|
7523
|
+
deleteAction = {
|
|
7498
7524
|
label: 'Delete',
|
|
7499
7525
|
icon: lucideReact.Trash,
|
|
7500
7526
|
onClick: onDelete,
|
|
7501
7527
|
variant: 'danger',
|
|
7502
7528
|
tooltip: 'Delete item'
|
|
7503
|
-
}
|
|
7529
|
+
};
|
|
7504
7530
|
}
|
|
7505
|
-
|
|
7531
|
+
// Build final actions array with consistent ordering:
|
|
7532
|
+
// 1. Edit (first - most common action)
|
|
7533
|
+
// 2. View Details
|
|
7534
|
+
// 3. Add Related actions
|
|
7535
|
+
// 4. Manage Related actions
|
|
7536
|
+
// 5. Custom actions (from actions prop)
|
|
7537
|
+
// 6. Delete (always last - destructive action)
|
|
7538
|
+
const allActions = [
|
|
7539
|
+
...builtInActions,
|
|
7540
|
+
...actions,
|
|
7541
|
+
...(deleteAction ? [deleteAction] : [])
|
|
7542
|
+
];
|
|
7543
|
+
// Convert actions to menu items for context menu
|
|
7544
|
+
const convertActionsToMenuItems = (item) => {
|
|
7545
|
+
const visibleActions = allActions.filter(action => !action.show || action.show(item));
|
|
7546
|
+
return visibleActions.map((action, idx) => {
|
|
7547
|
+
let iconElement = null;
|
|
7548
|
+
if (action.icon) {
|
|
7549
|
+
if (React.isValidElement(action.icon)) {
|
|
7550
|
+
iconElement = action.icon;
|
|
7551
|
+
}
|
|
7552
|
+
else {
|
|
7553
|
+
iconElement = React.createElement(action.icon, { className: 'h-4 w-4' });
|
|
7554
|
+
}
|
|
7555
|
+
}
|
|
7556
|
+
return {
|
|
7557
|
+
id: `action-${idx}`,
|
|
7558
|
+
label: action.label,
|
|
7559
|
+
icon: iconElement,
|
|
7560
|
+
onClick: () => action.onClick(item),
|
|
7561
|
+
danger: action.variant === 'danger',
|
|
7562
|
+
};
|
|
7563
|
+
});
|
|
7564
|
+
};
|
|
7506
7565
|
// Selection state management
|
|
7507
7566
|
const [internalSelectedRows, setInternalSelectedRows] = React.useState(new Set());
|
|
7508
7567
|
// Expansion state management
|
|
@@ -7660,7 +7719,19 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7660
7719
|
// Hover state for row pair (primary + secondary)
|
|
7661
7720
|
const isHovered = hoveredRowKey === rowKey;
|
|
7662
7721
|
const hoverClass = disableHover ? '' : (isHovered ? 'bg-paper-100' : '');
|
|
7663
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { className: `table-row-stable ${onRowDoubleClick || onRowClick || onEdit || expandedRowConfig?.edit || expandedRowConfig?.details || expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length ? 'cursor-pointer' : ''} ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : hoverClass || rowBgClass} ${borderClass}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), onClick: () => onRowClick?.(item),
|
|
7722
|
+
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { className: `table-row-stable ${onRowDoubleClick || onRowClick || onEdit || expandedRowConfig?.edit || expandedRowConfig?.details || expandedRowConfig?.addRelated?.length || expandedRowConfig?.manageRelated?.length ? 'cursor-pointer' : ''} ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : hoverClass || rowBgClass} ${borderClass}`, onMouseEnter: () => !disableHover && setHoveredRowKey(rowKey), onMouseLeave: () => !disableHover && setHoveredRowKey(null), onClick: () => onRowClick?.(item), onContextMenu: (e) => {
|
|
7723
|
+
if (enableContextMenu && allActions.length > 0) {
|
|
7724
|
+
e.preventDefault();
|
|
7725
|
+
e.stopPropagation();
|
|
7726
|
+
const x = e.clientX;
|
|
7727
|
+
const y = e.clientY;
|
|
7728
|
+
setContextMenuState({
|
|
7729
|
+
isOpen: true,
|
|
7730
|
+
position: { x, y },
|
|
7731
|
+
item,
|
|
7732
|
+
});
|
|
7733
|
+
}
|
|
7734
|
+
}, onDoubleClick: () => {
|
|
7664
7735
|
// Priority 1: If there's an onEdit handler (legacy), trigger it
|
|
7665
7736
|
if (onEdit) {
|
|
7666
7737
|
onEdit(item);
|
|
@@ -7816,10 +7887,23 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7816
7887
|
}, children: jsxRuntime.jsx("div", { className: "absolute right-0 top-0 bottom-0 w-1 bg-paper-300 group-hover:bg-accent-400 transition-colors" }) }))] }, columnKey));
|
|
7817
7888
|
})] }) }), jsxRuntime.jsx("tbody", { className: "bg-white table-loading transition-opacity duration-200", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
|
|
7818
7889
|
// Wrap in scrollable container if virtualized
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7890
|
+
const finalContent = virtualized ? (jsxRuntime.jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent })) : tableContent;
|
|
7891
|
+
// Calculate pagination values
|
|
7892
|
+
const effectiveTotalItems = totalItems ?? data.length;
|
|
7893
|
+
const totalPages = Math.ceil(effectiveTotalItems / pageSize);
|
|
7894
|
+
// Page size selector options
|
|
7895
|
+
const pageSizeSelectOptions = pageSizeOptions.map(size => ({
|
|
7896
|
+
value: String(size),
|
|
7897
|
+
label: `${size} per page`,
|
|
7898
|
+
}));
|
|
7899
|
+
// Render pagination controls
|
|
7900
|
+
const renderPaginationControls = () => {
|
|
7901
|
+
if (!paginated)
|
|
7902
|
+
return null;
|
|
7903
|
+
return (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsxRuntime.jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: ["Showing ", ((currentPage - 1) * pageSize) + 1, " - ", Math.min(currentPage * pageSize, effectiveTotalItems), " of ", effectiveTotalItems] })) : ('No items') })] }), totalPages > 1 && onPageChange && (jsxRuntime.jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
|
|
7904
|
+
};
|
|
7905
|
+
// Render with context menu
|
|
7906
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderPaginationControls(), finalContent, contextMenuState.isOpen && contextMenuState.item && (jsxRuntime.jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
|
|
7823
7907
|
}
|
|
7824
7908
|
|
|
7825
7909
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
@@ -11631,12 +11715,12 @@ var bessel$1 = {};
|
|
|
11631
11715
|
|
|
11632
11716
|
/* bessel.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
|
11633
11717
|
|
|
11634
|
-
(function (exports) {
|
|
11718
|
+
(function (exports$1) {
|
|
11635
11719
|
(function (factory) {
|
|
11636
11720
|
/*jshint ignore:start */
|
|
11637
11721
|
if(typeof DO_NOT_EXPORT_BESSEL === 'undefined') {
|
|
11638
11722
|
{
|
|
11639
|
-
factory(exports);
|
|
11723
|
+
factory(exports$1);
|
|
11640
11724
|
}
|
|
11641
11725
|
} else {
|
|
11642
11726
|
factory({});
|
|
@@ -11870,7 +11954,7 @@ var bessel$1 = {};
|
|
|
11870
11954
|
|
|
11871
11955
|
var jstat = {exports: {}};
|
|
11872
11956
|
|
|
11873
|
-
(function (module, exports) {
|
|
11957
|
+
(function (module, exports$1) {
|
|
11874
11958
|
(function (window, factory) {
|
|
11875
11959
|
{
|
|
11876
11960
|
module.exports = factory();
|
|
@@ -30527,7 +30611,7 @@ var hasRequiredScheduler_production;
|
|
|
30527
30611
|
function requireScheduler_production () {
|
|
30528
30612
|
if (hasRequiredScheduler_production) return scheduler_production;
|
|
30529
30613
|
hasRequiredScheduler_production = 1;
|
|
30530
|
-
(function (exports) {
|
|
30614
|
+
(function (exports$1) {
|
|
30531
30615
|
function push(heap, node) {
|
|
30532
30616
|
var index = heap.length;
|
|
30533
30617
|
heap.push(node);
|
|
@@ -30576,16 +30660,16 @@ function requireScheduler_production () {
|
|
|
30576
30660
|
var diff = a.sortIndex - b.sortIndex;
|
|
30577
30661
|
return 0 !== diff ? diff : a.id - b.id;
|
|
30578
30662
|
}
|
|
30579
|
-
exports.unstable_now = void 0;
|
|
30663
|
+
exports$1.unstable_now = void 0;
|
|
30580
30664
|
if ("object" === typeof performance && "function" === typeof performance.now) {
|
|
30581
30665
|
var localPerformance = performance;
|
|
30582
|
-
exports.unstable_now = function () {
|
|
30666
|
+
exports$1.unstable_now = function () {
|
|
30583
30667
|
return localPerformance.now();
|
|
30584
30668
|
};
|
|
30585
30669
|
} else {
|
|
30586
30670
|
var localDate = Date,
|
|
30587
30671
|
initialTime = localDate.now();
|
|
30588
|
-
exports.unstable_now = function () {
|
|
30672
|
+
exports$1.unstable_now = function () {
|
|
30589
30673
|
return localDate.now() - initialTime;
|
|
30590
30674
|
};
|
|
30591
30675
|
}
|
|
@@ -30633,14 +30717,14 @@ function requireScheduler_production () {
|
|
|
30633
30717
|
function shouldYieldToHost() {
|
|
30634
30718
|
return needsPaint
|
|
30635
30719
|
? true
|
|
30636
|
-
: exports.unstable_now() - startTime < frameInterval
|
|
30720
|
+
: exports$1.unstable_now() - startTime < frameInterval
|
|
30637
30721
|
? false
|
|
30638
30722
|
: true;
|
|
30639
30723
|
}
|
|
30640
30724
|
function performWorkUntilDeadline() {
|
|
30641
30725
|
needsPaint = false;
|
|
30642
30726
|
if (isMessageLoopRunning) {
|
|
30643
|
-
var currentTime = exports.unstable_now();
|
|
30727
|
+
var currentTime = exports$1.unstable_now();
|
|
30644
30728
|
startTime = currentTime;
|
|
30645
30729
|
var hasMoreWork = true;
|
|
30646
30730
|
try {
|
|
@@ -30670,7 +30754,7 @@ function requireScheduler_production () {
|
|
|
30670
30754
|
var continuationCallback = callback(
|
|
30671
30755
|
currentTask.expirationTime <= currentTime
|
|
30672
30756
|
);
|
|
30673
|
-
currentTime = exports.unstable_now();
|
|
30757
|
+
currentTime = exports$1.unstable_now();
|
|
30674
30758
|
if ("function" === typeof continuationCallback) {
|
|
30675
30759
|
currentTask.callback = continuationCallback;
|
|
30676
30760
|
advanceTimers(currentTime);
|
|
@@ -30726,29 +30810,29 @@ function requireScheduler_production () {
|
|
|
30726
30810
|
};
|
|
30727
30811
|
function requestHostTimeout(callback, ms) {
|
|
30728
30812
|
taskTimeoutID = localSetTimeout(function () {
|
|
30729
|
-
callback(exports.unstable_now());
|
|
30813
|
+
callback(exports$1.unstable_now());
|
|
30730
30814
|
}, ms);
|
|
30731
30815
|
}
|
|
30732
|
-
exports.unstable_IdlePriority = 5;
|
|
30733
|
-
exports.unstable_ImmediatePriority = 1;
|
|
30734
|
-
exports.unstable_LowPriority = 4;
|
|
30735
|
-
exports.unstable_NormalPriority = 3;
|
|
30736
|
-
exports.unstable_Profiling = null;
|
|
30737
|
-
exports.unstable_UserBlockingPriority = 2;
|
|
30738
|
-
exports.unstable_cancelCallback = function (task) {
|
|
30816
|
+
exports$1.unstable_IdlePriority = 5;
|
|
30817
|
+
exports$1.unstable_ImmediatePriority = 1;
|
|
30818
|
+
exports$1.unstable_LowPriority = 4;
|
|
30819
|
+
exports$1.unstable_NormalPriority = 3;
|
|
30820
|
+
exports$1.unstable_Profiling = null;
|
|
30821
|
+
exports$1.unstable_UserBlockingPriority = 2;
|
|
30822
|
+
exports$1.unstable_cancelCallback = function (task) {
|
|
30739
30823
|
task.callback = null;
|
|
30740
30824
|
};
|
|
30741
|
-
exports.unstable_forceFrameRate = function (fps) {
|
|
30825
|
+
exports$1.unstable_forceFrameRate = function (fps) {
|
|
30742
30826
|
0 > fps || 125 < fps
|
|
30743
30827
|
? console.error(
|
|
30744
30828
|
"forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"
|
|
30745
30829
|
)
|
|
30746
30830
|
: (frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5);
|
|
30747
30831
|
};
|
|
30748
|
-
exports.unstable_getCurrentPriorityLevel = function () {
|
|
30832
|
+
exports$1.unstable_getCurrentPriorityLevel = function () {
|
|
30749
30833
|
return currentPriorityLevel;
|
|
30750
30834
|
};
|
|
30751
|
-
exports.unstable_next = function (eventHandler) {
|
|
30835
|
+
exports$1.unstable_next = function (eventHandler) {
|
|
30752
30836
|
switch (currentPriorityLevel) {
|
|
30753
30837
|
case 1:
|
|
30754
30838
|
case 2:
|
|
@@ -30766,10 +30850,10 @@ function requireScheduler_production () {
|
|
|
30766
30850
|
currentPriorityLevel = previousPriorityLevel;
|
|
30767
30851
|
}
|
|
30768
30852
|
};
|
|
30769
|
-
exports.unstable_requestPaint = function () {
|
|
30853
|
+
exports$1.unstable_requestPaint = function () {
|
|
30770
30854
|
needsPaint = true;
|
|
30771
30855
|
};
|
|
30772
|
-
exports.unstable_runWithPriority = function (priorityLevel, eventHandler) {
|
|
30856
|
+
exports$1.unstable_runWithPriority = function (priorityLevel, eventHandler) {
|
|
30773
30857
|
switch (priorityLevel) {
|
|
30774
30858
|
case 1:
|
|
30775
30859
|
case 2:
|
|
@@ -30788,12 +30872,12 @@ function requireScheduler_production () {
|
|
|
30788
30872
|
currentPriorityLevel = previousPriorityLevel;
|
|
30789
30873
|
}
|
|
30790
30874
|
};
|
|
30791
|
-
exports.unstable_scheduleCallback = function (
|
|
30875
|
+
exports$1.unstable_scheduleCallback = function (
|
|
30792
30876
|
priorityLevel,
|
|
30793
30877
|
callback,
|
|
30794
30878
|
options
|
|
30795
30879
|
) {
|
|
30796
|
-
var currentTime = exports.unstable_now();
|
|
30880
|
+
var currentTime = exports$1.unstable_now();
|
|
30797
30881
|
"object" === typeof options && null !== options
|
|
30798
30882
|
? ((options = options.delay),
|
|
30799
30883
|
(options =
|
|
@@ -30844,8 +30928,8 @@ function requireScheduler_production () {
|
|
|
30844
30928
|
((isMessageLoopRunning = true), schedulePerformWorkUntilDeadline())));
|
|
30845
30929
|
return priorityLevel;
|
|
30846
30930
|
};
|
|
30847
|
-
exports.unstable_shouldYield = shouldYieldToHost;
|
|
30848
|
-
exports.unstable_wrapCallback = function (callback) {
|
|
30931
|
+
exports$1.unstable_shouldYield = shouldYieldToHost;
|
|
30932
|
+
exports$1.unstable_wrapCallback = function (callback) {
|
|
30849
30933
|
var parentPriorityLevel = currentPriorityLevel;
|
|
30850
30934
|
return function () {
|
|
30851
30935
|
var previousPriorityLevel = currentPriorityLevel;
|
|
@@ -30878,13 +30962,13 @@ var hasRequiredScheduler_development;
|
|
|
30878
30962
|
function requireScheduler_development () {
|
|
30879
30963
|
if (hasRequiredScheduler_development) return scheduler_development;
|
|
30880
30964
|
hasRequiredScheduler_development = 1;
|
|
30881
|
-
(function (exports) {
|
|
30965
|
+
(function (exports$1) {
|
|
30882
30966
|
"production" !== process.env.NODE_ENV &&
|
|
30883
30967
|
(function () {
|
|
30884
30968
|
function performWorkUntilDeadline() {
|
|
30885
30969
|
needsPaint = false;
|
|
30886
30970
|
if (isMessageLoopRunning) {
|
|
30887
|
-
var currentTime = exports.unstable_now();
|
|
30971
|
+
var currentTime = exports$1.unstable_now();
|
|
30888
30972
|
startTime = currentTime;
|
|
30889
30973
|
var hasMoreWork = true;
|
|
30890
30974
|
try {
|
|
@@ -30915,7 +30999,7 @@ function requireScheduler_development () {
|
|
|
30915
30999
|
var continuationCallback = callback(
|
|
30916
31000
|
currentTask.expirationTime <= currentTime
|
|
30917
31001
|
);
|
|
30918
|
-
currentTime = exports.unstable_now();
|
|
31002
|
+
currentTime = exports$1.unstable_now();
|
|
30919
31003
|
if ("function" === typeof continuationCallback) {
|
|
30920
31004
|
currentTask.callback = continuationCallback;
|
|
30921
31005
|
advanceTimers(currentTime);
|
|
@@ -31036,32 +31120,32 @@ function requireScheduler_development () {
|
|
|
31036
31120
|
function shouldYieldToHost() {
|
|
31037
31121
|
return needsPaint
|
|
31038
31122
|
? true
|
|
31039
|
-
: exports.unstable_now() - startTime < frameInterval
|
|
31123
|
+
: exports$1.unstable_now() - startTime < frameInterval
|
|
31040
31124
|
? false
|
|
31041
31125
|
: true;
|
|
31042
31126
|
}
|
|
31043
31127
|
function requestHostTimeout(callback, ms) {
|
|
31044
31128
|
taskTimeoutID = localSetTimeout(function () {
|
|
31045
|
-
callback(exports.unstable_now());
|
|
31129
|
+
callback(exports$1.unstable_now());
|
|
31046
31130
|
}, ms);
|
|
31047
31131
|
}
|
|
31048
31132
|
"undefined" !== typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ &&
|
|
31049
31133
|
"function" ===
|
|
31050
31134
|
typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart &&
|
|
31051
31135
|
__REACT_DEVTOOLS_GLOBAL_HOOK__.registerInternalModuleStart(Error());
|
|
31052
|
-
exports.unstable_now = void 0;
|
|
31136
|
+
exports$1.unstable_now = void 0;
|
|
31053
31137
|
if (
|
|
31054
31138
|
"object" === typeof performance &&
|
|
31055
31139
|
"function" === typeof performance.now
|
|
31056
31140
|
) {
|
|
31057
31141
|
var localPerformance = performance;
|
|
31058
|
-
exports.unstable_now = function () {
|
|
31142
|
+
exports$1.unstable_now = function () {
|
|
31059
31143
|
return localPerformance.now();
|
|
31060
31144
|
};
|
|
31061
31145
|
} else {
|
|
31062
31146
|
var localDate = Date,
|
|
31063
31147
|
initialTime = localDate.now();
|
|
31064
|
-
exports.unstable_now = function () {
|
|
31148
|
+
exports$1.unstable_now = function () {
|
|
31065
31149
|
return localDate.now() - initialTime;
|
|
31066
31150
|
};
|
|
31067
31151
|
}
|
|
@@ -31098,26 +31182,26 @@ function requireScheduler_development () {
|
|
|
31098
31182
|
schedulePerformWorkUntilDeadline = function () {
|
|
31099
31183
|
localSetTimeout(performWorkUntilDeadline, 0);
|
|
31100
31184
|
};
|
|
31101
|
-
exports.unstable_IdlePriority = 5;
|
|
31102
|
-
exports.unstable_ImmediatePriority = 1;
|
|
31103
|
-
exports.unstable_LowPriority = 4;
|
|
31104
|
-
exports.unstable_NormalPriority = 3;
|
|
31105
|
-
exports.unstable_Profiling = null;
|
|
31106
|
-
exports.unstable_UserBlockingPriority = 2;
|
|
31107
|
-
exports.unstable_cancelCallback = function (task) {
|
|
31185
|
+
exports$1.unstable_IdlePriority = 5;
|
|
31186
|
+
exports$1.unstable_ImmediatePriority = 1;
|
|
31187
|
+
exports$1.unstable_LowPriority = 4;
|
|
31188
|
+
exports$1.unstable_NormalPriority = 3;
|
|
31189
|
+
exports$1.unstable_Profiling = null;
|
|
31190
|
+
exports$1.unstable_UserBlockingPriority = 2;
|
|
31191
|
+
exports$1.unstable_cancelCallback = function (task) {
|
|
31108
31192
|
task.callback = null;
|
|
31109
31193
|
};
|
|
31110
|
-
exports.unstable_forceFrameRate = function (fps) {
|
|
31194
|
+
exports$1.unstable_forceFrameRate = function (fps) {
|
|
31111
31195
|
0 > fps || 125 < fps
|
|
31112
31196
|
? console.error(
|
|
31113
31197
|
"forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"
|
|
31114
31198
|
)
|
|
31115
31199
|
: (frameInterval = 0 < fps ? Math.floor(1e3 / fps) : 5);
|
|
31116
31200
|
};
|
|
31117
|
-
exports.unstable_getCurrentPriorityLevel = function () {
|
|
31201
|
+
exports$1.unstable_getCurrentPriorityLevel = function () {
|
|
31118
31202
|
return currentPriorityLevel;
|
|
31119
31203
|
};
|
|
31120
|
-
exports.unstable_next = function (eventHandler) {
|
|
31204
|
+
exports$1.unstable_next = function (eventHandler) {
|
|
31121
31205
|
switch (currentPriorityLevel) {
|
|
31122
31206
|
case 1:
|
|
31123
31207
|
case 2:
|
|
@@ -31135,10 +31219,10 @@ function requireScheduler_development () {
|
|
|
31135
31219
|
currentPriorityLevel = previousPriorityLevel;
|
|
31136
31220
|
}
|
|
31137
31221
|
};
|
|
31138
|
-
exports.unstable_requestPaint = function () {
|
|
31222
|
+
exports$1.unstable_requestPaint = function () {
|
|
31139
31223
|
needsPaint = true;
|
|
31140
31224
|
};
|
|
31141
|
-
exports.unstable_runWithPriority = function (priorityLevel, eventHandler) {
|
|
31225
|
+
exports$1.unstable_runWithPriority = function (priorityLevel, eventHandler) {
|
|
31142
31226
|
switch (priorityLevel) {
|
|
31143
31227
|
case 1:
|
|
31144
31228
|
case 2:
|
|
@@ -31157,12 +31241,12 @@ function requireScheduler_development () {
|
|
|
31157
31241
|
currentPriorityLevel = previousPriorityLevel;
|
|
31158
31242
|
}
|
|
31159
31243
|
};
|
|
31160
|
-
exports.unstable_scheduleCallback = function (
|
|
31244
|
+
exports$1.unstable_scheduleCallback = function (
|
|
31161
31245
|
priorityLevel,
|
|
31162
31246
|
callback,
|
|
31163
31247
|
options
|
|
31164
31248
|
) {
|
|
31165
|
-
var currentTime = exports.unstable_now();
|
|
31249
|
+
var currentTime = exports$1.unstable_now();
|
|
31166
31250
|
"object" === typeof options && null !== options
|
|
31167
31251
|
? ((options = options.delay),
|
|
31168
31252
|
(options =
|
|
@@ -31214,8 +31298,8 @@ function requireScheduler_development () {
|
|
|
31214
31298
|
schedulePerformWorkUntilDeadline())));
|
|
31215
31299
|
return priorityLevel;
|
|
31216
31300
|
};
|
|
31217
|
-
exports.unstable_shouldYield = shouldYieldToHost;
|
|
31218
|
-
exports.unstable_wrapCallback = function (callback) {
|
|
31301
|
+
exports$1.unstable_shouldYield = shouldYieldToHost;
|
|
31302
|
+
exports$1.unstable_wrapCallback = function (callback) {
|
|
31219
31303
|
var parentPriorityLevel = currentPriorityLevel;
|
|
31220
31304
|
return function () {
|
|
31221
31305
|
var previousPriorityLevel = currentPriorityLevel;
|
|
@@ -35476,8 +35560,8 @@ return CRC32;
|
|
|
35476
35560
|
})();
|
|
35477
35561
|
/* [MS-CFB] v20171201 */
|
|
35478
35562
|
var CFB = /*#__PURE__*/(function _CFB(){
|
|
35479
|
-
var exports = {};
|
|
35480
|
-
exports.version = '1.2.1';
|
|
35563
|
+
var exports$1 = {};
|
|
35564
|
+
exports$1.version = '1.2.1';
|
|
35481
35565
|
/* [MS-CFB] 2.6.4 */
|
|
35482
35566
|
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
|
|
35483
35567
|
var L = l.split("/"), R = r.split("/");
|
|
@@ -37149,12 +37233,12 @@ function cfb_mov(cfb/*:CFBContainer*/, old_name/*:string*/, new_name/*:string*/)
|
|
|
37149
37233
|
|
|
37150
37234
|
function cfb_gc(cfb/*:CFBContainer*/)/*:void*/ { rebuild_cfb(cfb, true); }
|
|
37151
37235
|
|
|
37152
|
-
exports.find = find;
|
|
37153
|
-
exports.read = read;
|
|
37154
|
-
exports.parse = parse;
|
|
37155
|
-
exports.write = write;
|
|
37156
|
-
exports.writeFile = write_file;
|
|
37157
|
-
exports.utils = {
|
|
37236
|
+
exports$1.find = find;
|
|
37237
|
+
exports$1.read = read;
|
|
37238
|
+
exports$1.parse = parse;
|
|
37239
|
+
exports$1.write = write;
|
|
37240
|
+
exports$1.writeFile = write_file;
|
|
37241
|
+
exports$1.utils = {
|
|
37158
37242
|
cfb_new: cfb_new,
|
|
37159
37243
|
cfb_add: cfb_add,
|
|
37160
37244
|
cfb_del: cfb_del,
|
|
@@ -37170,7 +37254,7 @@ exports.utils = {
|
|
|
37170
37254
|
consts: consts
|
|
37171
37255
|
};
|
|
37172
37256
|
|
|
37173
|
-
return exports;
|
|
37257
|
+
return exports$1;
|
|
37174
37258
|
})();
|
|
37175
37259
|
|
|
37176
37260
|
/* normalize data for blob ctor */
|
|
@@ -58633,6 +58717,137 @@ function CurrencyDisplay({ amount, currency = 'USD', locale = 'en-US', className
|
|
|
58633
58717
|
return (jsxRuntime.jsx("span", { className: combinedClasses, title: `${currency} ${safeAmount.toFixed(precision)}`, children: displayValue }));
|
|
58634
58718
|
}
|
|
58635
58719
|
|
|
58720
|
+
/**
|
|
58721
|
+
* CurrencyInput - Specialized input for monetary values
|
|
58722
|
+
*
|
|
58723
|
+
* Automatically formats currency values with proper symbols and thousands separators.
|
|
58724
|
+
* Handles parsing and validation of numeric currency input.
|
|
58725
|
+
*
|
|
58726
|
+
* @example Basic usage
|
|
58727
|
+
* ```tsx
|
|
58728
|
+
* <CurrencyInput
|
|
58729
|
+
* label="Price"
|
|
58730
|
+
* value={price}
|
|
58731
|
+
* onChange={setPrice}
|
|
58732
|
+
* currency="USD"
|
|
58733
|
+
* />
|
|
58734
|
+
* ```
|
|
58735
|
+
*
|
|
58736
|
+
* @example With validation
|
|
58737
|
+
* ```tsx
|
|
58738
|
+
* <CurrencyInput
|
|
58739
|
+
* label="Budget"
|
|
58740
|
+
* value={budget}
|
|
58741
|
+
* onChange={setBudget}
|
|
58742
|
+
* min={0}
|
|
58743
|
+
* max={10000}
|
|
58744
|
+
* validationState={budget > 10000 ? 'error' : null}
|
|
58745
|
+
* validationMessage={budget > 10000 ? 'Exceeds maximum budget' : ''}
|
|
58746
|
+
* />
|
|
58747
|
+
* ```
|
|
58748
|
+
*/
|
|
58749
|
+
const CurrencyInput = React.forwardRef(({ value, onChange, currency = 'USD', locale = 'en-US', precision = 2, allowNegative = false, min, max, onBlur, onFocus, ...props }, ref) => {
|
|
58750
|
+
const [displayValue, setDisplayValue] = React.useState('');
|
|
58751
|
+
const [isFocused, setIsFocused] = React.useState(false);
|
|
58752
|
+
// Get currency symbol
|
|
58753
|
+
const getCurrencySymbol = () => {
|
|
58754
|
+
const formatter = new Intl.NumberFormat(locale, {
|
|
58755
|
+
style: 'currency',
|
|
58756
|
+
currency,
|
|
58757
|
+
});
|
|
58758
|
+
const parts = formatter.formatToParts(0);
|
|
58759
|
+
const symbolPart = parts.find(part => part.type === 'currency');
|
|
58760
|
+
return symbolPart?.value || '$';
|
|
58761
|
+
};
|
|
58762
|
+
const currencySymbol = getCurrencySymbol();
|
|
58763
|
+
// Format number as currency
|
|
58764
|
+
const formatCurrency = (num) => {
|
|
58765
|
+
const formatter = new Intl.NumberFormat(locale, {
|
|
58766
|
+
minimumFractionDigits: isFocused ? 0 : precision,
|
|
58767
|
+
maximumFractionDigits: precision,
|
|
58768
|
+
});
|
|
58769
|
+
return formatter.format(num);
|
|
58770
|
+
};
|
|
58771
|
+
// Parse display value to number
|
|
58772
|
+
const parseValue = (str) => {
|
|
58773
|
+
if (!str || str === '')
|
|
58774
|
+
return null;
|
|
58775
|
+
// Remove all non-numeric characters except decimal point and minus sign
|
|
58776
|
+
let cleaned = str.replace(/[^\d.-]/g, '');
|
|
58777
|
+
// Handle multiple decimal points
|
|
58778
|
+
const parts = cleaned.split('.');
|
|
58779
|
+
if (parts.length > 2) {
|
|
58780
|
+
cleaned = parts[0] + '.' + parts.slice(1).join('');
|
|
58781
|
+
}
|
|
58782
|
+
// Handle multiple minus signs (keep only first)
|
|
58783
|
+
const minusCount = (cleaned.match(/-/g) || []).length;
|
|
58784
|
+
if (minusCount > 1) {
|
|
58785
|
+
const hasLeadingMinus = cleaned.startsWith('-');
|
|
58786
|
+
cleaned = cleaned.replace(/-/g, '');
|
|
58787
|
+
if (hasLeadingMinus)
|
|
58788
|
+
cleaned = '-' + cleaned;
|
|
58789
|
+
}
|
|
58790
|
+
// Parse to float
|
|
58791
|
+
const num = parseFloat(cleaned);
|
|
58792
|
+
if (isNaN(num))
|
|
58793
|
+
return null;
|
|
58794
|
+
// Apply precision
|
|
58795
|
+
return Math.round(num * Math.pow(10, precision)) / Math.pow(10, precision);
|
|
58796
|
+
};
|
|
58797
|
+
// Update display value when external value changes
|
|
58798
|
+
React.useEffect(() => {
|
|
58799
|
+
if (value === undefined || value === null || value === '') {
|
|
58800
|
+
setDisplayValue('');
|
|
58801
|
+
}
|
|
58802
|
+
else {
|
|
58803
|
+
const numValue = typeof value === 'string' ? parseFloat(value) : value;
|
|
58804
|
+
if (!isNaN(numValue)) {
|
|
58805
|
+
setDisplayValue(formatCurrency(numValue));
|
|
58806
|
+
}
|
|
58807
|
+
}
|
|
58808
|
+
}, [value, isFocused]);
|
|
58809
|
+
const handleChange = (e) => {
|
|
58810
|
+
const inputValue = e.target.value;
|
|
58811
|
+
setDisplayValue(inputValue);
|
|
58812
|
+
const numValue = parseValue(inputValue);
|
|
58813
|
+
// Validate constraints
|
|
58814
|
+
if (numValue !== null) {
|
|
58815
|
+
if (!allowNegative && numValue < 0)
|
|
58816
|
+
return;
|
|
58817
|
+
if (min !== undefined && numValue < min)
|
|
58818
|
+
return;
|
|
58819
|
+
if (max !== undefined && numValue > max)
|
|
58820
|
+
return;
|
|
58821
|
+
}
|
|
58822
|
+
onChange?.(numValue);
|
|
58823
|
+
};
|
|
58824
|
+
const handleFocus = (e) => {
|
|
58825
|
+
setIsFocused(true);
|
|
58826
|
+
// Remove formatting when focused for easier editing
|
|
58827
|
+
if (value !== undefined && value !== null && value !== '') {
|
|
58828
|
+
const numValue = typeof value === 'string' ? parseFloat(value) : value;
|
|
58829
|
+
if (!isNaN(numValue)) {
|
|
58830
|
+
setDisplayValue(numValue.toString());
|
|
58831
|
+
}
|
|
58832
|
+
}
|
|
58833
|
+
onFocus?.(e);
|
|
58834
|
+
};
|
|
58835
|
+
const handleBlur = (e) => {
|
|
58836
|
+
setIsFocused(false);
|
|
58837
|
+
// Reformat on blur
|
|
58838
|
+
const numValue = parseValue(displayValue);
|
|
58839
|
+
if (numValue !== null) {
|
|
58840
|
+
setDisplayValue(formatCurrency(numValue));
|
|
58841
|
+
}
|
|
58842
|
+
else if (displayValue === '') {
|
|
58843
|
+
setDisplayValue('');
|
|
58844
|
+
}
|
|
58845
|
+
onBlur?.(e);
|
|
58846
|
+
};
|
|
58847
|
+
return (jsxRuntime.jsx(Input, { ref: ref, type: "text", value: displayValue, onChange: handleChange, onFocus: handleFocus, onBlur: handleBlur, prefix: currencySymbol, ...props }));
|
|
58848
|
+
});
|
|
58849
|
+
CurrencyInput.displayName = 'CurrencyInput';
|
|
58850
|
+
|
|
58636
58851
|
const formatOptions = {
|
|
58637
58852
|
short: {
|
|
58638
58853
|
year: 'numeric',
|
|
@@ -59543,8 +59758,19 @@ const AppLayout = ({ children, toolbarSections = [], className = '', showToolbar
|
|
|
59543
59758
|
* </Layout>
|
|
59544
59759
|
* ```
|
|
59545
59760
|
*/
|
|
59546
|
-
function PageLayout({ title, description, children, className = '', headerContent }) {
|
|
59547
|
-
|
|
59761
|
+
function PageLayout({ title, description, children, className = '', headerContent, maxWidth = '7xl', fixed = false }) {
|
|
59762
|
+
// Responsive padding classes - fixed left/top, responsive right/bottom
|
|
59763
|
+
const paddingClasses = fixed
|
|
59764
|
+
? 'p-6 pb-20'
|
|
59765
|
+
: 'pt-6 pl-6 pr-2 pb-8 sm:pr-4 md:pr-6 sm:pb-12 md:pb-16 lg:pb-20';
|
|
59766
|
+
const maxWidthClasses = {
|
|
59767
|
+
'4xl': 'max-w-4xl',
|
|
59768
|
+
'5xl': 'max-w-5xl',
|
|
59769
|
+
'6xl': 'max-w-6xl',
|
|
59770
|
+
'7xl': 'max-w-7xl',
|
|
59771
|
+
'full': 'max-w-full',
|
|
59772
|
+
};
|
|
59773
|
+
return (jsxRuntime.jsxs(Page, { padding: "none", maxWidth: maxWidth, fixed: fixed, children: [headerContent, jsxRuntime.jsxs("div", { className: `${paddingClasses} ${maxWidthClasses[maxWidth]} mx-auto ${className}`, children: [jsxRuntime.jsxs("div", { className: "mb-8", children: [jsxRuntime.jsx("h1", { className: "text-3xl font-bold text-ink-900 mb-2", children: title }), description && (jsxRuntime.jsx("p", { className: "text-ink-600", children: description }))] }), children] })] }));
|
|
59548
59774
|
}
|
|
59549
59775
|
|
|
59550
59776
|
const sizeClasses = {
|
|
@@ -59916,6 +60142,113 @@ function loadColumnOrder(tableId) {
|
|
|
59916
60142
|
}
|
|
59917
60143
|
}
|
|
59918
60144
|
|
|
60145
|
+
/**
|
|
60146
|
+
* Export data to Excel file
|
|
60147
|
+
*
|
|
60148
|
+
* A standalone utility for exporting any data array to Excel format.
|
|
60149
|
+
* Works independently of the Spreadsheet component.
|
|
60150
|
+
*
|
|
60151
|
+
* **Features:**
|
|
60152
|
+
* - Export arrays of objects to Excel
|
|
60153
|
+
* - Custom column headers and ordering
|
|
60154
|
+
* - Value formatting with custom functions
|
|
60155
|
+
* - Multi-sheet support
|
|
60156
|
+
* - Automatic type handling
|
|
60157
|
+
*
|
|
60158
|
+
* @example
|
|
60159
|
+
* ```typescript
|
|
60160
|
+
* // Simple export - uses object keys as headers
|
|
60161
|
+
* const data = [
|
|
60162
|
+
* { id: 1, name: 'Product A', price: 29.99 },
|
|
60163
|
+
* { id: 2, name: 'Product B', price: 49.99 },
|
|
60164
|
+
* ];
|
|
60165
|
+
* exportToExcel({ data, filename: 'products.xlsx' });
|
|
60166
|
+
*
|
|
60167
|
+
* // Custom columns with formatting
|
|
60168
|
+
* exportToExcel({
|
|
60169
|
+
* data: users,
|
|
60170
|
+
* filename: 'users.xlsx',
|
|
60171
|
+
* columns: [
|
|
60172
|
+
* { key: 'id', label: 'ID' },
|
|
60173
|
+
* { key: 'name', label: 'Full Name' },
|
|
60174
|
+
* { key: 'email', label: 'Email Address' },
|
|
60175
|
+
* { key: 'createdAt', label: 'Joined', format: (date) => new Date(date).toLocaleDateString() },
|
|
60176
|
+
* { key: 'isActive', label: 'Status', format: (active) => active ? 'Active' : 'Inactive' },
|
|
60177
|
+
* ],
|
|
60178
|
+
* });
|
|
60179
|
+
*
|
|
60180
|
+
* // Multi-sheet export
|
|
60181
|
+
* const wb = utils.book_new();
|
|
60182
|
+
* exportToExcel({ data: products, sheetName: 'Products', workbook: wb });
|
|
60183
|
+
* exportToExcel({ data: orders, sheetName: 'Orders', workbook: wb });
|
|
60184
|
+
* writeFile(wb, 'multi-sheet.xlsx');
|
|
60185
|
+
* ```
|
|
60186
|
+
*
|
|
60187
|
+
* @param options - Export configuration options
|
|
60188
|
+
* @returns WorkBook if workbook option provided, otherwise void (auto-downloads)
|
|
60189
|
+
*/
|
|
60190
|
+
function exportToExcel({ data, filename = 'export.xlsx', sheetName = 'Sheet1', columns, includeHeaders = true, workbook, }) {
|
|
60191
|
+
if (!data || data.length === 0) {
|
|
60192
|
+
throw new Error('No data provided for export');
|
|
60193
|
+
}
|
|
60194
|
+
let worksheetData;
|
|
60195
|
+
if (columns) {
|
|
60196
|
+
// Use custom columns with specific ordering and formatting
|
|
60197
|
+
const headers = columns.map((col) => col.label);
|
|
60198
|
+
const rows = data.map((row) => columns.map((col) => {
|
|
60199
|
+
const value = row[col.key];
|
|
60200
|
+
return col.format ? col.format(value) : value ?? '';
|
|
60201
|
+
}));
|
|
60202
|
+
worksheetData = includeHeaders ? [headers, ...rows] : rows;
|
|
60203
|
+
}
|
|
60204
|
+
else {
|
|
60205
|
+
// Auto-generate from object keys
|
|
60206
|
+
if (includeHeaders) {
|
|
60207
|
+
const headers = Object.keys(data[0]);
|
|
60208
|
+
const rows = data.map((row) => headers.map((key) => row[key] ?? ''));
|
|
60209
|
+
worksheetData = [headers, ...rows];
|
|
60210
|
+
}
|
|
60211
|
+
else {
|
|
60212
|
+
const headers = Object.keys(data[0]);
|
|
60213
|
+
worksheetData = data.map((row) => headers.map((key) => row[key] ?? ''));
|
|
60214
|
+
}
|
|
60215
|
+
}
|
|
60216
|
+
const worksheet = utils.aoa_to_sheet(worksheetData);
|
|
60217
|
+
// If workbook provided, add sheet and return (for multi-sheet exports)
|
|
60218
|
+
if (workbook) {
|
|
60219
|
+
utils.book_append_sheet(workbook, worksheet, sheetName);
|
|
60220
|
+
return workbook;
|
|
60221
|
+
}
|
|
60222
|
+
// Otherwise, create workbook and download
|
|
60223
|
+
const newWorkbook = utils.book_new();
|
|
60224
|
+
utils.book_append_sheet(newWorkbook, worksheet, sheetName);
|
|
60225
|
+
writeFileSync(newWorkbook, filename);
|
|
60226
|
+
}
|
|
60227
|
+
function exportDataTableToExcel({ data, columns, filename = 'export.xlsx', sheetName = 'Sheet1', }) {
|
|
60228
|
+
const excelColumns = columns.map((col) => ({
|
|
60229
|
+
key: col.key,
|
|
60230
|
+
label: col.header,
|
|
60231
|
+
}));
|
|
60232
|
+
exportToExcel({
|
|
60233
|
+
data,
|
|
60234
|
+
columns: excelColumns,
|
|
60235
|
+
filename,
|
|
60236
|
+
sheetName,
|
|
60237
|
+
});
|
|
60238
|
+
}
|
|
60239
|
+
function createMultiSheetExcel({ filename, sheets }) {
|
|
60240
|
+
const workbook = utils.book_new();
|
|
60241
|
+
sheets.forEach((sheet) => {
|
|
60242
|
+
exportToExcel({
|
|
60243
|
+
data: sheet.data,
|
|
60244
|
+
sheetName: sheet.name,
|
|
60245
|
+
columns: sheet.columns,
|
|
60246
|
+
workbook,
|
|
60247
|
+
});
|
|
60248
|
+
});
|
|
60249
|
+
writeFileSync(workbook, filename);
|
|
60250
|
+
}
|
|
60251
|
+
|
|
59919
60252
|
function useColumnResize(options = {}) {
|
|
59920
60253
|
const { tableId, persist = false } = options;
|
|
59921
60254
|
const [columnWidths, setColumnWidths] = React.useState({});
|
|
@@ -60066,6 +60399,7 @@ exports.ConfirmDialog = ConfirmDialog;
|
|
|
60066
60399
|
exports.ContextMenu = ContextMenu;
|
|
60067
60400
|
exports.ControlBar = ControlBar;
|
|
60068
60401
|
exports.CurrencyDisplay = CurrencyDisplay;
|
|
60402
|
+
exports.CurrencyInput = CurrencyInput;
|
|
60069
60403
|
exports.Dashboard = Dashboard;
|
|
60070
60404
|
exports.DashboardContent = DashboardContent;
|
|
60071
60405
|
exports.DashboardHeader = DashboardHeader;
|
|
@@ -60148,7 +60482,6 @@ exports.StatusBar = StatusBar;
|
|
|
60148
60482
|
exports.StepIndicator = StepIndicator;
|
|
60149
60483
|
exports.Stepper = Stepper;
|
|
60150
60484
|
exports.Switch = Switch;
|
|
60151
|
-
exports.Table = Table$1;
|
|
60152
60485
|
exports.Tabs = Tabs;
|
|
60153
60486
|
exports.Text = Text;
|
|
60154
60487
|
exports.Textarea = Textarea;
|
|
@@ -60169,8 +60502,11 @@ exports.addWarningMessage = addWarningMessage;
|
|
|
60169
60502
|
exports.calculateColumnWidth = calculateColumnWidth;
|
|
60170
60503
|
exports.createActionsSection = createActionsSection;
|
|
60171
60504
|
exports.createFiltersSection = createFiltersSection;
|
|
60505
|
+
exports.createMultiSheetExcel = createMultiSheetExcel;
|
|
60172
60506
|
exports.createPageControlsSection = createPageControlsSection;
|
|
60173
60507
|
exports.createQueryDetailsSection = createQueryDetailsSection;
|
|
60508
|
+
exports.exportDataTableToExcel = exportDataTableToExcel;
|
|
60509
|
+
exports.exportToExcel = exportToExcel;
|
|
60174
60510
|
exports.formatStatisticValue = formatStatisticValue;
|
|
60175
60511
|
exports.formatStatistics = formatStatistics;
|
|
60176
60512
|
exports.loadColumnOrder = loadColumnOrder;
|