indas-ui 0.1.7 → 0.1.9
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/cjs/components/dashboard/charts/BoxPlot.js +5 -5
- package/dist/cjs/components/dashboard/charts/Gantt.js +30 -30
- package/dist/cjs/components/dashboard/charts/Pareto.js +2 -2
- package/dist/cjs/components/datagrid/DataGrid.js +10 -10
- package/dist/cjs/components/datagrid/controls/menu/view/CardView.js +6 -6
- package/dist/cjs/components/modals/Modal.js +53 -10
- package/dist/cjs/components/ui/chart.js +4 -4
- package/dist/cjs/contexts/ThemeContext.js +52 -52
- package/dist/cjs/lib/api/activity/email/templates.js +218 -218
- package/dist/cjs/lib/theme/utils.js +26 -26
- package/dist/cjs/lib/vision/dieline-extractor.js +76 -76
- package/dist/cjs/locales/de.json +78 -78
- package/dist/cjs/locales/en.json +2217 -2217
- package/dist/cjs/locales/es.json +78 -78
- package/dist/cjs/locales/fr.json +77 -77
- package/dist/cjs/locales/hi.json +1599 -1599
- package/dist/cjs/services/GlobalLoadingService.js +37 -37
- package/dist/cjs/styles/grid-themes.css +345 -345
- package/dist/cjs/styles/sidebar-scrollbar.css +45 -45
- package/dist/cjs/styles/tokens.css +712 -712
- package/dist/components/dashboard/charts/BoxPlot.js +5 -5
- package/dist/components/dashboard/charts/Gantt.js +30 -30
- package/dist/components/dashboard/charts/Pareto.js +2 -2
- package/dist/components/datagrid/DataGrid.js +10 -10
- package/dist/components/datagrid/controls/menu/view/CardView.js +6 -6
- package/dist/components/modals/Modal.js +53 -10
- package/dist/components/ui/chart.js +4 -4
- package/dist/contexts/ThemeContext.js +52 -52
- package/dist/lib/api/activity/email/templates.js +218 -218
- package/dist/lib/theme/utils.js +26 -26
- package/dist/lib/vision/dieline-extractor.js +76 -76
- package/dist/locales/de.json +78 -78
- package/dist/locales/en.json +2217 -2217
- package/dist/locales/es.json +78 -78
- package/dist/locales/fr.json +77 -77
- package/dist/locales/hi.json +1599 -1599
- package/dist/services/GlobalLoadingService.js +37 -37
- package/dist/styles/grid-themes.css +345 -345
- package/dist/styles/sidebar-scrollbar.css +45 -45
- package/dist/styles/tokens.css +712 -712
- package/package.json +196 -196
|
@@ -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,
|
|
@@ -25,7 +25,11 @@ const modalSizes = {
|
|
|
25
25
|
* @param breakpoint - Pixel width threshold (default 768)
|
|
26
26
|
*/
|
|
27
27
|
export function useIsMobile(breakpoint = 768) {
|
|
28
|
-
|
|
28
|
+
return useMobileQuery(breakpoint) ?? false;
|
|
29
|
+
}
|
|
30
|
+
/** As useIsMobile, but null until the width has been read (the first render, and on the server). */
|
|
31
|
+
function useMobileQuery(breakpoint) {
|
|
32
|
+
const [isMobile, setIsMobile] = React.useState(null);
|
|
29
33
|
React.useEffect(() => {
|
|
30
34
|
const mq = window.matchMedia(`(max-width: ${breakpoint}px)`);
|
|
31
35
|
setIsMobile(mq.matches);
|
|
@@ -111,6 +115,12 @@ function Modal({ open, onOpenChange, ...props }) {
|
|
|
111
115
|
const childRegistry = React.useCallback((delta) => {
|
|
112
116
|
childOpenCountRef.current += delta;
|
|
113
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);
|
|
114
124
|
React.useEffect(() => {
|
|
115
125
|
if (!open)
|
|
116
126
|
return;
|
|
@@ -121,8 +131,17 @@ function Modal({ open, onOpenChange, ...props }) {
|
|
|
121
131
|
// Push a sentinel tagged with THIS modal's identity, so we can tell our own
|
|
122
132
|
// dismissal apart from a nested child retracting its entry. Without the id
|
|
123
133
|
// the parent closes too when a child modal applies or cancels.
|
|
124
|
-
|
|
125
|
-
|
|
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;
|
|
126
145
|
let selfPopped = false;
|
|
127
146
|
const onPopState = () => {
|
|
128
147
|
// React only when OUR sentinel is the one that just left the stack.
|
|
@@ -146,12 +165,21 @@ function Modal({ open, onOpenChange, ...props }) {
|
|
|
146
165
|
// Closing normally (Apply / Cancel / X) — retract our own sentinel so the
|
|
147
166
|
// history stack doesn't grow. If the back button already popped it,
|
|
148
167
|
// calling back() again would navigate the real page away.
|
|
149
|
-
if (selfPopped)
|
|
168
|
+
if (selfPopped) {
|
|
169
|
+
sentinelRef.current = null;
|
|
150
170
|
return;
|
|
151
|
-
const state = window.history.state;
|
|
152
|
-
if (state && state.__modal && state.__modalId === id) {
|
|
153
|
-
window.history.back();
|
|
154
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
|
+
});
|
|
155
183
|
};
|
|
156
184
|
}, [open]);
|
|
157
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 }) }) }) }));
|
|
@@ -198,7 +226,22 @@ ModalOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
|
198
226
|
*/
|
|
199
227
|
const ModalContent = React.forwardRef(({ className, children, hideCloseButton, disableOutsideClick, size, style, 'aria-describedby': ariaDescribedBy, ...props }, ref) => {
|
|
200
228
|
const stableRef = useStableRef(ref);
|
|
201
|
-
|
|
229
|
+
// The page and the dialog are different trees, so switching between them remounts everything
|
|
230
|
+
// inside: a form half filled in was wiped when a tablet turned, or a window was dragged, across
|
|
231
|
+
// the breakpoint. So the layout follows the screen only while closed; open, it keeps the one it
|
|
232
|
+
// opened with, and catches up once closed. The content exists only while open, so its ref says.
|
|
233
|
+
const live = useMobileQuery(768);
|
|
234
|
+
const [open, setOpen] = React.useState(false);
|
|
235
|
+
const [held, setHeld] = React.useState(null);
|
|
236
|
+
// The first reading always counts: before it the width is unknown, and a modal open at page load
|
|
237
|
+
// on a phone must still become the page.
|
|
238
|
+
if (live !== null && held !== live && (held === null || !open))
|
|
239
|
+
setHeld(live);
|
|
240
|
+
const isMobile = held ?? false;
|
|
241
|
+
const contentRef = React.useCallback((node) => {
|
|
242
|
+
stableRef(node);
|
|
243
|
+
setOpen(node !== null);
|
|
244
|
+
}, [stableRef]);
|
|
202
245
|
// Nested modals must paint above their parent. Radix portals every modal to
|
|
203
246
|
// <body>, so equal z-index makes stacking fall back to DOM order and the
|
|
204
247
|
// child renders behind / overlapping the parent.
|
|
@@ -213,12 +256,12 @@ const ModalContent = React.forwardRef(({ className, children, hideCloseButton, d
|
|
|
213
256
|
}, [hasOpenChild]);
|
|
214
257
|
// On mobile: render as a full-screen page
|
|
215
258
|
if (isMobile) {
|
|
216
|
-
return (_jsx(DialogPrimitive.Portal, { children: _jsx(DialogPrimitive.Content, { ref:
|
|
259
|
+
return (_jsx(DialogPrimitive.Portal, { children: _jsx(DialogPrimitive.Content, { ref: contentRef, "aria-describedby": ariaDescribedBy, style: { zIndex, ...style }, className: cn("fixed inset-0 flex flex-col", "bg-[rgb(var(--bg-surface))]", className),
|
|
217
260
|
// Always block outside click on mobile — there's nothing "outside"
|
|
218
261
|
onInteractOutside: (e) => e.preventDefault(), onEscapeKeyDown: handleEscapeKeyDown, ...props, children: _jsx(ModalMobileContext.Provider, { value: { isMobilePage: true, onClose: undefined }, children: children }) }) }));
|
|
219
262
|
}
|
|
220
263
|
// Desktop: unchanged Radix dialog
|
|
221
|
-
return (_jsxs(ModalPortal, { children: [_jsx(ModalOverlay, { style: { zIndex: zIndex - 1 } }), _jsxs(DialogPrimitive.Content, { ref:
|
|
264
|
+
return (_jsxs(ModalPortal, { children: [_jsx(ModalOverlay, { style: { zIndex: zIndex - 1 } }), _jsxs(DialogPrimitive.Content, { ref: contentRef, "aria-describedby": ariaDescribedBy, style: { zIndex, ...style }, className: cn("fixed left-[50%] top-[50%] grid translate-x-[-50%] translate-y-[-50%]", "border border-[rgb(var(--bd-default))] bg-[rgb(var(--bg-surface))] shadow-lg", "rounded-lg sm:rounded-lg", size ? modalSizes[size] : "max-w-lg w-full mx-4 h-auto max-h-[85vh]",
|
|
222
265
|
// Gap + padding only for standard modals — fullscreen/master/p-0 modals
|
|
223
266
|
// run their own flush header/body/footer layout, so the gap shows as bands.
|
|
224
267
|
size !== 'master' && size !== 'fullscreen' && !className?.includes('p-0') && "gap-3 sm:gap-4 p-4 sm:p-6", className), onInteractOutside: (e) => {
|
|
@@ -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
|