indas-ui 0.1.8 → 0.1.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/cjs/components/chat/multimodal-input.js +2 -2
  2. package/dist/cjs/components/dashboard/charts/BoxPlot.js +5 -5
  3. package/dist/cjs/components/dashboard/charts/Gantt.js +30 -30
  4. package/dist/cjs/components/dashboard/charts/Pareto.js +2 -2
  5. package/dist/cjs/components/datagrid/DataGrid.js +10 -10
  6. package/dist/cjs/components/datagrid/controls/menu/view/CardView.js +6 -6
  7. package/dist/cjs/components/modals/Modal.js +30 -6
  8. package/dist/cjs/components/ui/chart.js +4 -4
  9. package/dist/cjs/contexts/ThemeContext.js +52 -52
  10. package/dist/cjs/lib/api/activity/email/templates.js +218 -218
  11. package/dist/cjs/lib/theme/utils.js +26 -26
  12. package/dist/cjs/lib/vision/dieline-extractor.js +76 -76
  13. package/dist/cjs/locales/de.json +78 -78
  14. package/dist/cjs/locales/en.json +2217 -2217
  15. package/dist/cjs/locales/es.json +78 -78
  16. package/dist/cjs/locales/fr.json +77 -77
  17. package/dist/cjs/locales/hi.json +1599 -1599
  18. package/dist/cjs/services/GlobalLoadingService.js +37 -37
  19. package/dist/cjs/styles/grid-themes.css +345 -345
  20. package/dist/cjs/styles/sidebar-scrollbar.css +45 -45
  21. package/dist/cjs/styles/tokens.css +712 -712
  22. package/dist/components/chat/multimodal-input.d.ts +11 -1
  23. package/dist/components/chat/multimodal-input.js +2 -2
  24. package/dist/components/dashboard/charts/BoxPlot.js +5 -5
  25. package/dist/components/dashboard/charts/Gantt.js +30 -30
  26. package/dist/components/dashboard/charts/Pareto.js +2 -2
  27. package/dist/components/datagrid/DataGrid.js +10 -10
  28. package/dist/components/datagrid/controls/menu/view/CardView.js +6 -6
  29. package/dist/components/modals/Modal.js +30 -6
  30. package/dist/components/ui/chart.js +4 -4
  31. package/dist/contexts/ThemeContext.js +52 -52
  32. package/dist/lib/api/activity/email/templates.js +218 -218
  33. package/dist/lib/theme/utils.js +26 -26
  34. package/dist/lib/vision/dieline-extractor.js +76 -76
  35. package/dist/locales/de.json +78 -78
  36. package/dist/locales/en.json +2217 -2217
  37. package/dist/locales/es.json +78 -78
  38. package/dist/locales/fr.json +77 -77
  39. package/dist/locales/hi.json +1599 -1599
  40. package/dist/services/GlobalLoadingService.js +37 -37
  41. package/dist/styles/grid-themes.css +345 -345
  42. package/dist/styles/sidebar-scrollbar.css +45 -45
  43. package/dist/styles/tokens.css +712 -712
  44. package/package.json +196 -196
@@ -1,3 +1,8 @@
1
+ /**
2
+ * Multimodal Input Component
3
+ * Chat input with auto-expanding textarea, file upload, and voice input
4
+ */
5
+ import { type ReactNode } from 'react';
1
6
  /** What the paperclip offers when the host does not say: images, PDFs and documents. */
2
7
  export declare const DEFAULT_CHAT_ACCEPT = "image/*,application/pdf,.doc,.docx,.txt";
3
8
  interface MultimodalInputProps {
@@ -15,9 +20,14 @@ interface MultimodalInputProps {
15
20
  multiple?: boolean;
16
21
  /** Screen-reader name of the paperclip. Default "Attach file". */
17
22
  attachLabel?: string;
23
+ /**
24
+ * The attach button's icon. Default a paperclip; a host whose button opens more than a file
25
+ * picker (a menu, a scan) may pass a plus. Sized by the host, e.g. `<Plus className="w-4 h-4" />`.
26
+ */
27
+ attachIcon?: ReactNode;
18
28
  compact?: boolean;
19
29
  disabled?: boolean;
20
30
  disabledReason?: string;
21
31
  }
22
- export declare function MultimodalInput({ onSubmit, onStop, isLoading, placeholder, allowFileUpload, accept, multiple, attachLabel, compact, disabled, disabledReason }: MultimodalInputProps): import("react").JSX.Element;
32
+ export declare function MultimodalInput({ onSubmit, onStop, isLoading, placeholder, allowFileUpload, accept, multiple, attachLabel, attachIcon, compact, disabled, disabledReason }: MultimodalInputProps): import("react").JSX.Element;
23
33
  export {};
@@ -10,7 +10,7 @@ import { cn } from '../../lib/utils.js';
10
10
  import { useOptionalLanguage } from '../../contexts/LanguageContext.js';
11
11
  /** What the paperclip offers when the host does not say: images, PDFs and documents. */
12
12
  export const DEFAULT_CHAT_ACCEPT = 'image/*,application/pdf,.doc,.docx,.txt';
13
- export function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'Send a message...', allowFileUpload = true, accept = DEFAULT_CHAT_ACCEPT, multiple = true, attachLabel = 'Attach file', compact = false, disabled = false, disabledReason }) {
13
+ export function MultimodalInput({ onSubmit, onStop, isLoading = false, placeholder = 'Send a message...', allowFileUpload = true, accept = DEFAULT_CHAT_ACCEPT, multiple = true, attachLabel = 'Attach file', attachIcon, compact = false, disabled = false, disabledReason }) {
14
14
  // Optional: the composer is exported for host apps that have no LanguageProvider, and falls
15
15
  // back to the English source text rather than throwing.
16
16
  const { t } = useOptionalLanguage();
@@ -110,7 +110,7 @@ export function MultimodalInput({ onSubmit, onStop, isLoading = false, placehold
110
110
  const removeFile = (index) => {
111
111
  setFiles(prev => prev.filter((_, i) => i !== index));
112
112
  };
113
- return (_jsx("div", { className: cn("bg-[rgb(var(--bg-surface))] shrink-0", compact ? "px-1 py-1" : "border-t border-[rgb(var(--bd-default))] px-4 py-2.5"), children: _jsxs("div", { className: "max-w-3xl mx-auto", children: [disabled && disabledReason && (_jsxs("div", { className: "mb-2 px-3 py-2 rounded-lg bg-amber-500/10 border border-amber-500/30 text-xs text-amber-700 dark:text-amber-400 flex items-center gap-2", children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }), _jsx("span", { children: disabledReason })] })), files.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 mb-3", children: files.map((file, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 bg-[rgb(var(--bg-app))] border border-[rgb(var(--bd-default))] rounded-lg text-sm", children: [file.type.startsWith('image/') ? (_jsx(ImageIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : /\.(xlsx|xls|csv)$/i.test(file.name) ? (_jsx(FileSpreadsheet, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : (_jsx(FileIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })), _jsx("span", { className: "text-[rgb(var(--fg-default))] truncate max-w-[150px]", children: file.name }), _jsx("button", { type: "button", onClick: () => removeFile(index), "aria-label": `Remove ${file.name}`, className: "text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors", children: _jsx(X, { className: "w-3 h-3" }) })] }, index))) })), _jsxs("div", { className: cn("relative flex items-center gap-1 bg-[rgb(var(--bg-app))]/60 backdrop-blur-xl border border-[rgb(var(--bd-default))] shadow-lg transition-all duration-250 focus-within:border-[rgb(var(--color-primary))] focus-within:shadow-[0_0_0_4px_rgb(var(--color-primary)/0.12),0_20px_25px_-5px_rgba(0,0,0,0.15)] focus-within:-translate-y-px", compact ? "rounded-xl p-1.5" : "rounded-2xl p-2.5"), children: [allowFileUpload && (_jsxs(_Fragment, { children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: multiple, accept: accept, onChange: handleFileSelect, className: "hidden" }), _jsx("button", { onClick: () => fileInputRef.current?.click(), className: "shrink-0 !min-h-0 w-9 h-9 rounded-lg flex items-center justify-center transition-colors text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]", "aria-label": attachLabel, title: attachLabel, children: _jsx(Paperclip, { className: "w-4 h-4" }) })] })), _jsx("textarea", { ref: textareaRef, "data-chat-input": true, value: input, onChange: (e) => setInput(e.target.value), onKeyDown: handleKeyDown, placeholder: disabled ? t('Conversation closed — start a new chat')
113
+ return (_jsx("div", { className: cn("bg-[rgb(var(--bg-surface))] shrink-0", compact ? "px-1 py-1" : "border-t border-[rgb(var(--bd-default))] px-4 py-2.5"), children: _jsxs("div", { className: "max-w-3xl mx-auto", children: [disabled && disabledReason && (_jsxs("div", { className: "mb-2 px-3 py-2 rounded-lg bg-amber-500/10 border border-amber-500/30 text-xs text-amber-700 dark:text-amber-400 flex items-center gap-2", children: [_jsxs("svg", { width: "14", height: "14", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: "shrink-0", children: [_jsx("circle", { cx: "12", cy: "12", r: "10" }), _jsx("line", { x1: "12", y1: "8", x2: "12", y2: "12" }), _jsx("line", { x1: "12", y1: "16", x2: "12.01", y2: "16" })] }), _jsx("span", { children: disabledReason })] })), files.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-2 mb-3", children: files.map((file, index) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2 bg-[rgb(var(--bg-app))] border border-[rgb(var(--bd-default))] rounded-lg text-sm", children: [file.type.startsWith('image/') ? (_jsx(ImageIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : /\.(xlsx|xls|csv)$/i.test(file.name) ? (_jsx(FileSpreadsheet, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })) : (_jsx(FileIcon, { className: "w-4 h-4 text-[rgb(var(--fg-muted))]" })), _jsx("span", { className: "text-[rgb(var(--fg-default))] truncate max-w-[150px]", children: file.name }), _jsx("button", { type: "button", onClick: () => removeFile(index), "aria-label": `Remove ${file.name}`, className: "text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] transition-colors", children: _jsx(X, { className: "w-3 h-3" }) })] }, index))) })), _jsxs("div", { className: cn("relative flex items-center gap-1 bg-[rgb(var(--bg-app))]/60 backdrop-blur-xl border border-[rgb(var(--bd-default))] shadow-lg transition-all duration-250 focus-within:border-[rgb(var(--color-primary))] focus-within:shadow-[0_0_0_4px_rgb(var(--color-primary)/0.12),0_20px_25px_-5px_rgba(0,0,0,0.15)] focus-within:-translate-y-px", compact ? "rounded-xl p-1.5" : "rounded-2xl p-2.5"), children: [allowFileUpload && (_jsxs(_Fragment, { children: [_jsx("input", { ref: fileInputRef, type: "file", multiple: multiple, accept: accept, onChange: handleFileSelect, className: "hidden" }), _jsx("button", { onClick: () => fileInputRef.current?.click(), className: "shrink-0 !min-h-0 w-9 h-9 rounded-lg flex items-center justify-center transition-colors text-[rgb(var(--fg-muted))] hover:text-[rgb(var(--fg-default))] hover:bg-[rgb(var(--bg-subtle))]", "aria-label": attachLabel, title: attachLabel, children: attachIcon ?? _jsx(Paperclip, { className: "w-4 h-4" }) })] })), _jsx("textarea", { ref: textareaRef, "data-chat-input": true, value: input, onChange: (e) => setInput(e.target.value), onKeyDown: handleKeyDown, placeholder: disabled ? t('Conversation closed — start a new chat')
114
114
  : isListening ? t('Listening...')
115
115
  : placeholder, disabled: isListening || disabled, autoFocus: !disabled, rows: 1, className: cn('flex-1 bg-transparent text-[rgb(var(--fg-default))] placeholder:text-[rgb(var(--fg-muted))]', 'resize-none outline-none text-sm', compact ? 'px-2 py-1.5 max-h-[120px]' : 'px-3 py-2.5 max-h-[200px]', 'overflow-y-auto', disabled && 'cursor-not-allowed') }), speechSupported && (_jsx("button", { onClick: handleVoiceInput, className: cn('shrink-0 !min-h-0 w-9 h-9 rounded-lg flex items-center justify-center transition-colors', isListening
116
116
  ? 'text-red-500 bg-red-500/10 animate-pulse'
@@ -56,11 +56,11 @@ export function BoxPlotChart({ data, height = 300, showLegend = false, color = '
56
56
  formatter: (params) => {
57
57
  if (params.seriesType === 'boxplot') {
58
58
  const [min, q1, median, q3, max] = params.data;
59
- return `<strong>${categories[params.dataIndex]}</strong><br/>
60
- Max: ${max}<br/>
61
- Q3: ${q3}<br/>
62
- Median: ${median}<br/>
63
- Q1: ${q1}<br/>
59
+ return `<strong>${categories[params.dataIndex]}</strong><br/>
60
+ Max: ${max}<br/>
61
+ Q3: ${q3}<br/>
62
+ Median: ${median}<br/>
63
+ Q1: ${q1}<br/>
64
64
  Min: ${min}`;
65
65
  }
66
66
  return `Outlier: ${params.data[1]}`;
@@ -97,36 +97,36 @@ export function GanttChart({ tasks, height = 400, showProgress = true, showToday
97
97
  return '';
98
98
  const duration = getDuration(task.startDate, task.endDate);
99
99
  const progress = task.progress ?? 0;
100
- return `
101
- <div style="padding: 8px; min-width: 180px;">
102
- <div style="font-weight: 600; margin-bottom: 6px; color: ${theme.textColorStrong};">${task.name}</div>
103
- <div style="display: grid; gap: 4px; font-size: 12px;">
104
- <div style="display: flex; justify-content: space-between;">
105
- <span style="color: ${theme.textColor};">Start:</span>
106
- <span style="font-weight: 500;">${formatDate(task.startDate)}</span>
107
- </div>
108
- <div style="display: flex; justify-content: space-between;">
109
- <span style="color: ${theme.textColor};">End:</span>
110
- <span style="font-weight: 500;">${formatDate(task.endDate)}</span>
111
- </div>
112
- <div style="display: flex; justify-content: space-between;">
113
- <span style="color: ${theme.textColor};">Duration:</span>
114
- <span style="font-weight: 500;">${duration} day${duration !== 1 ? 's' : ''}</span>
115
- </div>
116
- ${showProgress ? `
117
- <div style="display: flex; justify-content: space-between;">
118
- <span style="color: ${theme.textColor};">Progress:</span>
119
- <span style="font-weight: 500; color: ${progress >= 100 ? theme.success : progress >= 50 ? theme.warning : theme.info};">${progress}%</span>
120
- </div>
121
- ` : ''}
122
- ${task.category ? `
123
- <div style="display: flex; justify-content: space-between;">
124
- <span style="color: ${theme.textColor};">Category:</span>
125
- <span style="font-weight: 500;">${task.category}</span>
126
- </div>
127
- ` : ''}
128
- </div>
129
- </div>
100
+ return `
101
+ <div style="padding: 8px; min-width: 180px;">
102
+ <div style="font-weight: 600; margin-bottom: 6px; color: ${theme.textColorStrong};">${task.name}</div>
103
+ <div style="display: grid; gap: 4px; font-size: 12px;">
104
+ <div style="display: flex; justify-content: space-between;">
105
+ <span style="color: ${theme.textColor};">Start:</span>
106
+ <span style="font-weight: 500;">${formatDate(task.startDate)}</span>
107
+ </div>
108
+ <div style="display: flex; justify-content: space-between;">
109
+ <span style="color: ${theme.textColor};">End:</span>
110
+ <span style="font-weight: 500;">${formatDate(task.endDate)}</span>
111
+ </div>
112
+ <div style="display: flex; justify-content: space-between;">
113
+ <span style="color: ${theme.textColor};">Duration:</span>
114
+ <span style="font-weight: 500;">${duration} day${duration !== 1 ? 's' : ''}</span>
115
+ </div>
116
+ ${showProgress ? `
117
+ <div style="display: flex; justify-content: space-between;">
118
+ <span style="color: ${theme.textColor};">Progress:</span>
119
+ <span style="font-weight: 500; color: ${progress >= 100 ? theme.success : progress >= 50 ? theme.warning : theme.info};">${progress}%</span>
120
+ </div>
121
+ ` : ''}
122
+ ${task.category ? `
123
+ <div style="display: flex; justify-content: space-between;">
124
+ <span style="color: ${theme.textColor};">Category:</span>
125
+ <span style="font-weight: 500;">${task.category}</span>
126
+ </div>
127
+ ` : ''}
128
+ </div>
129
+ </div>
130
130
  `;
131
131
  }
132
132
  },
@@ -28,8 +28,8 @@ export function ParetoChart({ data, height = 300, showLegend = true, barColor =
28
28
  formatter: (params) => {
29
29
  const bar = params.find((p) => p.seriesType === 'bar');
30
30
  const line = params.find((p) => p.seriesType === 'line');
31
- return `${bar?.name}<br/>
32
- Value: ${formatNumber(bar?.value)}<br/>
31
+ return `${bar?.name}<br/>
32
+ Value: ${formatNumber(bar?.value)}<br/>
33
33
  Cumulative: ${line?.value}%`;
34
34
  }
35
35
  },
@@ -1530,15 +1530,15 @@ enableFilterRow = false, initialColumnFilters, }) {
1530
1530
  e.preventDefault();
1531
1531
  onRowContextMenu(row.original, e);
1532
1532
  }
1533
- }, style: getRowProps?.(row.original)?.style, className: `
1534
- cursor-pointer group
1535
- transition-colors duration-150 ease-out
1533
+ }, style: getRowProps?.(row.original)?.style, className: `
1534
+ cursor-pointer group
1535
+ transition-colors duration-150 ease-out
1536
1536
  ${isHighlighted
1537
1537
  ? 'border-2 border-[rgb(var(--color-primary))] bg-gradient-to-r from-[rgb(var(--color-primary))]/10 to-[rgb(var(--color-primary))]/20 shadow-lg relative'
1538
1538
  : isSelected
1539
1539
  ? 'bg-[color-mix(in_srgb,rgb(var(--color-primary))_8%,rgb(var(--bg-surface)))] shadow-sm hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_15%,rgb(var(--bg-surface)))]'
1540
- : 'hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'}
1541
- ${getRowProps?.(row.original)?.className ?? ''}
1540
+ : 'hover:bg-[color-mix(in_srgb,rgb(var(--color-primary))_5%,rgb(var(--bg-surface)))]'}
1541
+ ${getRowProps?.(row.original)?.className ?? ''}
1542
1542
  `, children: row.getVisibleCells().map((cell, cellIndex) => (_jsx(CellRenderer, { cell: cell, cellIndex: cellIndex, row: row, enableBacchaSearch: enableBacchaSearch, mainColumnsArray: mainColumnsArray, frozenColumnsState: frozenColumnsState, navigationState: navigationState, columnSearches: columnSearches, isColumnSearchActive: isColumnSearchActive, onColumnSearch: handleColumnSearch, onClearColumnSearch: handleClearColumnSearch, SearchHighlighter: SearchHighlighter, InlineSearchCell: InlineSearchCell, isSelected: isSelected }, cell.id))) }, row.id));
1543
1543
  }), rowVirtualizer.getVirtualItems().length > 0 && (_jsx("tr", { children: _jsx("td", { colSpan: table.getVisibleFlatColumns().length, style: {
1544
1544
  height: `${rowVirtualizer.getTotalSize() -
@@ -1554,15 +1554,15 @@ enableFilterRow = false, initialColumnFilters, }) {
1554
1554
  e.preventDefault();
1555
1555
  onRowContextMenu(row.original, e);
1556
1556
  }
1557
- }, rowHeight: rowHeight, style: getRowProps?.(row.original)?.style, className: `
1558
- cursor-pointer group
1559
- transition-colors duration-150 ease-out
1557
+ }, rowHeight: rowHeight, style: getRowProps?.(row.original)?.style, className: `
1558
+ cursor-pointer group
1559
+ transition-colors duration-150 ease-out
1560
1560
  ${isHighlighted
1561
1561
  ? 'border-2 border-primary bg-gradient-to-r from-primary/10 to-primary/20 shadow-lg relative z-10'
1562
1562
  : isSelected
1563
1563
  ? 'bg-[rgb(var(--bg-selected))] shadow-sm hover:bg-[rgb(var(--bg-hover))]'
1564
- : 'hover:bg-[rgb(var(--bg-hover))]'}
1565
- ${getRowProps?.(row.original)?.className ?? ''}
1564
+ : 'hover:bg-[rgb(var(--bg-hover))]'}
1565
+ ${getRowProps?.(row.original)?.className ?? ''}
1566
1566
  `, children: row.getVisibleCells().map((cell, cellIndex) => (_jsx(CellRenderer, { cell: cell, cellIndex: cellIndex, row: row, enableBacchaSearch: enableBacchaSearch, mainColumnsArray: mainColumnsArray, frozenColumnsState: frozenColumnsState, navigationState: navigationState, columnSearches: columnSearches, isColumnSearchActive: isColumnSearchActive, onColumnSearch: handleColumnSearch, onClearColumnSearch: handleClearColumnSearch, SearchHighlighter: SearchHighlighter, InlineSearchCell: InlineSearchCell, isSelected: isSelected }, cell.id))) }, row.id));
1567
1567
  })) })) }));
1568
1568
  })() }), enableSummary && summaryConfig && (_jsx(SummaryRow, { table: table, data: processedData, config: summaryConfig, enableRowSelection: enableRowSelection, showDragHandle: isRowReorderingActive }))] }), !loading && table.getRowModel().rows.length === 0 && (_jsx("div", { className: "absolute left-0 right-0 bottom-0 flex items-center justify-center pointer-events-none z-10", style: { top: '44px' }, children: _jsx("span", { className: "text-[rgb(var(--fg-muted))] text-sm", children: "No data available" }) }))] }) }));
@@ -152,14 +152,14 @@ export function CardView({ data, columns, onRowClick, selectedRows, onRowSelect,
152
152
  return (_jsxs("div", { ref: containerRef, className: "outline-none", tabIndex: 0, onKeyDown: handleKeyDown, children: [_jsx("div", { className: cfg.pad, children: _jsx("div", { className: `grid ${cfg.grid} ${cfg.gap}`, children: _jsx(AnimatePresence, { initial: false, children: data.map((item, index) => {
153
153
  const isFocused = focusedIndex === index;
154
154
  const itemSelected = isSelected(item);
155
- return (_jsx(motion.div, { ref: (el) => { cardRefs.current[index] = el; }, initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -6 }, transition: { duration: 0.12, delay: Math.min(index * 0.015, 0.15) }, className: "group/card outline-none", tabIndex: -1, onClick: () => setFocusedIndex(index), onDoubleClick: () => handleCardClick(item), children: _jsxs("div", { className: `
156
- relative rounded-lg border bg-[rgb(var(--bg-surface))] overflow-hidden h-full
157
- transition-all duration-150
155
+ return (_jsx(motion.div, { ref: (el) => { cardRefs.current[index] = el; }, initial: { opacity: 0, y: 6 }, animate: { opacity: 1, y: 0 }, exit: { opacity: 0, y: -6 }, transition: { duration: 0.12, delay: Math.min(index * 0.015, 0.15) }, className: "group/card outline-none", tabIndex: -1, onClick: () => setFocusedIndex(index), onDoubleClick: () => handleCardClick(item), children: _jsxs("div", { className: `
156
+ relative rounded-lg border bg-[rgb(var(--bg-surface))] overflow-hidden h-full
157
+ transition-all duration-150
158
158
  ${itemSelected
159
159
  ? 'border-[rgb(var(--color-primary))] shadow-sm'
160
- : 'border-[rgb(var(--bd-default))] hover:border-[rgb(var(--color-primary))]/40 hover:shadow-sm'}
161
- ${isFocused ? 'ring-2 ring-[rgb(var(--color-primary))]/30 ring-offset-1' : ''}
162
- ${getCardClassName?.(item) ?? ''}
160
+ : 'border-[rgb(var(--bd-default))] hover:border-[rgb(var(--color-primary))]/40 hover:shadow-sm'}
161
+ ${isFocused ? 'ring-2 ring-[rgb(var(--color-primary))]/30 ring-offset-1' : ''}
162
+ ${getCardClassName?.(item) ?? ''}
163
163
  `, children: [_jsx("div", { className: `absolute left-0 top-0 bottom-0 w-[2px] transition-colors duration-150 ${itemSelected ? 'bg-[rgb(var(--color-primary))]' : 'bg-transparent group-hover/card:bg-[rgb(var(--color-primary))]/30'}` }), _jsxs("div", { className: "pl-3 pr-2.5 py-2.5", children: [_jsxs("div", { className: "flex items-center gap-2", children: [onRowSelect && (_jsx("div", { className: "flex-shrink-0", onClick: (e) => e.stopPropagation(), children: _jsx(SelectionCheckbox, { checked: itemSelected, onChange: (checked) => handleCheckboxChange(item, checked), circular: circularCheckboxes, mode: "checkbox" }) })), _jsxs("div", { className: "flex-1 min-w-0 flex items-baseline gap-1.5", children: [_jsx("p", { className: `${cfg.titleText} font-semibold text-[rgb(var(--fg-default))] truncate leading-tight`, children: displayColumns.length > 0 && getDisplayValue(item, displayColumns[0].accessorKey) }), displayColumns.length > 1 && (_jsx("p", { className: `${cfg.subtitleText} text-[rgb(var(--color-primary))] font-medium truncate flex-shrink-0`, children: getDisplayValue(item, displayColumns[1].accessorKey) }))] }), _jsx("div", { className: "flex-shrink-0 opacity-0 group-hover/card:opacity-100 transition-opacity duration-150", onClick: (e) => e.stopPropagation(), children: actionsColumn && actionsColumn.cell?.({
164
164
  row: { original: item },
165
165
  getValue: () => null,
@@ -115,6 +115,12 @@ function Modal({ open, onOpenChange, ...props }) {
115
115
  const childRegistry = React.useCallback((delta) => {
116
116
  childOpenCountRef.current += delta;
117
117
  }, []);
118
+ // The sentinel outlives one run of the effect below: React Strict Mode runs it, cleans it up and
119
+ // runs it again at once in development. Retracting in that cleanup meant a `history.back()` that
120
+ // landed after the replay had pushed a new sentinel, popped that one, and read as a back press:
121
+ // every modal on a phone closed itself a moment after opening. So the cleanup only marks it for
122
+ // retraction, a replay in the same tick takes it back, and the retraction happens a microtask later.
123
+ const sentinelRef = React.useRef(null);
118
124
  React.useEffect(() => {
119
125
  if (!open)
120
126
  return;
@@ -125,8 +131,17 @@ function Modal({ open, onOpenChange, ...props }) {
125
131
  // Push a sentinel tagged with THIS modal's identity, so we can tell our own
126
132
  // dismissal apart from a nested child retracting its entry. Without the id
127
133
  // the parent closes too when a child modal applies or cancels.
128
- const id = ++modalSentinelSeq;
129
- window.history.pushState({ __modal: true, __modalId: id }, '');
134
+ let sentinel = sentinelRef.current;
135
+ if (sentinel?.retracting) {
136
+ sentinel.retracting = false;
137
+ }
138
+ else {
139
+ sentinel = { id: ++modalSentinelSeq, retracting: false };
140
+ sentinelRef.current = sentinel;
141
+ window.history.pushState({ __modal: true, __modalId: sentinel.id }, '');
142
+ }
143
+ const mine = sentinel;
144
+ const id = mine.id;
130
145
  let selfPopped = false;
131
146
  const onPopState = () => {
132
147
  // React only when OUR sentinel is the one that just left the stack.
@@ -150,12 +165,21 @@ function Modal({ open, onOpenChange, ...props }) {
150
165
  // Closing normally (Apply / Cancel / X) — retract our own sentinel so the
151
166
  // history stack doesn't grow. If the back button already popped it,
152
167
  // calling back() again would navigate the real page away.
153
- if (selfPopped)
168
+ if (selfPopped) {
169
+ sentinelRef.current = null;
154
170
  return;
155
- const state = window.history.state;
156
- if (state && state.__modal && state.__modalId === id) {
157
- window.history.back();
158
171
  }
172
+ mine.retracting = true;
173
+ queueMicrotask(() => {
174
+ if (!mine.retracting)
175
+ return;
176
+ if (sentinelRef.current === mine)
177
+ sentinelRef.current = null;
178
+ const state = window.history.state;
179
+ if (state && state.__modal && state.__modalId === id) {
180
+ window.history.back();
181
+ }
182
+ });
159
183
  };
160
184
  }, [open]);
161
185
  return (_jsx(ModalHasOpenChildContext.Provider, { value: childOpenCountRef, children: _jsx(ModalDepthContext.Provider, { value: depth, children: _jsx(ModalChildRegistryContext.Provider, { value: childRegistry, children: _jsx(DialogPrimitive.Root, { open: open, onOpenChange: handleOpenChange, ...props }) }) }) }));
@@ -26,16 +26,16 @@ const ChartStyle = ({ id, config }) => {
26
26
  }
27
27
  return (_jsx("style", { dangerouslySetInnerHTML: {
28
28
  __html: Object.entries(THEMES)
29
- .map(([theme, prefix]) => `
30
- ${prefix} [data-chart=${id}] {
29
+ .map(([theme, prefix]) => `
30
+ ${prefix} [data-chart=${id}] {
31
31
  ${colorConfig
32
32
  .map(([key, itemConfig]) => {
33
33
  const color = itemConfig.theme?.[theme] ||
34
34
  itemConfig.color;
35
35
  return color ? ` --color-${key}: ${color};` : null;
36
36
  })
37
- .join('\n')}
38
- }
37
+ .join('\n')}
38
+ }
39
39
  `)
40
40
  .join('\n'),
41
41
  } }));
@@ -50,58 +50,58 @@ export function ThemeProvider({ children, defaultTheme = { variant: 'default', m
50
50
  * ```
51
51
  */
52
52
  export function ThemeScript({ storageKey = THEME_CONFIG.storageKey, defaultTheme = 'default', defaultMode = 'light' }) {
53
- const script = `
54
- (function() {
55
- try {
56
- // Get saved theme or use default - no system detection
57
- var savedTheme;
58
- try {
59
- savedTheme = JSON.parse(localStorage.getItem('${storageKey}'));
60
- } catch (e) {
61
- savedTheme = null;
62
- }
63
-
64
- // Force light theme with default variant - this is hardcoded
65
- var mode = 'light';
66
- var variant = 'default';
67
-
68
- // Always use default light theme, no exceptions
69
-
70
- // Remove any existing theme classes
71
- var html = document.documentElement;
72
- var classList = html.classList;
73
- var classesToRemove = [];
74
- for (var i = 0; i < classList.length; i++) {
75
- var className = classList[i];
76
- if (className.startsWith('theme-') || className === 'light' || className === 'dark') {
77
- classesToRemove.push(className);
78
- }
79
- }
80
- classesToRemove.forEach(function(className) {
81
- html.classList.remove(className);
82
- });
83
-
84
- // Add new theme classes
85
- html.classList.add('theme-' + variant, mode);
86
-
87
- // CSS variables are handled by CSS classes, no need to set them here
88
- } catch (e) {
89
- // Fallback: ensure we have default classes
90
- var html = document.documentElement;
91
- var classList = html.classList;
92
- var classesToRemove = [];
93
- for (var i = 0; i < classList.length; i++) {
94
- var className = classList[i];
95
- if (className.startsWith('theme-') || className === 'light' || className === 'dark') {
96
- classesToRemove.push(className);
97
- }
98
- }
99
- classesToRemove.forEach(function(className) {
100
- html.classList.remove(className);
101
- });
102
- html.classList.add('theme-${defaultTheme}', '${defaultMode}');
103
- }
104
- })()
53
+ const script = `
54
+ (function() {
55
+ try {
56
+ // Get saved theme or use default - no system detection
57
+ var savedTheme;
58
+ try {
59
+ savedTheme = JSON.parse(localStorage.getItem('${storageKey}'));
60
+ } catch (e) {
61
+ savedTheme = null;
62
+ }
63
+
64
+ // Force light theme with default variant - this is hardcoded
65
+ var mode = 'light';
66
+ var variant = 'default';
67
+
68
+ // Always use default light theme, no exceptions
69
+
70
+ // Remove any existing theme classes
71
+ var html = document.documentElement;
72
+ var classList = html.classList;
73
+ var classesToRemove = [];
74
+ for (var i = 0; i < classList.length; i++) {
75
+ var className = classList[i];
76
+ if (className.startsWith('theme-') || className === 'light' || className === 'dark') {
77
+ classesToRemove.push(className);
78
+ }
79
+ }
80
+ classesToRemove.forEach(function(className) {
81
+ html.classList.remove(className);
82
+ });
83
+
84
+ // Add new theme classes
85
+ html.classList.add('theme-' + variant, mode);
86
+
87
+ // CSS variables are handled by CSS classes, no need to set them here
88
+ } catch (e) {
89
+ // Fallback: ensure we have default classes
90
+ var html = document.documentElement;
91
+ var classList = html.classList;
92
+ var classesToRemove = [];
93
+ for (var i = 0; i < classList.length; i++) {
94
+ var className = classList[i];
95
+ if (className.startsWith('theme-') || className === 'light' || className === 'dark') {
96
+ classesToRemove.push(className);
97
+ }
98
+ }
99
+ classesToRemove.forEach(function(className) {
100
+ html.classList.remove(className);
101
+ });
102
+ html.classList.add('theme-${defaultTheme}', '${defaultMode}');
103
+ }
104
+ })()
105
105
  `;
106
106
  // suppressHydrationWarning: this inline head script is a known target for
107
107
  // browser extensions (e.g. ad/popup blockers) that overwrite its content or