@papernote/ui 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/DataTable.d.ts +17 -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/MultiSelect.d.ts +13 -1
- package/dist/components/MultiSelect.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 +1 -3
- package/dist/components/index.d.ts.map +1 -1
- package/dist/index.d.ts +110 -48
- package/dist/index.esm.js +144 -138
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +143 -138
- package/dist/index.js.map +1 -1
- package/dist/styles.css +8 -51
- package/package.json +1 -1
- 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/DataTable.stories.tsx +36 -25
- package/src/components/DataTable.tsx +95 -5
- 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/MultiSelect.tsx +41 -10
- package/src/components/Stack.stories.tsx +24 -1
- package/src/components/Stack.tsx +40 -10
- 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 +1 -4
- package/dist/components/Table.d.ts +0 -26
- package/dist/components/Table.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: {
|
|
@@ -6088,99 +6157,6 @@ function StepIndicator({ steps, currentStep, variant = 'horizontal', onStepClick
|
|
|
6088
6157
|
}) }) }));
|
|
6089
6158
|
}
|
|
6090
6159
|
|
|
6091
|
-
function Table$1({ data, columns, keyExtractor, selectable = false, expandable = false, onRowSelect, renderExpandedRow, emptyState, className = '', onSort, sortColumn: externalSortColumn, sortDirection: externalSortDirection, }) {
|
|
6092
|
-
const [internalSortColumn, setInternalSortColumn] = React.useState(null);
|
|
6093
|
-
const [internalSortDirection, setInternalSortDirection] = React.useState(null);
|
|
6094
|
-
// Use external sort state if provided, otherwise use internal state
|
|
6095
|
-
const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
|
|
6096
|
-
const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
|
|
6097
|
-
const [selectedRows, setSelectedRows] = React.useState(new Set());
|
|
6098
|
-
const [expandedRows, setExpandedRows] = React.useState(new Set());
|
|
6099
|
-
// Handle sorting
|
|
6100
|
-
const handleSort = (columnKey) => {
|
|
6101
|
-
let newDirection;
|
|
6102
|
-
if (sortColumn === columnKey) {
|
|
6103
|
-
if (sortDirection === 'asc') {
|
|
6104
|
-
newDirection = 'desc';
|
|
6105
|
-
}
|
|
6106
|
-
else if (sortDirection === 'desc') {
|
|
6107
|
-
newDirection = null;
|
|
6108
|
-
}
|
|
6109
|
-
else {
|
|
6110
|
-
newDirection = 'asc';
|
|
6111
|
-
}
|
|
6112
|
-
}
|
|
6113
|
-
else {
|
|
6114
|
-
newDirection = 'asc';
|
|
6115
|
-
}
|
|
6116
|
-
// If using external sort control, call the callback
|
|
6117
|
-
if (onSort) {
|
|
6118
|
-
onSort(columnKey, newDirection);
|
|
6119
|
-
}
|
|
6120
|
-
else {
|
|
6121
|
-
// Otherwise update internal state
|
|
6122
|
-
setInternalSortColumn(newDirection === null ? null : columnKey);
|
|
6123
|
-
setInternalSortDirection(newDirection);
|
|
6124
|
-
}
|
|
6125
|
-
};
|
|
6126
|
-
// Handle row selection
|
|
6127
|
-
const handleRowSelect = (rowKey) => {
|
|
6128
|
-
const newSelected = new Set(selectedRows);
|
|
6129
|
-
if (newSelected.has(rowKey)) {
|
|
6130
|
-
newSelected.delete(rowKey);
|
|
6131
|
-
}
|
|
6132
|
-
else {
|
|
6133
|
-
newSelected.add(rowKey);
|
|
6134
|
-
}
|
|
6135
|
-
setSelectedRows(newSelected);
|
|
6136
|
-
onRowSelect?.(Array.from(newSelected));
|
|
6137
|
-
};
|
|
6138
|
-
// Handle select all
|
|
6139
|
-
const handleSelectAll = () => {
|
|
6140
|
-
if (selectedRows.size === data.length) {
|
|
6141
|
-
setSelectedRows(new Set());
|
|
6142
|
-
onRowSelect?.([]);
|
|
6143
|
-
}
|
|
6144
|
-
else {
|
|
6145
|
-
const allKeys = new Set(data.map(keyExtractor));
|
|
6146
|
-
setSelectedRows(allKeys);
|
|
6147
|
-
onRowSelect?.(Array.from(allKeys));
|
|
6148
|
-
}
|
|
6149
|
-
};
|
|
6150
|
-
// Handle row expansion
|
|
6151
|
-
const handleRowExpand = (rowKey) => {
|
|
6152
|
-
const newExpanded = new Set(expandedRows);
|
|
6153
|
-
if (newExpanded.has(rowKey)) {
|
|
6154
|
-
newExpanded.delete(rowKey);
|
|
6155
|
-
}
|
|
6156
|
-
else {
|
|
6157
|
-
newExpanded.add(rowKey);
|
|
6158
|
-
}
|
|
6159
|
-
setExpandedRows(newExpanded);
|
|
6160
|
-
};
|
|
6161
|
-
const getSortIcon = (columnKey) => {
|
|
6162
|
-
if (sortColumn !== columnKey) {
|
|
6163
|
-
return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
|
|
6164
|
-
}
|
|
6165
|
-
if (sortDirection === 'asc') {
|
|
6166
|
-
return jsxRuntime.jsx(lucideReact.ArrowUp, { className: "h-4 w-4 text-accent-600" });
|
|
6167
|
-
}
|
|
6168
|
-
if (sortDirection === 'desc') {
|
|
6169
|
-
return jsxRuntime.jsx(lucideReact.ArrowDown, { className: "h-4 w-4 text-accent-600" });
|
|
6170
|
-
}
|
|
6171
|
-
return jsxRuntime.jsx(lucideReact.ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
|
|
6172
|
-
};
|
|
6173
|
-
if (data.length === 0 && emptyState) {
|
|
6174
|
-
return jsxRuntime.jsx("div", { children: emptyState });
|
|
6175
|
-
}
|
|
6176
|
-
return (jsxRuntime.jsx("div", { className: `overflow-x-auto ${className}`, children: jsxRuntime.jsxs("table", { className: "table", children: [jsxRuntime.jsx("thead", { className: "table-header", children: jsxRuntime.jsxs("tr", { children: [selectable && (jsxRuntime.jsx("th", { className: "table-header-cell w-12", children: jsxRuntime.jsx("input", { type: "checkbox", checked: selectedRows.size === data.length && data.length > 0, onChange: handleSelectAll, className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": "Select all rows" }) })), expandable && jsxRuntime.jsx("th", { className: "table-header-cell w-12" }), columns.map((column) => (jsxRuntime.jsx("th", { className: "table-header-cell", style: { width: column.width }, children: column.sortable ? (jsxRuntime.jsxs("button", { onClick: () => handleSort(column.key), className: "group inline-flex items-center gap-2 hover:text-ink-900 transition-colors", children: [jsxRuntime.jsx("span", { children: column.header }), getSortIcon(column.key)] })) : (column.header) }, column.key)))] }) }), jsxRuntime.jsx("tbody", { children: data.map((row) => {
|
|
6177
|
-
const rowKey = keyExtractor(row);
|
|
6178
|
-
const isSelected = selectedRows.has(rowKey);
|
|
6179
|
-
const isExpanded = expandedRows.has(rowKey);
|
|
6180
|
-
return (jsxRuntime.jsxs(React.Fragment, { children: [jsxRuntime.jsxs("tr", { className: `table-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : ''}`, children: [selectable && (jsxRuntime.jsx("td", { className: "table-cell", children: jsxRuntime.jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleRowSelect(rowKey), className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": `Select row ${rowKey}` }) })), expandable && (jsxRuntime.jsx("td", { className: "table-cell", children: jsxRuntime.jsx("button", { onClick: () => handleRowExpand(rowKey), className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded ? 'Collapse row' : 'Expand row', children: isExpanded ? (jsxRuntime.jsx(lucideReact.ChevronDown, { className: "h-4 w-4" })) : (jsxRuntime.jsx(lucideReact.ChevronRight, { className: "h-4 w-4" })) }) })), columns.map((column) => (jsxRuntime.jsx("td", { className: "table-cell", children: column.accessor ? column.accessor(row) : row[column.key] }, column.key)))] }), expandable && isExpanded && renderExpandedRow && (jsxRuntime.jsx("tr", { children: jsxRuntime.jsx("td", { colSpan: columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0), className: "px-6 py-4 bg-paper-50", children: renderExpandedRow(row) }) }))] }, rowKey));
|
|
6181
|
-
}) })] }) }));
|
|
6182
|
-
}
|
|
6183
|
-
|
|
6184
6160
|
function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, }) {
|
|
6185
6161
|
const variantStyles = {
|
|
6186
6162
|
success: 'bg-success-50 text-success-700 border-success-200',
|
|
@@ -6288,8 +6264,8 @@ const Avatar = ({ firstName, lastName, fallbackText = 'U', imageUrl, size = 'md'
|
|
|
6288
6264
|
`, style: { textShadow: '0 1px 2px rgba(0,0,0,0.3)' }, children: getInitials() }) }));
|
|
6289
6265
|
};
|
|
6290
6266
|
|
|
6291
|
-
function EmptyState({ icon, title, description, action, secondaryAction, }) {
|
|
6292
|
-
return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsxRuntime.jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsxRuntime.jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsxRuntime.jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), (action || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [action && (jsxRuntime.jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsxRuntime.jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
|
|
6267
|
+
function EmptyState({ icon, title, description, action, secondaryAction, children, }) {
|
|
6268
|
+
return (jsxRuntime.jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsxRuntime.jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsxRuntime.jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsxRuntime.jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), children && (jsxRuntime.jsx("div", { className: "mb-8 w-full max-w-md", children: children })), (action || secondaryAction) && (jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [action && (jsxRuntime.jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsxRuntime.jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
|
|
6293
6269
|
}
|
|
6294
6270
|
|
|
6295
6271
|
/**
|
|
@@ -7305,7 +7281,9 @@ function getColumnStyle(column, dynamicWidth) {
|
|
|
7305
7281
|
*/
|
|
7306
7282
|
function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], enableContextMenu = true, onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
|
|
7307
7283
|
// Visual customization props
|
|
7308
|
-
striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
|
|
7284
|
+
striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
|
|
7285
|
+
// Pagination props
|
|
7286
|
+
paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true, }) {
|
|
7309
7287
|
// Column resizing state
|
|
7310
7288
|
const [columnWidths, setColumnWidths] = React.useState({});
|
|
7311
7289
|
const [resizingColumn, setResizingColumn] = React.useState(null);
|
|
@@ -7538,16 +7516,30 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7538
7516
|
}
|
|
7539
7517
|
});
|
|
7540
7518
|
}
|
|
7519
|
+
// Combine all actions: built-in first, then custom actions, then delete last
|
|
7520
|
+
// Delete is stored separately to ensure it's always last
|
|
7521
|
+
let deleteAction = null;
|
|
7541
7522
|
if (onDelete) {
|
|
7542
|
-
|
|
7523
|
+
deleteAction = {
|
|
7543
7524
|
label: 'Delete',
|
|
7544
7525
|
icon: lucideReact.Trash,
|
|
7545
7526
|
onClick: onDelete,
|
|
7546
7527
|
variant: 'danger',
|
|
7547
7528
|
tooltip: 'Delete item'
|
|
7548
|
-
}
|
|
7529
|
+
};
|
|
7549
7530
|
}
|
|
7550
|
-
|
|
7531
|
+
// Build final actions array with consistent ordering:
|
|
7532
|
+
// 1. Edit (first - most common action)
|
|
7533
|
+
// 2. View Details
|
|
7534
|
+
// 3. Add Related actions
|
|
7535
|
+
// 4. Manage Related actions
|
|
7536
|
+
// 5. Custom actions (from actions prop)
|
|
7537
|
+
// 6. Delete (always last - destructive action)
|
|
7538
|
+
const allActions = [
|
|
7539
|
+
...builtInActions,
|
|
7540
|
+
...actions,
|
|
7541
|
+
...(deleteAction ? [deleteAction] : [])
|
|
7542
|
+
];
|
|
7551
7543
|
// Convert actions to menu items for context menu
|
|
7552
7544
|
const convertActionsToMenuItems = (item) => {
|
|
7553
7545
|
const visibleActions = allActions.filter(action => !action.show || action.show(item));
|
|
@@ -7896,8 +7888,22 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7896
7888
|
})] }) }), jsxRuntime.jsx("tbody", { className: "bg-white table-loading transition-opacity duration-200", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
|
|
7897
7889
|
// Wrap in scrollable container if virtualized
|
|
7898
7890
|
const finalContent = virtualized ? (jsxRuntime.jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent })) : tableContent;
|
|
7891
|
+
// Calculate pagination values
|
|
7892
|
+
const effectiveTotalItems = totalItems ?? data.length;
|
|
7893
|
+
const totalPages = Math.ceil(effectiveTotalItems / pageSize);
|
|
7894
|
+
// Page size selector options
|
|
7895
|
+
const pageSizeSelectOptions = pageSizeOptions.map(size => ({
|
|
7896
|
+
value: String(size),
|
|
7897
|
+
label: `${size} per page`,
|
|
7898
|
+
}));
|
|
7899
|
+
// Render pagination controls
|
|
7900
|
+
const renderPaginationControls = () => {
|
|
7901
|
+
if (!paginated)
|
|
7902
|
+
return null;
|
|
7903
|
+
return (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsxRuntime.jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsxRuntime.jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: ["Showing ", ((currentPage - 1) * pageSize) + 1, " - ", Math.min(currentPage * pageSize, effectiveTotalItems), " of ", effectiveTotalItems] })) : ('No items') })] }), totalPages > 1 && onPageChange && (jsxRuntime.jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
|
|
7904
|
+
};
|
|
7899
7905
|
// Render with context menu
|
|
7900
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [finalContent, contextMenuState.isOpen && contextMenuState.item && (jsxRuntime.jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
|
|
7906
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [renderPaginationControls(), finalContent, contextMenuState.isOpen && contextMenuState.item && (jsxRuntime.jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
|
|
7901
7907
|
}
|
|
7902
7908
|
|
|
7903
7909
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
@@ -60476,7 +60482,6 @@ exports.StatusBar = StatusBar;
|
|
|
60476
60482
|
exports.StepIndicator = StepIndicator;
|
|
60477
60483
|
exports.Stepper = Stepper;
|
|
60478
60484
|
exports.Switch = Switch;
|
|
60479
|
-
exports.Table = Table$1;
|
|
60480
60485
|
exports.Tabs = Tabs;
|
|
60481
60486
|
exports.Text = Text;
|
|
60482
60487
|
exports.Textarea = Textarea;
|