@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.esm.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
2
|
-
import { Loader2, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Check, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Info, Trash2, Circle, ChevronsRight, ChevronsLeft, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, Home, ArrowUpDown, ArrowUp, ArrowDown, FileText, Image, File as File$1, User, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Download, Save, XCircle, Filter, BarChart3, MessageSquare } from 'lucide-react';
|
|
3
2
|
import * as React from 'react';
|
|
4
3
|
import React__default, { forwardRef, useState, useRef, useId, useImperativeHandle, useEffect, useCallback, useMemo, cloneElement, isValidElement, Component, createContext as createContext$1, useLayoutEffect, createElement, useContext, useReducer } from 'react';
|
|
4
|
+
import { Loader2, X, EyeOff, Eye, AlertTriangle, CheckCircle, AlertCircle, ChevronDown, Search, Check, Minus, Star, Calendar as Calendar$1, ChevronLeft, ChevronRight, Clock, ChevronUp, Plus, TrendingUp, TrendingDown, Info, Trash2, Circle, ChevronsRight, ChevronsLeft, MoreVertical, GripVertical, Upload, Bold, Italic, Underline, List, ListOrdered, Code, Link, Home, FileText, Image, File as File$1, User, Settings, LogOut, Moon, Sun, Bell, Edit, Trash, Download, Save, XCircle, Filter, BarChart3, MessageSquare } from 'lucide-react';
|
|
5
5
|
import { createPortal } from 'react-dom';
|
|
6
6
|
import { Link as Link$1 } from 'react-router-dom';
|
|
7
7
|
|
|
@@ -11,6 +11,8 @@ import { Link as Link$1 } from 'react-router-dom';
|
|
|
11
11
|
* A versatile button component that supports multiple visual styles, sizes, icons,
|
|
12
12
|
* loading states, and notification badges.
|
|
13
13
|
*
|
|
14
|
+
* Supports ref forwarding for DOM access.
|
|
15
|
+
*
|
|
14
16
|
* @example Basic usage
|
|
15
17
|
* ```tsx
|
|
16
18
|
* <Button variant="primary">Click me</Button>
|
|
@@ -37,8 +39,14 @@ import { Link as Link$1 } from 'react-router-dom';
|
|
|
37
39
|
* <Bell />
|
|
38
40
|
* </Button>
|
|
39
41
|
* ```
|
|
42
|
+
*
|
|
43
|
+
* @example With ref
|
|
44
|
+
* ```tsx
|
|
45
|
+
* const buttonRef = useRef<HTMLButtonElement>(null);
|
|
46
|
+
* <Button ref={buttonRef}>Focusable</Button>
|
|
47
|
+
* ```
|
|
40
48
|
*/
|
|
41
|
-
|
|
49
|
+
const Button = forwardRef(({ variant = 'primary', size = 'md', loading = false, icon, iconPosition = 'left', fullWidth = false, iconOnly = false, badge, badgeVariant = 'error', children, disabled, className = '', ...props }, ref) => {
|
|
42
50
|
const baseStyles = 'inline-flex items-center justify-center font-medium rounded-lg border transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-accent-400 disabled:opacity-40 disabled:cursor-not-allowed';
|
|
43
51
|
const variantStyles = {
|
|
44
52
|
primary: 'bg-accent-500 text-white border-accent-500 hover:bg-accent-600 hover:shadow-sm active:scale-[0.98]',
|
|
@@ -69,7 +77,7 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
|
|
|
69
77
|
md: 'min-w-[18px] h-[18px] text-[11px] px-1.5',
|
|
70
78
|
lg: 'min-w-[20px] h-5 text-xs px-1.5',
|
|
71
79
|
};
|
|
72
|
-
const buttonElement = (jsxs("button", { className: `
|
|
80
|
+
const buttonElement = (jsxs("button", { ref: ref, className: `
|
|
73
81
|
${baseStyles}
|
|
74
82
|
${variantStyles[variant]}
|
|
75
83
|
${sizeStyles[size]}
|
|
@@ -92,7 +100,8 @@ function Button({ variant = 'primary', size = 'md', loading = false, icon, iconP
|
|
|
92
100
|
shadow-sm
|
|
93
101
|
pointer-events-none
|
|
94
102
|
`, "aria-label": `${badgeContent} notifications`, children: badgeContent })] }));
|
|
95
|
-
}
|
|
103
|
+
});
|
|
104
|
+
Button.displayName = 'Button';
|
|
96
105
|
|
|
97
106
|
/**
|
|
98
107
|
* ButtonGroup component - Toggle button group for single or multiple selection.
|
|
@@ -239,7 +248,7 @@ function ButtonGroup({ options, value, values = [], onChange, onChangeMultiple,
|
|
|
239
248
|
* />
|
|
240
249
|
* ```
|
|
241
250
|
*/
|
|
242
|
-
const Input = forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
|
|
251
|
+
const Input = forwardRef(({ label, helperText, validationState, validationMessage, icon, iconPosition = 'left', showCount = false, prefix, suffix, prefixIcon, suffixIcon, showPasswordToggle = false, clearable = false, onClear, loading = false, className = '', id, type = 'text', value, maxLength, ...props }, ref) => {
|
|
243
252
|
const inputId = id || `input-${Math.random().toString(36).substring(2, 9)}`;
|
|
244
253
|
const [showPassword, setShowPassword] = useState(false);
|
|
245
254
|
// Handle clear button click
|
|
@@ -311,7 +320,7 @@ const Input = forwardRef(({ label, helperText, validationState, validationMessag
|
|
|
311
320
|
${validationState && !suffix && !suffixIcon && !showPasswordToggle ? 'pr-10' : ''}
|
|
312
321
|
${(showPasswordToggle && type === 'password') || validationState || suffix || suffixIcon ? 'pr-20' : ''}
|
|
313
322
|
${className}
|
|
314
|
-
`, ...props }), suffix && (jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && (jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsx(X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsx(EyeOff, { className: "h-5 w-5" }) : jsx(Eye, { className: "h-5 w-5" }) })), validationState && (jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
|
|
323
|
+
`, ...props }), suffix && (jsx("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center pointer-events-none text-ink-500 text-sm", children: suffix })), jsxs("div", { className: "absolute inset-y-0 right-0 pr-3 flex items-center gap-2", children: [loading && (jsx("div", { className: "pointer-events-none text-ink-400", children: jsx(Loader2, { className: "h-5 w-5 animate-spin" }) })), suffixIcon && !suffix && !validationState && !showPasswordToggle && !showClearButton && !loading && (jsx("div", { className: "pointer-events-none text-ink-400", children: suffixIcon })), showClearButton && (jsx("button", { type: "button", onClick: handleClear, className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": "Clear input", children: jsx(X, { className: "h-4 w-4" }) })), type === 'password' && showPasswordToggle && (jsx("button", { type: "button", onClick: () => setShowPassword(!showPassword), className: "text-ink-400 hover:text-ink-600 focus:outline-none cursor-pointer pointer-events-auto", "aria-label": showPassword ? 'Hide password' : 'Show password', children: showPassword ? jsx(EyeOff, { className: "h-5 w-5" }) : jsx(Eye, { className: "h-5 w-5" }) })), validationState && (jsx("div", { className: "pointer-events-none", children: getValidationIcon() })), icon && iconPosition === 'right' && !suffix && !suffixIcon && !validationState && (jsx("div", { className: "pointer-events-none text-ink-400", children: icon }))] })] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || validationMessage) && (jsx("p", { className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText })), showCounter && (jsxs("p", { className: `text-xs ml-auto ${currentLength > maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] })] }));
|
|
315
324
|
});
|
|
316
325
|
Input.displayName = 'Input';
|
|
317
326
|
|
|
@@ -518,11 +527,18 @@ const Select = forwardRef((props, ref) => {
|
|
|
518
527
|
});
|
|
519
528
|
Select.displayName = 'Select';
|
|
520
529
|
|
|
521
|
-
|
|
530
|
+
const MultiSelect = forwardRef(({ options, value = [], onChange, placeholder = 'Select options', searchable = false, disabled = false, label, helperText, error, maxHeight = 240, maxSelections, loading = false, 'aria-label': ariaLabel, }, ref) => {
|
|
522
531
|
const [isOpen, setIsOpen] = useState(false);
|
|
523
532
|
const [searchQuery, setSearchQuery] = useState('');
|
|
524
533
|
const selectRef = useRef(null);
|
|
525
534
|
const searchInputRef = useRef(null);
|
|
535
|
+
const triggerRef = useRef(null);
|
|
536
|
+
// Expose imperative methods
|
|
537
|
+
useImperativeHandle(ref, () => ({
|
|
538
|
+
focus: () => triggerRef.current?.focus(),
|
|
539
|
+
open: () => !disabled && setIsOpen(true),
|
|
540
|
+
close: () => setIsOpen(false),
|
|
541
|
+
}));
|
|
526
542
|
const selectedOptions = options.filter(opt => value.includes(opt.value));
|
|
527
543
|
const hasReachedMax = maxSelections ? value.length >= maxSelections : false;
|
|
528
544
|
const filteredOptions = searchable && searchQuery
|
|
@@ -569,11 +585,11 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
|
|
|
569
585
|
e.stopPropagation();
|
|
570
586
|
onChange?.([]);
|
|
571
587
|
};
|
|
572
|
-
return (jsxs("div", { className: "w-full", children: [label && (jsx("label", { className: "label", children: label })), jsxs("div", { ref: selectRef, className: "relative", children: [jsxs("button", { type: "button", onClick: () => !disabled && setIsOpen(!isOpen), disabled: disabled, className: `
|
|
588
|
+
return (jsxs("div", { className: "w-full", children: [label && (jsx("label", { className: "label", children: label })), jsxs("div", { ref: selectRef, className: "relative", children: [jsxs("button", { ref: triggerRef, type: "button", onClick: () => !disabled && !loading && setIsOpen(!isOpen), disabled: disabled || loading, className: `
|
|
573
589
|
input w-full flex items-center justify-between min-h-[42px]
|
|
574
590
|
${error ? 'border-error-400 focus:border-error-400 focus:ring-error-400' : ''}
|
|
575
|
-
${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
576
|
-
`, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsx("span", { className: "text-xs", children: option.icon }), option.label, jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsx(X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxs("div", { className: "flex items-center gap-2 ml-2", children: [selectedOptions.length > 0 && !disabled && (jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsx(X, { className: "h-4 w-4" }) })), jsx(ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` })] })] }), isOpen && (jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsx("div", { className: "p-2 border-b border-paper-200", children: jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
|
|
591
|
+
${disabled || loading ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}
|
|
592
|
+
`, "aria-haspopup": "listbox", "aria-expanded": isOpen, "aria-label": ariaLabel || label, children: [jsx("div", { className: "flex-1 flex items-center gap-2 flex-wrap", children: selectedOptions.length === 0 ? (jsx("span", { className: "text-ink-400", children: placeholder })) : (selectedOptions.map((option) => (jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-1 bg-accent-100 text-accent-800 rounded text-sm", children: [option.icon && jsx("span", { className: "text-xs", children: option.icon }), option.label, jsx("button", { type: "button", onClick: (e) => handleRemove(option.value, e), className: "hover:text-accent-900", "aria-label": `Remove ${option.label}`, children: jsx(X, { className: "h-3 w-3" }) })] }, option.value)))) }), jsxs("div", { className: "flex items-center gap-2 ml-2", children: [loading && (jsx(Loader2, { className: "h-4 w-4 text-ink-400 animate-spin" })), !loading && selectedOptions.length > 0 && !disabled && (jsx("button", { type: "button", onClick: handleClearAll, className: "text-ink-400 hover:text-ink-600", "aria-label": "Clear all", children: jsx(X, { className: "h-4 w-4" }) })), !loading && (jsx(ChevronDown, { className: `h-4 w-4 text-ink-500 transition-transform ${isOpen ? 'rotate-180' : ''}` }))] })] }), isOpen && (jsxs("div", { className: "absolute z-50 w-full mt-2 bg-white bg-subtle-grain rounded-lg shadow-lg border border-paper-200 overflow-hidden animate-fade-in", style: { maxHeight: `${maxHeight}px` }, children: [searchable && (jsx("div", { className: "p-2 border-b border-paper-200", children: jsxs("div", { className: "relative", children: [jsx(Search, { className: "absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-ink-400" }), jsx("input", { ref: searchInputRef, type: "text", value: searchQuery, onChange: (e) => setSearchQuery(e.target.value), placeholder: "Search...", className: "w-full pl-9 pr-3 py-2 text-sm border border-paper-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-accent-400" })] }) })), jsx("div", { className: "overflow-y-auto", style: { maxHeight: `${maxHeight - 60}px` }, role: "listbox", "aria-multiselectable": "true", children: filteredOptions.length === 0 ? (jsx("div", { className: "px-4 py-3 text-sm text-ink-500 text-center", children: "No options found" })) : (filteredOptions.map((option) => {
|
|
577
593
|
const isSelected = value.includes(option.value);
|
|
578
594
|
const isDisabled = option.disabled || (hasReachedMax && !isSelected);
|
|
579
595
|
return (jsx("button", { type: "button", onClick: () => !isDisabled && handleToggle(option.value), disabled: isDisabled, className: `
|
|
@@ -585,7 +601,8 @@ function MultiSelect({ options, value = [], onChange, placeholder = 'Select opti
|
|
|
585
601
|
${isSelected ? 'bg-accent-600 border-accent-600' : 'border-paper-300'}
|
|
586
602
|
`, children: isSelected && jsx(Check, { className: "h-3 w-3 text-white" }) }), option.icon && jsx("span", { children: option.icon }), option.label] }) }, option.value));
|
|
587
603
|
})) })] }))] }), jsxs("div", { className: "flex justify-between items-center mt-2", children: [(helperText || error) && (jsx("p", { className: `text-xs ${error ? 'text-error-600' : 'text-ink-600'}`, children: error || helperText })), maxSelections && (jsxs("p", { className: `text-xs ml-auto ${hasReachedMax ? 'text-warning-600 font-medium' : 'text-ink-500'}`, children: [value.length, " / ", maxSelections, " selected"] }))] })] }));
|
|
588
|
-
}
|
|
604
|
+
});
|
|
605
|
+
MultiSelect.displayName = 'MultiSelect';
|
|
589
606
|
|
|
590
607
|
const Switch = forwardRef(({ checked, onChange, label, description, disabled = false, size = 'md', loading = false, }, ref) => {
|
|
591
608
|
// Generate unique IDs for ARIA
|
|
@@ -632,7 +649,7 @@ const Switch = forwardRef(({ checked, onChange, label, description, disabled = f
|
|
|
632
649
|
});
|
|
633
650
|
Switch.displayName = 'Switch';
|
|
634
651
|
|
|
635
|
-
const Textarea = forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', className = '', id, value, rows = 4, ...props }, ref) => {
|
|
652
|
+
const Textarea = forwardRef(({ label, helperText, validationState, validationMessage, maxLength, showCharCount = false, autoExpand = false, minRows = 2, maxRows = 10, resize = 'vertical', loading = false, className = '', id, value, rows = 4, ...props }, ref) => {
|
|
636
653
|
const textareaId = id || `textarea-${Math.random().toString(36).substring(2, 9)}`;
|
|
637
654
|
const currentLength = typeof value === 'string' ? value.length : 0;
|
|
638
655
|
const internalRef = useRef(null);
|
|
@@ -707,14 +724,15 @@ const Textarea = forwardRef(({ label, helperText, validationState, validationMes
|
|
|
707
724
|
return 'text-ink-600';
|
|
708
725
|
}
|
|
709
726
|
};
|
|
710
|
-
return (jsxs("div", { className: "w-full", children: [label && (jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
727
|
+
return (jsxs("div", { className: "w-full", children: [label && (jsxs("label", { htmlFor: textareaId, className: "label", children: [label, props.required && jsx("span", { className: "text-error-500 ml-1", children: "*" })] })), jsxs("div", { className: "relative", children: [jsx("textarea", { ref: textareaRef, id: textareaId, value: value, maxLength: maxLength, rows: autoExpand ? minRows : rows, className: `
|
|
728
|
+
block w-full px-4 py-3 border rounded-lg text-sm text-ink-800 placeholder-ink-400
|
|
729
|
+
bg-white bg-subtle-grain transition-all duration-200
|
|
730
|
+
focus:outline-none focus:ring-2 ${getResizeClass()}
|
|
731
|
+
disabled:bg-paper-100 disabled:text-ink-400 disabled:cursor-not-allowed disabled:opacity-60
|
|
732
|
+
${getValidationClasses()}
|
|
733
|
+
${loading ? 'pr-10' : ''}
|
|
734
|
+
${className}
|
|
735
|
+
`, "aria-invalid": validationState === 'error', "aria-describedby": validationMessage || helperText ? `${textareaId}-help` : undefined, "aria-required": props.required, ...props }), loading && (jsx("div", { className: "absolute top-3 right-3 pointer-events-none", children: jsx(Loader2, { className: "h-5 w-5 text-ink-400 animate-spin" }) }))] }), ((helperText || validationMessage) || (showCharCount && maxLength)) && (jsxs("div", { className: "mt-2 flex items-center justify-between", children: [jsxs("div", { className: "flex items-center gap-2", children: [validationState && getValidationIcon(), (helperText || validationMessage) && (jsx("p", { id: `${textareaId}-help`, className: `text-xs ${validationMessage ? getValidationMessageColor() : 'text-ink-600'}`, children: validationMessage || helperText }))] }), showCharCount && maxLength && (jsxs("p", { className: `text-xs ${currentLength >= maxLength ? 'text-error-600' : 'text-ink-500'}`, children: [currentLength, " / ", maxLength] }))] }))] }));
|
|
718
736
|
});
|
|
719
737
|
Textarea.displayName = 'Textarea';
|
|
720
738
|
|
|
@@ -1930,6 +1948,8 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
|
|
|
1930
1948
|
/**
|
|
1931
1949
|
* Card - Container component with paper aesthetic and subtle shadow
|
|
1932
1950
|
*
|
|
1951
|
+
* Supports ref forwarding for DOM access.
|
|
1952
|
+
*
|
|
1933
1953
|
* A content container with paper texture, border, and shadow effects. Supports
|
|
1934
1954
|
* different sizes, variants (padding/shadow levels), and loading states.
|
|
1935
1955
|
*
|
|
@@ -1959,8 +1979,14 @@ function SkeletonTable({ rows = 5, columns = 4 }) {
|
|
|
1959
1979
|
* <p>Content</p>
|
|
1960
1980
|
* </Card>
|
|
1961
1981
|
* ```
|
|
1982
|
+
*
|
|
1983
|
+
* @example With ref
|
|
1984
|
+
* ```tsx
|
|
1985
|
+
* const cardRef = useRef<HTMLDivElement>(null);
|
|
1986
|
+
* <Card ref={cardRef}>Content</Card>
|
|
1987
|
+
* ```
|
|
1962
1988
|
*/
|
|
1963
|
-
|
|
1989
|
+
const Card = forwardRef(({ children, variant = 'default', width = 'auto', className = '', onClick, hoverable = false, loading = false, ...htmlProps }, ref) => {
|
|
1964
1990
|
const baseStyles = 'bg-white bg-subtle-grain border-2 border-paper-300 transition-shadow duration-200';
|
|
1965
1991
|
const variantStyles = {
|
|
1966
1992
|
default: 'rounded-xl shadow-lg p-8',
|
|
@@ -1976,8 +2002,9 @@ function Card({ children, variant = 'default', width = 'auto', className = '', o
|
|
|
1976
2002
|
full: 'w-full',
|
|
1977
2003
|
};
|
|
1978
2004
|
const interactiveStyles = onClick || hoverable ? 'cursor-pointer hover:shadow-md' : '';
|
|
1979
|
-
return (jsx("div", { className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxs("div", { className: "space-y-4", children: [jsx(Skeleton, { className: "h-6 w-3/4" }), jsx(Skeleton, { className: "h-4 w-full" }), jsx(Skeleton, { className: "h-4 w-5/6" }), jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
|
|
1980
|
-
}
|
|
2005
|
+
return (jsx("div", { ref: ref, ...htmlProps, className: `${baseStyles} ${variantStyles[variant]} ${widthStyles[width]} ${interactiveStyles} ${className}`, onClick: !loading ? onClick : undefined, role: onClick ? 'button' : undefined, tabIndex: onClick ? 0 : undefined, children: loading ? (jsxs("div", { className: "space-y-4", children: [jsx(Skeleton, { className: "h-6 w-3/4" }), jsx(Skeleton, { className: "h-4 w-full" }), jsx(Skeleton, { className: "h-4 w-5/6" }), jsx(Skeleton, { className: "h-4 w-4/6" })] })) : (children) }));
|
|
2006
|
+
});
|
|
2007
|
+
Card.displayName = 'Card';
|
|
1981
2008
|
/**
|
|
1982
2009
|
* CardHeader - Header section for Card component
|
|
1983
2010
|
*
|
|
@@ -2075,15 +2102,34 @@ function Separator({ orientation = 'horizontal', className = '', spacing = 'md',
|
|
|
2075
2102
|
/**
|
|
2076
2103
|
* Stack component for arranging children vertically or horizontally with consistent spacing.
|
|
2077
2104
|
*
|
|
2078
|
-
*
|
|
2105
|
+
* Supports ref forwarding for DOM access.
|
|
2106
|
+
*
|
|
2107
|
+
* Spacing scale (use either `spacing` or `gap` prop - they're aliases):
|
|
2079
2108
|
* - none: 0
|
|
2080
2109
|
* - xs: 0.5rem (2)
|
|
2081
2110
|
* - sm: 0.75rem (3)
|
|
2082
2111
|
* - md: 1.5rem (6)
|
|
2083
2112
|
* - lg: 2rem (8)
|
|
2084
2113
|
* - xl: 3rem (12)
|
|
2114
|
+
*
|
|
2115
|
+
* @example
|
|
2116
|
+
* ```tsx
|
|
2117
|
+
* // Using spacing prop
|
|
2118
|
+
* <Stack spacing="md">
|
|
2119
|
+
* <Card>Item 1</Card>
|
|
2120
|
+
* <Card>Item 2</Card>
|
|
2121
|
+
* </Stack>
|
|
2122
|
+
*
|
|
2123
|
+
* // Using gap prop (alias)
|
|
2124
|
+
* <Stack gap="md">
|
|
2125
|
+
* <Card>Item 1</Card>
|
|
2126
|
+
* <Card>Item 2</Card>
|
|
2127
|
+
* </Stack>
|
|
2128
|
+
* ```
|
|
2085
2129
|
*/
|
|
2086
|
-
const Stack = ({ children, direction = 'vertical', spacing
|
|
2130
|
+
const Stack = forwardRef(({ children, direction = 'vertical', spacing, gap, align = 'stretch', justify = 'start', wrap = false, className = '', ...htmlProps }, ref) => {
|
|
2131
|
+
// Use gap as alias for spacing (spacing takes precedence if both provided)
|
|
2132
|
+
const effectiveSpacing = spacing ?? gap ?? 'md';
|
|
2087
2133
|
const spacingClasses = {
|
|
2088
2134
|
vertical: {
|
|
2089
2135
|
none: '',
|
|
@@ -2115,20 +2161,23 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
|
|
|
2115
2161
|
between: 'justify-between',
|
|
2116
2162
|
around: 'justify-around',
|
|
2117
2163
|
};
|
|
2118
|
-
return (jsx("div", { className: `
|
|
2164
|
+
return (jsx("div", { ref: ref, ...htmlProps, className: `
|
|
2119
2165
|
flex
|
|
2120
2166
|
${direction === 'vertical' ? 'flex-col' : 'flex-row'}
|
|
2121
2167
|
${wrap ? 'flex-wrap' : ''}
|
|
2122
|
-
${spacingClasses[direction][
|
|
2168
|
+
${spacingClasses[direction][effectiveSpacing]}
|
|
2123
2169
|
${alignClasses[align]}
|
|
2124
2170
|
${justifyClasses[justify]}
|
|
2125
2171
|
${className}
|
|
2126
2172
|
`, children: children }));
|
|
2127
|
-
};
|
|
2173
|
+
});
|
|
2174
|
+
Stack.displayName = 'Stack';
|
|
2128
2175
|
|
|
2129
2176
|
/**
|
|
2130
2177
|
* Grid component for arranging children in a CSS grid layout.
|
|
2131
2178
|
*
|
|
2179
|
+
* Supports ref forwarding for DOM access.
|
|
2180
|
+
*
|
|
2132
2181
|
* Column options: 1, 2, 3, 4, 6, 12
|
|
2133
2182
|
*
|
|
2134
2183
|
* Responsive breakpoints (mobile-first):
|
|
@@ -2153,7 +2202,7 @@ const Stack = ({ children, direction = 'vertical', spacing = 'md', align = 'stre
|
|
|
2153
2202
|
* <Card>Item 2</Card>
|
|
2154
2203
|
* </Grid>
|
|
2155
2204
|
*/
|
|
2156
|
-
const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', }) => {
|
|
2205
|
+
const Grid = forwardRef(({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '', ...htmlProps }, ref) => {
|
|
2157
2206
|
// Base column classes
|
|
2158
2207
|
const baseColumnClasses = {
|
|
2159
2208
|
1: 'grid-cols-1',
|
|
@@ -2212,18 +2261,20 @@ const Grid = ({ children, columns = 1, sm, md, lg, xl, gap = 'md', className = '
|
|
|
2212
2261
|
lg ? lgColumnClasses[lg] : '',
|
|
2213
2262
|
xl ? xlColumnClasses[xl] : '',
|
|
2214
2263
|
].filter(Boolean).join(' ');
|
|
2215
|
-
return (jsx("div", { className: `
|
|
2264
|
+
return (jsx("div", { ref: ref, ...htmlProps, className: `
|
|
2216
2265
|
grid
|
|
2217
2266
|
${columnClassList}
|
|
2218
2267
|
${gapClasses[gap]}
|
|
2219
2268
|
${className}
|
|
2220
2269
|
`, children: children }));
|
|
2221
|
-
};
|
|
2270
|
+
});
|
|
2271
|
+
Grid.displayName = 'Grid';
|
|
2222
2272
|
|
|
2223
2273
|
/**
|
|
2224
2274
|
* Box component for generic containers with design system spacing and borders.
|
|
2275
|
+
* Supports ref forwarding for DOM access.
|
|
2225
2276
|
*/
|
|
2226
|
-
const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }) => {
|
|
2277
|
+
const Box = forwardRef(({ children, padding, paddingTop, paddingBottom, paddingLeft, paddingRight, margin, marginTop, marginBottom, marginLeft, marginRight, border = 'none', borderColor = 'default', rounded, width, height, className = '', ...htmlProps }, ref) => {
|
|
2227
2278
|
const spacingMap = {
|
|
2228
2279
|
none: '0',
|
|
2229
2280
|
xs: '2',
|
|
@@ -2308,7 +2359,7 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
|
|
|
2308
2359
|
};
|
|
2309
2360
|
return roundedClasses[rounded];
|
|
2310
2361
|
};
|
|
2311
|
-
return (jsx("div", { ...htmlProps, className: `
|
|
2362
|
+
return (jsx("div", { ref: ref, ...htmlProps, className: `
|
|
2312
2363
|
${getPaddingClass()}
|
|
2313
2364
|
${getMarginClass()}
|
|
2314
2365
|
${borderClasses[border]}
|
|
@@ -2318,7 +2369,8 @@ const Box = ({ children, padding, paddingTop, paddingBottom, paddingLeft, paddin
|
|
|
2318
2369
|
${getHeightClass()}
|
|
2319
2370
|
${className}
|
|
2320
2371
|
`, children: children }));
|
|
2321
|
-
};
|
|
2372
|
+
});
|
|
2373
|
+
Box.displayName = 'Box';
|
|
2322
2374
|
|
|
2323
2375
|
/**
|
|
2324
2376
|
* GridItem component for items within a Grid layout.
|
|
@@ -2363,6 +2415,8 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
|
|
|
2363
2415
|
/**
|
|
2364
2416
|
* Text component for consistent typography across the application.
|
|
2365
2417
|
*
|
|
2418
|
+
* Supports ref forwarding for DOM access.
|
|
2419
|
+
*
|
|
2366
2420
|
* Size scale:
|
|
2367
2421
|
* - xs: 0.75rem (12px)
|
|
2368
2422
|
* - sm: 0.875rem (14px)
|
|
@@ -2370,8 +2424,21 @@ const GridItem = ({ colSpan, rowSpan, children, className = '', ...boxProps }) =
|
|
|
2370
2424
|
* - lg: 1.125rem (18px)
|
|
2371
2425
|
* - xl: 1.25rem (20px)
|
|
2372
2426
|
* - 2xl: 1.5rem (24px)
|
|
2427
|
+
*
|
|
2428
|
+
* @example
|
|
2429
|
+
* ```tsx
|
|
2430
|
+
* <Text size="lg" weight="semibold" color="primary">
|
|
2431
|
+
* Hello World
|
|
2432
|
+
* </Text>
|
|
2433
|
+
*
|
|
2434
|
+
* <Text color="warning">Warning message</Text>
|
|
2435
|
+
*
|
|
2436
|
+
* // With ref
|
|
2437
|
+
* const textRef = useRef<HTMLParagraphElement>(null);
|
|
2438
|
+
* <Text ref={textRef}>Measurable text</Text>
|
|
2439
|
+
* ```
|
|
2373
2440
|
*/
|
|
2374
|
-
const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', }) => {
|
|
2441
|
+
const Text = forwardRef(({ children, as: Component = 'p', size = 'base', weight = 'normal', color = 'primary', align = 'left', truncate = false, lineClamp, transform, className = '', ...htmlProps }, ref) => {
|
|
2375
2442
|
const sizeClasses = {
|
|
2376
2443
|
xs: 'text-xs',
|
|
2377
2444
|
sm: 'text-sm',
|
|
@@ -2393,6 +2460,7 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
|
|
|
2393
2460
|
accent: 'text-primary-600',
|
|
2394
2461
|
error: 'text-error-600',
|
|
2395
2462
|
success: 'text-success-600',
|
|
2463
|
+
warning: 'text-warning-600',
|
|
2396
2464
|
};
|
|
2397
2465
|
const alignClasses = {
|
|
2398
2466
|
left: 'text-left',
|
|
@@ -2424,8 +2492,9 @@ const Text = ({ children, as: Component = 'p', size = 'base', weight = 'normal',
|
|
|
2424
2492
|
lineClamp ? lineClampClasses[lineClamp] : '',
|
|
2425
2493
|
className,
|
|
2426
2494
|
].filter(Boolean).join(' ');
|
|
2427
|
-
return (jsx(Component, { className: classes, children: children }));
|
|
2428
|
-
};
|
|
2495
|
+
return (jsx(Component, { ref: ref, className: classes, ...htmlProps, children: children }));
|
|
2496
|
+
});
|
|
2497
|
+
Text.displayName = 'Text';
|
|
2429
2498
|
|
|
2430
2499
|
const toastStyles = {
|
|
2431
2500
|
success: {
|
|
@@ -6068,99 +6137,6 @@ function StepIndicator({ steps, currentStep, variant = 'horizontal', onStepClick
|
|
|
6068
6137
|
}) }) }));
|
|
6069
6138
|
}
|
|
6070
6139
|
|
|
6071
|
-
function Table$1({ data, columns, keyExtractor, selectable = false, expandable = false, onRowSelect, renderExpandedRow, emptyState, className = '', onSort, sortColumn: externalSortColumn, sortDirection: externalSortDirection, }) {
|
|
6072
|
-
const [internalSortColumn, setInternalSortColumn] = useState(null);
|
|
6073
|
-
const [internalSortDirection, setInternalSortDirection] = useState(null);
|
|
6074
|
-
// Use external sort state if provided, otherwise use internal state
|
|
6075
|
-
const sortColumn = externalSortColumn !== undefined ? externalSortColumn : internalSortColumn;
|
|
6076
|
-
const sortDirection = externalSortDirection !== undefined ? externalSortDirection : internalSortDirection;
|
|
6077
|
-
const [selectedRows, setSelectedRows] = useState(new Set());
|
|
6078
|
-
const [expandedRows, setExpandedRows] = useState(new Set());
|
|
6079
|
-
// Handle sorting
|
|
6080
|
-
const handleSort = (columnKey) => {
|
|
6081
|
-
let newDirection;
|
|
6082
|
-
if (sortColumn === columnKey) {
|
|
6083
|
-
if (sortDirection === 'asc') {
|
|
6084
|
-
newDirection = 'desc';
|
|
6085
|
-
}
|
|
6086
|
-
else if (sortDirection === 'desc') {
|
|
6087
|
-
newDirection = null;
|
|
6088
|
-
}
|
|
6089
|
-
else {
|
|
6090
|
-
newDirection = 'asc';
|
|
6091
|
-
}
|
|
6092
|
-
}
|
|
6093
|
-
else {
|
|
6094
|
-
newDirection = 'asc';
|
|
6095
|
-
}
|
|
6096
|
-
// If using external sort control, call the callback
|
|
6097
|
-
if (onSort) {
|
|
6098
|
-
onSort(columnKey, newDirection);
|
|
6099
|
-
}
|
|
6100
|
-
else {
|
|
6101
|
-
// Otherwise update internal state
|
|
6102
|
-
setInternalSortColumn(newDirection === null ? null : columnKey);
|
|
6103
|
-
setInternalSortDirection(newDirection);
|
|
6104
|
-
}
|
|
6105
|
-
};
|
|
6106
|
-
// Handle row selection
|
|
6107
|
-
const handleRowSelect = (rowKey) => {
|
|
6108
|
-
const newSelected = new Set(selectedRows);
|
|
6109
|
-
if (newSelected.has(rowKey)) {
|
|
6110
|
-
newSelected.delete(rowKey);
|
|
6111
|
-
}
|
|
6112
|
-
else {
|
|
6113
|
-
newSelected.add(rowKey);
|
|
6114
|
-
}
|
|
6115
|
-
setSelectedRows(newSelected);
|
|
6116
|
-
onRowSelect?.(Array.from(newSelected));
|
|
6117
|
-
};
|
|
6118
|
-
// Handle select all
|
|
6119
|
-
const handleSelectAll = () => {
|
|
6120
|
-
if (selectedRows.size === data.length) {
|
|
6121
|
-
setSelectedRows(new Set());
|
|
6122
|
-
onRowSelect?.([]);
|
|
6123
|
-
}
|
|
6124
|
-
else {
|
|
6125
|
-
const allKeys = new Set(data.map(keyExtractor));
|
|
6126
|
-
setSelectedRows(allKeys);
|
|
6127
|
-
onRowSelect?.(Array.from(allKeys));
|
|
6128
|
-
}
|
|
6129
|
-
};
|
|
6130
|
-
// Handle row expansion
|
|
6131
|
-
const handleRowExpand = (rowKey) => {
|
|
6132
|
-
const newExpanded = new Set(expandedRows);
|
|
6133
|
-
if (newExpanded.has(rowKey)) {
|
|
6134
|
-
newExpanded.delete(rowKey);
|
|
6135
|
-
}
|
|
6136
|
-
else {
|
|
6137
|
-
newExpanded.add(rowKey);
|
|
6138
|
-
}
|
|
6139
|
-
setExpandedRows(newExpanded);
|
|
6140
|
-
};
|
|
6141
|
-
const getSortIcon = (columnKey) => {
|
|
6142
|
-
if (sortColumn !== columnKey) {
|
|
6143
|
-
return jsx(ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
|
|
6144
|
-
}
|
|
6145
|
-
if (sortDirection === 'asc') {
|
|
6146
|
-
return jsx(ArrowUp, { className: "h-4 w-4 text-accent-600" });
|
|
6147
|
-
}
|
|
6148
|
-
if (sortDirection === 'desc') {
|
|
6149
|
-
return jsx(ArrowDown, { className: "h-4 w-4 text-accent-600" });
|
|
6150
|
-
}
|
|
6151
|
-
return jsx(ArrowUpDown, { className: "h-4 w-4 text-ink-400" });
|
|
6152
|
-
};
|
|
6153
|
-
if (data.length === 0 && emptyState) {
|
|
6154
|
-
return jsx("div", { children: emptyState });
|
|
6155
|
-
}
|
|
6156
|
-
return (jsx("div", { className: `overflow-x-auto ${className}`, children: jsxs("table", { className: "table", children: [jsx("thead", { className: "table-header", children: jsxs("tr", { children: [selectable && (jsx("th", { className: "table-header-cell w-12", children: jsx("input", { type: "checkbox", checked: selectedRows.size === data.length && data.length > 0, onChange: handleSelectAll, className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": "Select all rows" }) })), expandable && jsx("th", { className: "table-header-cell w-12" }), columns.map((column) => (jsx("th", { className: "table-header-cell", style: { width: column.width }, children: column.sortable ? (jsxs("button", { onClick: () => handleSort(column.key), className: "group inline-flex items-center gap-2 hover:text-ink-900 transition-colors", children: [jsx("span", { children: column.header }), getSortIcon(column.key)] })) : (column.header) }, column.key)))] }) }), jsx("tbody", { children: data.map((row) => {
|
|
6157
|
-
const rowKey = keyExtractor(row);
|
|
6158
|
-
const isSelected = selectedRows.has(rowKey);
|
|
6159
|
-
const isExpanded = expandedRows.has(rowKey);
|
|
6160
|
-
return (jsxs(React__default.Fragment, { children: [jsxs("tr", { className: `table-row ${isSelected ? 'bg-accent-50 border-l-2 border-accent-500' : ''}`, children: [selectable && (jsx("td", { className: "table-cell", children: jsx("input", { type: "checkbox", checked: isSelected, onChange: () => handleRowSelect(rowKey), className: "w-4 h-4 text-accent-600 border-paper-300 rounded focus:ring-accent-400", "aria-label": `Select row ${rowKey}` }) })), expandable && (jsx("td", { className: "table-cell", children: jsx("button", { onClick: () => handleRowExpand(rowKey), className: "text-ink-500 hover:text-ink-900 transition-colors", "aria-label": isExpanded ? 'Collapse row' : 'Expand row', children: isExpanded ? (jsx(ChevronDown, { className: "h-4 w-4" })) : (jsx(ChevronRight, { className: "h-4 w-4" })) }) })), columns.map((column) => (jsx("td", { className: "table-cell", children: column.accessor ? column.accessor(row) : row[column.key] }, column.key)))] }), expandable && isExpanded && renderExpandedRow && (jsx("tr", { children: jsx("td", { colSpan: columns.length + (selectable ? 1 : 0) + (expandable ? 1 : 0), className: "px-6 py-4 bg-paper-50", children: renderExpandedRow(row) }) }))] }, rowKey));
|
|
6161
|
-
}) })] }) }));
|
|
6162
|
-
}
|
|
6163
|
-
|
|
6164
6140
|
function Badge({ children, variant = 'neutral', size = 'md', icon, onRemove, className = '', dot = false, }) {
|
|
6165
6141
|
const variantStyles = {
|
|
6166
6142
|
success: 'bg-success-50 text-success-700 border-success-200',
|
|
@@ -6268,8 +6244,8 @@ const Avatar = ({ firstName, lastName, fallbackText = 'U', imageUrl, size = 'md'
|
|
|
6268
6244
|
`, style: { textShadow: '0 1px 2px rgba(0,0,0,0.3)' }, children: getInitials() }) }));
|
|
6269
6245
|
};
|
|
6270
6246
|
|
|
6271
|
-
function EmptyState({ icon, title, description, action, secondaryAction, }) {
|
|
6272
|
-
return (jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), (action || secondaryAction) && (jsxs("div", { className: "flex items-center gap-3", children: [action && (jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
|
|
6247
|
+
function EmptyState({ icon, title, description, action, secondaryAction, children, }) {
|
|
6248
|
+
return (jsxs("div", { className: "flex flex-col items-center justify-center py-16 px-6 text-center", children: [icon && (jsx("div", { className: "mb-6 text-ink-400", children: icon })), jsx("h3", { className: "text-lg font-medium text-ink-900 mb-2", children: title }), jsx("p", { className: "text-sm text-ink-600 max-w-md mb-8", children: description }), children && (jsx("div", { className: "mb-8 w-full max-w-md", children: children })), (action || secondaryAction) && (jsxs("div", { className: "flex items-center gap-3", children: [action && (jsx(Button, { variant: "primary", onClick: action.onClick, children: action.label })), secondaryAction && (jsx(Button, { variant: "secondary", onClick: secondaryAction.onClick, children: secondaryAction.label }))] }))] }));
|
|
6273
6249
|
}
|
|
6274
6250
|
|
|
6275
6251
|
/**
|
|
@@ -7285,7 +7261,9 @@ function getColumnStyle(column, dynamicWidth) {
|
|
|
7285
7261
|
*/
|
|
7286
7262
|
function DataTable({ data, columns, loading = false, error = null, emptyMessage = 'No data available', loadingRows = 5, className = '', onSortChange, currentSort = null, onEdit, onDelete, actions = [], enableContextMenu = true, onRowClick, onRowDoubleClick, selectable = false, selectedRows: externalSelectedRows, onRowSelect, keyExtractor, expandable = false, expandedRows: externalExpandedRows, renderExpandedRow, expandedRowConfig, showExpandChevron = false,
|
|
7287
7263
|
// Visual customization props
|
|
7288
|
-
striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
|
|
7264
|
+
striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, highlightedRowId, bordered = false, borderColor = 'border-paper-200', disableHover = false, hiddenColumns = [], headerClassName = '', renderEmptyState: customRenderEmptyState, resizable = false, onColumnResize, reorderable = false, onColumnReorder, virtualized = false, virtualHeight = '600px', virtualRowHeight = 60,
|
|
7265
|
+
// Pagination props
|
|
7266
|
+
paginated = false, currentPage = 1, pageSize = 10, totalItems, onPageChange, pageSizeOptions = [10, 25, 50, 100], onPageSizeChange, showPageSizeSelector = true, }) {
|
|
7289
7267
|
// Column resizing state
|
|
7290
7268
|
const [columnWidths, setColumnWidths] = useState({});
|
|
7291
7269
|
const [resizingColumn, setResizingColumn] = useState(null);
|
|
@@ -7518,16 +7496,30 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7518
7496
|
}
|
|
7519
7497
|
});
|
|
7520
7498
|
}
|
|
7499
|
+
// Combine all actions: built-in first, then custom actions, then delete last
|
|
7500
|
+
// Delete is stored separately to ensure it's always last
|
|
7501
|
+
let deleteAction = null;
|
|
7521
7502
|
if (onDelete) {
|
|
7522
|
-
|
|
7503
|
+
deleteAction = {
|
|
7523
7504
|
label: 'Delete',
|
|
7524
7505
|
icon: Trash,
|
|
7525
7506
|
onClick: onDelete,
|
|
7526
7507
|
variant: 'danger',
|
|
7527
7508
|
tooltip: 'Delete item'
|
|
7528
|
-
}
|
|
7509
|
+
};
|
|
7529
7510
|
}
|
|
7530
|
-
|
|
7511
|
+
// Build final actions array with consistent ordering:
|
|
7512
|
+
// 1. Edit (first - most common action)
|
|
7513
|
+
// 2. View Details
|
|
7514
|
+
// 3. Add Related actions
|
|
7515
|
+
// 4. Manage Related actions
|
|
7516
|
+
// 5. Custom actions (from actions prop)
|
|
7517
|
+
// 6. Delete (always last - destructive action)
|
|
7518
|
+
const allActions = [
|
|
7519
|
+
...builtInActions,
|
|
7520
|
+
...actions,
|
|
7521
|
+
...(deleteAction ? [deleteAction] : [])
|
|
7522
|
+
];
|
|
7531
7523
|
// Convert actions to menu items for context menu
|
|
7532
7524
|
const convertActionsToMenuItems = (item) => {
|
|
7533
7525
|
const visibleActions = allActions.filter(action => !action.show || action.show(item));
|
|
@@ -7876,8 +7868,22 @@ striped = false, stripedColor, density = 'normal', rowClassName, rowHighlight, h
|
|
|
7876
7868
|
})] }) }), jsx("tbody", { className: "bg-white table-loading transition-opacity duration-200", children: loading && data.length === 0 ? (renderLoadingSkeleton()) : data.length === 0 ? (renderEmptyStateContent()) : (renderDataRows()) })] })] }));
|
|
7877
7869
|
// Wrap in scrollable container if virtualized
|
|
7878
7870
|
const finalContent = virtualized ? (jsx("div", { ref: tableContainerRef, onScroll: handleScroll, style: { height: virtualHeight, overflow: 'auto' }, className: "rounded-lg", children: tableContent })) : tableContent;
|
|
7871
|
+
// Calculate pagination values
|
|
7872
|
+
const effectiveTotalItems = totalItems ?? data.length;
|
|
7873
|
+
const totalPages = Math.ceil(effectiveTotalItems / pageSize);
|
|
7874
|
+
// Page size selector options
|
|
7875
|
+
const pageSizeSelectOptions = pageSizeOptions.map(size => ({
|
|
7876
|
+
value: String(size),
|
|
7877
|
+
label: `${size} per page`,
|
|
7878
|
+
}));
|
|
7879
|
+
// Render pagination controls
|
|
7880
|
+
const renderPaginationControls = () => {
|
|
7881
|
+
if (!paginated)
|
|
7882
|
+
return null;
|
|
7883
|
+
return (jsxs("div", { className: "flex items-center justify-between mb-4 px-1", children: [jsxs("div", { className: "flex items-center gap-4", children: [showPageSizeSelector && onPageSizeChange && (jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "text-sm text-ink-600", children: "Show:" }), jsx(Select, { options: pageSizeSelectOptions, value: String(pageSize), onChange: (value) => onPageSizeChange?.(Number(value)) })] })), jsx("span", { className: "text-sm text-ink-600", children: effectiveTotalItems > 0 ? (jsxs(Fragment, { children: ["Showing ", ((currentPage - 1) * pageSize) + 1, " - ", Math.min(currentPage * pageSize, effectiveTotalItems), " of ", effectiveTotalItems] })) : ('No items') })] }), totalPages > 1 && onPageChange && (jsx(Pagination, { currentPage: currentPage, totalPages: totalPages, onPageChange: onPageChange }))] }));
|
|
7884
|
+
};
|
|
7879
7885
|
// Render with context menu
|
|
7880
|
-
return (jsxs(Fragment, { children: [finalContent, contextMenuState.isOpen && contextMenuState.item && (jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
|
|
7886
|
+
return (jsxs(Fragment, { children: [renderPaginationControls(), finalContent, contextMenuState.isOpen && contextMenuState.item && (jsx(Menu, { items: convertActionsToMenuItems(contextMenuState.item), position: contextMenuState.position, onClose: () => setContextMenuState({ isOpen: false, position: { x: 0, y: 0 }, item: null }) }))] }));
|
|
7881
7887
|
}
|
|
7882
7888
|
|
|
7883
7889
|
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
|
|
@@ -60339,5 +60345,5 @@ function useColumnReorder(initialColumns, options = {}) {
|
|
|
60339
60345
|
};
|
|
60340
60346
|
}
|
|
60341
60347
|
|
|
60342
|
-
export { Accordion, ActionButton, AdminModal, Alert, AlertDialog, AppLayout, Autocomplete, Avatar, Badge, BottomSheet, Box, Breadcrumbs, Button, ButtonGroup, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Carousel, Checkbox, Chip, Collapsible, ColorPicker, Combobox, ComingSoon, CommandPalette, ConfirmDialog, ContextMenu, ControlBar, CurrencyDisplay, CurrencyInput, Dashboard, DashboardContent, DashboardHeader, DataTable, DateDisplay, DatePicker, DateRangePicker, DateTimePicker, Drawer, DrawerFooter, DropZone, Dropdown, DropdownTrigger, EmptyState, ErrorBoundary, ExpandableRowButton, ExpandableToolbar, ExpandedRowEditForm, ExportButton, FieldArray, FileUpload, FilterBar, FilterControls, FilterStatusBanner, Form, FormContext, FormControl, FormWizard, Grid, GridItem, Hide, HoverCard, InfiniteScroll, Input, KanbanBoard, Layout, Loading, LoadingOverlay, Logo, MarkdownEditor, MaskedInput, Menu, MenuDivider, Modal, ModalFooter, MultiSelect, NotificationBar, NotificationIndicator, NumberInput, Page, PageLayout, PageNavigation, Pagination, PasswordInput, Popover, Progress, QueryTransparency, RadioGroup, Rating, RichTextEditor, SearchBar, Select, Separator, Show, Sidebar, SidebarGroup, Skeleton, SkeletonCard, SkeletonTable, Slider, Spreadsheet, SpreadsheetReport, Stack, StatCard, StatItem, StatsCardGrid, StatsGrid, StatusBadge, StatusBar, StepIndicator, Stepper, Switch,
|
|
60348
|
+
export { Accordion, ActionButton, AdminModal, Alert, AlertDialog, AppLayout, Autocomplete, Avatar, Badge, BottomSheet, Box, Breadcrumbs, Button, ButtonGroup, Calendar, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CardView, Carousel, Checkbox, Chip, Collapsible, ColorPicker, Combobox, ComingSoon, CommandPalette, ConfirmDialog, ContextMenu, ControlBar, CurrencyDisplay, CurrencyInput, Dashboard, DashboardContent, DashboardHeader, DataTable, DateDisplay, DatePicker, DateRangePicker, DateTimePicker, Drawer, DrawerFooter, DropZone, Dropdown, DropdownTrigger, EmptyState, ErrorBoundary, ExpandableRowButton, ExpandableToolbar, ExpandedRowEditForm, ExportButton, FieldArray, FileUpload, FilterBar, FilterControls, FilterStatusBanner, Form, FormContext, FormControl, FormWizard, Grid, GridItem, Hide, HoverCard, InfiniteScroll, Input, KanbanBoard, Layout, Loading, LoadingOverlay, Logo, MarkdownEditor, MaskedInput, Menu, MenuDivider, Modal, ModalFooter, MultiSelect, NotificationBar, NotificationIndicator, NumberInput, Page, PageLayout, PageNavigation, Pagination, PasswordInput, Popover, Progress, QueryTransparency, RadioGroup, Rating, RichTextEditor, SearchBar, Select, Separator, Show, Sidebar, SidebarGroup, Skeleton, SkeletonCard, SkeletonTable, Slider, Spreadsheet, SpreadsheetReport, Stack, StatCard, StatItem, StatsCardGrid, StatsGrid, StatusBadge, StatusBar, StepIndicator, Stepper, Switch, Tabs, Text, Textarea, ThemeToggle, TimePicker, Timeline, Toast, ToastContainer, Tooltip, Transfer, TreeView, TwoColumnContent, UserProfileButton, addErrorMessage, addInfoMessage, addSuccessMessage, addWarningMessage, calculateColumnWidth, createActionsSection, createFiltersSection, createMultiSheetExcel, createPageControlsSection, createQueryDetailsSection, exportDataTableToExcel, exportToExcel, formatStatisticValue, formatStatistics, loadColumnOrder, loadColumnWidths, reorderArray, saveColumnOrder, saveColumnWidths, statusManager, useColumnReorder, useColumnResize, useCommandPalette, useConfirmDialog, useFormContext, useMediaQuery };
|
|
60343
60349
|
//# sourceMappingURL=index.esm.js.map
|