@sybilion/uilib 1.3.2 → 1.3.3
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/esm/components/ui/Chart/lightweight/LightweightForecastChart.js +25 -10
- package/dist/esm/components/ui/ChartAreaInteractive/ChartLines.js +6 -1
- package/dist/esm/components/ui/ChartAreaInteractive/overlays/useForecastColor.js +2 -4
- package/dist/esm/components/ui/Confirm/Confirm.js +30 -0
- package/dist/esm/components/ui/Dialog/Dialog.js +1 -1
- package/dist/esm/components/ui/Dialog/Dialog.styl.js +2 -2
- package/dist/esm/index.js +1 -0
- package/dist/esm/types/src/components/ui/Chart/chartForecastVisualization.types.d.ts +2 -0
- package/dist/esm/types/src/components/ui/ChartAreaInteractive/ChartLines.d.ts +2 -0
- package/dist/esm/types/src/components/ui/Confirm/Confirm.d.ts +2 -0
- package/dist/esm/types/src/components/ui/Confirm/Confirm.types.d.ts +15 -0
- package/dist/esm/types/src/components/ui/Confirm/index.d.ts +2 -0
- package/dist/esm/types/src/docs/pages/ConfirmPage.d.ts +1 -0
- package/dist/esm/types/src/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/components/ui/Chart/chartForecastVisualization.types.ts +2 -0
- package/src/components/ui/Chart/lightweight/LightweightForecastChart.tsx +31 -10
- package/src/components/ui/ChartAreaInteractive/ChartLines.tsx +10 -0
- package/src/components/ui/ChartAreaInteractive/overlays/useForecastColor.ts +5 -5
- package/src/components/ui/Confirm/Confirm.tsx +78 -0
- package/src/components/ui/Confirm/Confirm.types.ts +17 -0
- package/src/components/ui/Confirm/index.ts +3 -0
- package/src/components/ui/Dialog/Dialog.styl +3 -0
- package/src/components/ui/Dialog/Dialog.styl.d.ts +1 -0
- package/src/components/ui/Dialog/Dialog.tsx +5 -1
- package/src/docs/config/webpack.config.js +28 -17
- package/src/docs/pages/ConfirmPage.tsx +63 -0
- package/src/docs/pages/LightweightChartPage.tsx +0 -2
- package/src/docs/registry.ts +6 -0
- package/src/index.ts +1 -0
|
@@ -6,7 +6,7 @@ import { ChartStyle } from '../components/ChartContainer.js';
|
|
|
6
6
|
import { ChartTooltipContent } from '../components/ChartTooltipContent.js';
|
|
7
7
|
import { CustomChartLegend } from '../components/CustomChartLegend/CustomChartLegend.js';
|
|
8
8
|
import { formatDate } from '../tools/formatters.js';
|
|
9
|
-
import { getForecastColor,
|
|
9
|
+
import { getForecastColor, resolveQuantileBandFillForForecastLine } from '../../ChartAreaInteractive/ChartLines.js';
|
|
10
10
|
import { Skeleton } from '../../Skeleton/Skeleton.js';
|
|
11
11
|
import { ensureChartForecastBridge } from '../../../../utils/chartConnectionPoint.js';
|
|
12
12
|
import { createChart, LineSeries, LineType, LineStyle } from 'lightweight-charts';
|
|
@@ -14,6 +14,21 @@ import S from './LightweightForecastChart.styl.js';
|
|
|
14
14
|
import { buildLightweightChartOptions, buildHistoricalLineData, buildForecastLineData, buildQuantileBandCustomData, findNearestChartRow } from './lightweightForecastChart.helpers.js';
|
|
15
15
|
import { QuantileBandPaneView } from './quantileBandCustomSeries.js';
|
|
16
16
|
|
|
17
|
+
function forecastIndexForQuantileBand(band, forecastData) {
|
|
18
|
+
if (!forecastData.length)
|
|
19
|
+
return 0;
|
|
20
|
+
if (band.forecastSeriesId != null) {
|
|
21
|
+
const idx = forecastData.findIndex(f => f.id === band.forecastSeriesId);
|
|
22
|
+
if (idx !== -1)
|
|
23
|
+
return idx;
|
|
24
|
+
}
|
|
25
|
+
return 0;
|
|
26
|
+
}
|
|
27
|
+
function quantileBandFillForConfig(band, forecastData) {
|
|
28
|
+
const fi = forecastIndexForQuantileBand(band, forecastData);
|
|
29
|
+
const lineColor = forecastData[fi]?.color?.toString() ?? getForecastColor(fi);
|
|
30
|
+
return resolveQuantileBandFillForForecastLine(lineColor, fi);
|
|
31
|
+
}
|
|
17
32
|
function clampTooltipTranslate(args) {
|
|
18
33
|
const { coordinate, viewW, viewH, tooltipWidth: tw, tooltipHeight: th, offset, edgeMargin, } = args;
|
|
19
34
|
const minX = edgeMargin;
|
|
@@ -93,10 +108,10 @@ function LightweightForecastChart(props) {
|
|
|
93
108
|
color: f.color?.toString() ?? getForecastColor(index),
|
|
94
109
|
};
|
|
95
110
|
});
|
|
96
|
-
quantileBands?.forEach(
|
|
111
|
+
quantileBands?.forEach(band => {
|
|
97
112
|
base[band.key] = {
|
|
98
113
|
label: band.name,
|
|
99
|
-
color: band
|
|
114
|
+
color: quantileBandFillForConfig(band, forecastData),
|
|
100
115
|
};
|
|
101
116
|
});
|
|
102
117
|
return base;
|
|
@@ -200,8 +215,8 @@ function LightweightForecastChart(props) {
|
|
|
200
215
|
}),
|
|
201
216
|
});
|
|
202
217
|
const bands = new Map();
|
|
203
|
-
quantileBands?.forEach(
|
|
204
|
-
const fill = band
|
|
218
|
+
quantileBands?.forEach(band => {
|
|
219
|
+
const fill = quantileBandFillForConfig(band, forecastData);
|
|
205
220
|
const view = new QuantileBandPaneView({
|
|
206
221
|
fill,
|
|
207
222
|
stroke: band.strokeWidth ? fill : undefined,
|
|
@@ -297,7 +312,7 @@ function LightweightForecastChart(props) {
|
|
|
297
312
|
payload: row,
|
|
298
313
|
});
|
|
299
314
|
});
|
|
300
|
-
bandsCfg?.forEach(
|
|
315
|
+
bandsCfg?.forEach(band => {
|
|
301
316
|
if (hid.has(band.key))
|
|
302
317
|
return;
|
|
303
318
|
const tuple = row[band.key];
|
|
@@ -305,7 +320,7 @@ function LightweightForecastChart(props) {
|
|
|
305
320
|
tuple.length === 2 &&
|
|
306
321
|
typeof tuple[0] === 'number' &&
|
|
307
322
|
typeof tuple[1] === 'number') {
|
|
308
|
-
const color = band
|
|
323
|
+
const color = quantileBandFillForConfig(band, forecastsList);
|
|
309
324
|
payload.push({
|
|
310
325
|
type: 'line',
|
|
311
326
|
name: band.name,
|
|
@@ -366,11 +381,11 @@ function LightweightForecastChart(props) {
|
|
|
366
381
|
for (const [key, api] of model.forecasts.entries()) {
|
|
367
382
|
api.setData(buildForecastLineData(bridgedChartData, key));
|
|
368
383
|
}
|
|
369
|
-
quantileBands?.forEach(
|
|
384
|
+
quantileBands?.forEach(band => {
|
|
370
385
|
const entry = model.bands.get(band.key);
|
|
371
386
|
if (!entry)
|
|
372
387
|
return;
|
|
373
|
-
const fill = band
|
|
388
|
+
const fill = quantileBandFillForConfig(band, forecastData);
|
|
374
389
|
entry.view.updateStyle({
|
|
375
390
|
fill,
|
|
376
391
|
stroke: band.strokeWidth ? fill : undefined,
|
|
@@ -382,7 +397,7 @@ function LightweightForecastChart(props) {
|
|
|
382
397
|
entry.api.setData(buildQuantileBandCustomData(bridgedChartData, band.key));
|
|
383
398
|
});
|
|
384
399
|
scheduleFitTimeScale(model.chart);
|
|
385
|
-
}, [bridgedChartData, quantileBands]);
|
|
400
|
+
}, [bridgedChartData, quantileBands, forecastData]);
|
|
386
401
|
// Visibility toggles
|
|
387
402
|
useEffect(() => {
|
|
388
403
|
const model = modelRef.current;
|
|
@@ -17,6 +17,11 @@ const FORECAST_COLORS_MAP = {
|
|
|
17
17
|
const FORECAST_LINE_COLORS = Object.keys(FORECAST_COLORS_MAP);
|
|
18
18
|
const getForecastColor = (index) => FORECAST_LINE_COLORS[index % FORECAST_LINE_COLORS.length];
|
|
19
19
|
const getForecastQuantileBandColor = (index) => FORECAST_COLORS_MAP[FORECAST_LINE_COLORS[index % FORECAST_LINE_COLORS.length]];
|
|
20
|
+
/** Same tint logic as intervals/threshold overlays: band fill follows forecast line hex when known. */
|
|
21
|
+
function resolveQuantileBandFillForForecastLine(lineColor, forecastIndex) {
|
|
22
|
+
const mapped = FORECAST_COLORS_MAP[lineColor];
|
|
23
|
+
return mapped ?? getForecastQuantileBandColor(forecastIndex);
|
|
24
|
+
}
|
|
20
25
|
// Memoized component for chart lines - only re-renders when data/analyses/hiddenSeries change
|
|
21
26
|
const ChartLines = memo(({ chartData, forecastData, hiddenSeries, isDarkTheme, shouldAnimate, historicalLineColor = isDarkTheme ? '#ffffff' : '#000000', showLegend = true, forecastLineStyle = 'dashed', disableHistoricalAnimation = false, }) => {
|
|
22
27
|
const dotStroke = isDarkTheme ? '#000000' : '#FFFFFF';
|
|
@@ -78,4 +83,4 @@ const ChartLines = memo(({ chartData, forecastData, hiddenSeries, isDarkTheme, s
|
|
|
78
83
|
});
|
|
79
84
|
ChartLines.displayName = 'ChartLines';
|
|
80
85
|
|
|
81
|
-
export { ChartLines, FORECAST_COLORS_MAP, FORECAST_LINE_COLORS, getForecastColor, getForecastQuantileBandColor };
|
|
86
|
+
export { ChartLines, FORECAST_COLORS_MAP, FORECAST_LINE_COLORS, getForecastColor, getForecastQuantileBandColor, resolveQuantileBandFillForForecastLine };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useMemo } from 'react';
|
|
2
2
|
import { DEFAULT_QUANTILE_BAND_COLOR } from '../../Chart/components/QuantileBands.js';
|
|
3
|
-
import { FORECAST_LINE_COLORS,
|
|
3
|
+
import { FORECAST_LINE_COLORS, resolveQuantileBandFillForForecastLine } from '../ChartLines.js';
|
|
4
4
|
|
|
5
5
|
const DEFAULT_FORECAST_COLORS = {
|
|
6
6
|
lineColor: DEFAULT_QUANTILE_BAND_COLOR,
|
|
@@ -20,9 +20,7 @@ function useForecastColor(selectedForecast, forecastData) {
|
|
|
20
20
|
const forecastItem = forecastData[forecastIndex];
|
|
21
21
|
const lineColor = forecastItem.color ||
|
|
22
22
|
FORECAST_LINE_COLORS[forecastIndex % FORECAST_LINE_COLORS.length];
|
|
23
|
-
const quantileBandColor =
|
|
24
|
-
? FORECAST_COLORS_MAP[forecastItem.color]
|
|
25
|
-
: getForecastQuantileBandColor(forecastIndex);
|
|
23
|
+
const quantileBandColor = resolveQuantileBandFillForForecastLine(lineColor, forecastIndex);
|
|
26
24
|
return {
|
|
27
25
|
lineColor,
|
|
28
26
|
quantileBandColor,
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
2
|
+
import { useRef, useEffect, useCallback } from 'react';
|
|
3
|
+
import { Button } from '../Button/Button.js';
|
|
4
|
+
import { Dialog } from '../Dialog/Dialog.js';
|
|
5
|
+
|
|
6
|
+
function Confirm({ children, open, onOpenChange, onConfirm, onCancel, title = 'Confirm', confirmLabel = 'Confirm', cancelLabel = 'Cancel', trigger, disabled, confirmVariant = 'default', }) {
|
|
7
|
+
const closedByConfirmRef = useRef(false);
|
|
8
|
+
useEffect(() => {
|
|
9
|
+
if (open) {
|
|
10
|
+
closedByConfirmRef.current = false;
|
|
11
|
+
}
|
|
12
|
+
}, [open]);
|
|
13
|
+
const handleOpenChange = useCallback((next) => {
|
|
14
|
+
if (!next) {
|
|
15
|
+
if (!closedByConfirmRef.current) {
|
|
16
|
+
onCancel?.();
|
|
17
|
+
}
|
|
18
|
+
closedByConfirmRef.current = false;
|
|
19
|
+
}
|
|
20
|
+
onOpenChange(next);
|
|
21
|
+
}, [onCancel, onOpenChange]);
|
|
22
|
+
const handleConfirm = () => {
|
|
23
|
+
closedByConfirmRef.current = true;
|
|
24
|
+
onConfirm();
|
|
25
|
+
handleOpenChange(false);
|
|
26
|
+
};
|
|
27
|
+
return (jsx(Dialog, { open: open, onOpenChange: handleOpenChange, disabled: disabled, trigger: trigger, title: title, width: "min(fit-content, calc(100vw - var(--p-4)))", content: children, footerAlignment: "between", footer: jsxs(Fragment, { children: [jsx(Button, { type: "button", variant: "outline", onClick: () => handleOpenChange(false), children: cancelLabel }), jsx(Button, { type: "button", variant: confirmVariant, onClick: handleConfirm, children: confirmLabel })] }) }));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { Confirm };
|
|
@@ -118,7 +118,7 @@ function Dialog({ open, onOpenChange, disabled, trigger, title, subtitle, disabl
|
|
|
118
118
|
maxHeight: maxHeight
|
|
119
119
|
? `min(${maxHeight}, calc(100% - var(--p-4)))`
|
|
120
120
|
: null,
|
|
121
|
-
}, children: [(title || subtitle || icon) && (jsx(CardHeader, { icon: icon, title: title, description: subtitle })), !disableCloseButton && (jsx("button", { className: S.dialogClose, onClick: handleCloseClick, "aria-label": "Close dialog", type: "button", children: jsx(XIcon, { size: 16 }) })), content && (jsx(CardContent, { className: contentClassName, noScroll: noScroll, autoScrollBottom: autoScrollBottom, children: content })), footer && (jsx(CardFooter, { className: cn(S[`align-${footerAlignment}`], footerClassName), children: footer }))] })] }));
|
|
121
|
+
}, children: [(title || subtitle || icon) && (jsx(CardHeader, { icon: icon, title: title, description: subtitle })), !disableCloseButton && (jsx("button", { className: S.dialogClose, onClick: handleCloseClick, "aria-label": "Close dialog", type: "button", children: jsx(XIcon, { size: 16 }) })), content && (jsx(CardContent, { className: contentClassName, noScroll: noScroll, autoScrollBottom: autoScrollBottom, children: content })), footer && (jsx(CardFooter, { className: cn(S.footer, S[`align-${footerAlignment}`], footerClassName), children: footer }))] })] }));
|
|
122
122
|
const onTriggerClick = !disabled ? () => onOpenChange(true) : undefined;
|
|
123
123
|
return (jsxs(Fragment, { children: [trigger && jsx("div", { onClick: onTriggerClick, children: trigger }), open && !disabled && createPortal(dialogContent, document.body)] }));
|
|
124
124
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import styleInject from 'style-inject';
|
|
2
2
|
|
|
3
|
-
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.Dialog_dialogOverlay__DE-Lj{backdrop-filter:blur(4px);background-color:var(--background-alpha-700);inset:0;opacity:0;position:fixed;transition:opacity .2s ease-out;z-index:50}.Dialog_dialogOverlay__DE-Lj.Dialog_isOpen__KU869{animation-duration:.2s;animation-fill-mode:forwards;animation-name:Dialog_fadeIn__bMYrw;animation-timing-function:ease-out;opacity:1}.Dialog_dialogContent__9aiOO{border-radius:20px;box-shadow:0 0 0 1px var(--border),0 10px 15px -3px var(--border),0 4px 6px -2px var(--border);display:flex;left:50%;max-height:calc(100% - var(--p-4));opacity:0;position:fixed;top:50%;transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%) scale(.95);transition:all .2s ease-out;width:-moz-fit-content;width:fit-content;z-index:50}.dark .Dialog_dialogContent__9aiOO{box-shadow:0 0 0 1px var(--border),0 10px 15px -3px oklch(0 0 0),0 4px 6px -2px oklch(0 0 0)}.Dialog_dialogContent__9aiOO.Dialog_isOpen__KU869{animation-duration:.2s;animation-fill-mode:forwards;animation-name:Dialog_dialogIn__pAese;animation-timing-function:ease-out;opacity:1;transform:translateX(-50%) translateY(-50%) scale(1)}.Dialog_dialogContent__9aiOO.Dialog_isClosed__iUpMZ{animation-duration:.2s;animation-fill-mode:forwards;animation-name:Dialog_dialogOut__U2hfZ;animation-timing-function:ease-in;opacity:0;pointer-events:none;transform:translateX(-50%) translateY(-50%) scale(.95)}@media (max-width:768px){.Dialog_dialogContent__9aiOO{max-width:calc(100% - var(--p-4));width:calc(100% - var(--p-4))}}.Dialog_size-wide__TgCOo{max-width:calc(100% - var(--p-4))}@media (min-width:768px){.Dialog_size-wide__TgCOo{max-width:80rem}}.Dialog_dialogDescription__vcdnx{color:var(--muted-foreground);font-size:.875rem}.Dialog_dialogClose__v3o4O{align-items:center;background-color:transparent;border:none;border-radius:.125rem;cursor:pointer;display:flex;height:2rem;justify-content:center;opacity:.7;outline:none;position:absolute;right:var(--p-2);top:var(--p-2);transform-origin:center;transition:opacity .2s ease,transform .2s ease;width:2rem;z-index:10}.Dialog_dialogClose__v3o4O:hover{opacity:1;transform:scale(1.1)}.Dialog_dialogClose__v3o4O:focus-visible{box-shadow:0 0 0 2px var(--ring)}.Dialog_dialogClose__v3o4O:disabled{pointer-events:none}.Dialog_dialogContent__9aiOO [data-slot=card-footer]{width:100%}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-left__ml-lG{justify-content:flex-start}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-center__3bzlB{justify-content:center}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-right__uV3uE{justify-content:flex-end}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-between__AFcCs{justify-content:space-between}@keyframes Dialog_fadeIn__bMYrw{0%{opacity:0}to{opacity:1}}@keyframes Dialog_fadeOut__gOjrp{0%{opacity:1}to{opacity:0}}@keyframes Dialog_dialogIn__pAese{0%{opacity:0;transform:translateX(-50%) translateY(-50%) scale(.95)}to{opacity:1;transform:translateX(-50%) translateY(-50%) scale(1)}}@keyframes Dialog_dialogOut__U2hfZ{0%{opacity:1;transform:translateX(-50%) translateY(-50%) scale(1)}to{opacity:0;transform:translateX(-50%) translateY(-50%) scale(.95)}}";
|
|
4
|
-
var S = {"dialogOverlay":"Dialog_dialogOverlay__DE-Lj","isOpen":"Dialog_isOpen__KU869","fadeIn":"Dialog_fadeIn__bMYrw","dialogContent":"Dialog_dialogContent__9aiOO","dialogIn":"Dialog_dialogIn__pAese","isClosed":"Dialog_isClosed__iUpMZ","dialogOut":"Dialog_dialogOut__U2hfZ","size-wide":"Dialog_size-wide__TgCOo","dialogDescription":"Dialog_dialogDescription__vcdnx","dialogClose":"Dialog_dialogClose__v3o4O","align-left":"Dialog_align-left__ml-lG","align-center":"Dialog_align-center__3bzlB","align-right":"Dialog_align-right__uV3uE","align-between":"Dialog_align-between__AFcCs","fadeOut":"Dialog_fadeOut__gOjrp"};
|
|
3
|
+
var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.Dialog_dialogOverlay__DE-Lj{backdrop-filter:blur(4px);background-color:var(--background-alpha-700);inset:0;opacity:0;position:fixed;transition:opacity .2s ease-out;z-index:50}.Dialog_dialogOverlay__DE-Lj.Dialog_isOpen__KU869{animation-duration:.2s;animation-fill-mode:forwards;animation-name:Dialog_fadeIn__bMYrw;animation-timing-function:ease-out;opacity:1}.Dialog_dialogContent__9aiOO{border-radius:20px;box-shadow:0 0 0 1px var(--border),0 10px 15px -3px var(--border),0 4px 6px -2px var(--border);display:flex;left:50%;max-height:calc(100% - var(--p-4));opacity:0;position:fixed;top:50%;transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%) scale(.95);transition:all .2s ease-out;width:-moz-fit-content;width:fit-content;z-index:50}.dark .Dialog_dialogContent__9aiOO{box-shadow:0 0 0 1px var(--border),0 10px 15px -3px oklch(0 0 0),0 4px 6px -2px oklch(0 0 0)}.Dialog_dialogContent__9aiOO.Dialog_isOpen__KU869{animation-duration:.2s;animation-fill-mode:forwards;animation-name:Dialog_dialogIn__pAese;animation-timing-function:ease-out;opacity:1;transform:translateX(-50%) translateY(-50%) scale(1)}.Dialog_dialogContent__9aiOO.Dialog_isClosed__iUpMZ{animation-duration:.2s;animation-fill-mode:forwards;animation-name:Dialog_dialogOut__U2hfZ;animation-timing-function:ease-in;opacity:0;pointer-events:none;transform:translateX(-50%) translateY(-50%) scale(.95)}@media (max-width:768px){.Dialog_dialogContent__9aiOO{max-width:calc(100% - var(--p-4));width:calc(100% - var(--p-4))}}.Dialog_size-wide__TgCOo{max-width:calc(100% - var(--p-4))}@media (min-width:768px){.Dialog_size-wide__TgCOo{max-width:80rem}}.Dialog_dialogDescription__vcdnx{color:var(--muted-foreground);font-size:.875rem}.Dialog_dialogClose__v3o4O{align-items:center;background-color:transparent;border:none;border-radius:.125rem;cursor:pointer;display:flex;height:2rem;justify-content:center;opacity:.7;outline:none;position:absolute;right:var(--p-2);top:var(--p-2);transform-origin:center;transition:opacity .2s ease,transform .2s ease;width:2rem;z-index:10}.Dialog_dialogClose__v3o4O:hover{opacity:1;transform:scale(1.1)}.Dialog_dialogClose__v3o4O:focus-visible{box-shadow:0 0 0 2px var(--ring)}.Dialog_dialogClose__v3o4O:disabled{pointer-events:none}.Dialog_dialogContent__9aiOO [data-slot=card-footer]{width:100%}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-left__ml-lG{justify-content:flex-start}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-center__3bzlB{justify-content:center}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-right__uV3uE{justify-content:flex-end}.Dialog_dialogContent__9aiOO [data-slot=card-footer].Dialog_align-between__AFcCs{justify-content:space-between}.Dialog_footer__7U5vn button:not(:last-child){margin-right:var(--p-2)}@keyframes Dialog_fadeIn__bMYrw{0%{opacity:0}to{opacity:1}}@keyframes Dialog_fadeOut__gOjrp{0%{opacity:1}to{opacity:0}}@keyframes Dialog_dialogIn__pAese{0%{opacity:0;transform:translateX(-50%) translateY(-50%) scale(.95)}to{opacity:1;transform:translateX(-50%) translateY(-50%) scale(1)}}@keyframes Dialog_dialogOut__U2hfZ{0%{opacity:1;transform:translateX(-50%) translateY(-50%) scale(1)}to{opacity:0;transform:translateX(-50%) translateY(-50%) scale(.95)}}";
|
|
4
|
+
var S = {"dialogOverlay":"Dialog_dialogOverlay__DE-Lj","isOpen":"Dialog_isOpen__KU869","fadeIn":"Dialog_fadeIn__bMYrw","dialogContent":"Dialog_dialogContent__9aiOO","dialogIn":"Dialog_dialogIn__pAese","isClosed":"Dialog_isClosed__iUpMZ","dialogOut":"Dialog_dialogOut__U2hfZ","size-wide":"Dialog_size-wide__TgCOo","dialogDescription":"Dialog_dialogDescription__vcdnx","dialogClose":"Dialog_dialogClose__v3o4O","align-left":"Dialog_align-left__ml-lG","align-center":"Dialog_align-center__3bzlB","align-right":"Dialog_align-right__uV3uE","align-between":"Dialog_align-between__AFcCs","footer":"Dialog_footer__7U5vn","fadeOut":"Dialog_fadeOut__gOjrp"};
|
|
5
5
|
styleInject(css_248z);
|
|
6
6
|
|
|
7
7
|
export { S as default };
|
package/dist/esm/index.js
CHANGED
|
@@ -28,6 +28,7 @@ export { ChatPresets } from './components/ui/Chat/ChatPresets/ChatPresets.js';
|
|
|
28
28
|
export { MessageRole } from './components/ui/Chat/Chat.types.js';
|
|
29
29
|
export { CsvIcon } from './components/icons/CsvIcon/CsvIcon.js';
|
|
30
30
|
export { Checkbox } from './components/ui/Checkbox/Checkbox.js';
|
|
31
|
+
export { Confirm } from './components/ui/Confirm/Confirm.js';
|
|
31
32
|
export { Dialog } from './components/ui/Dialog/Dialog.js';
|
|
32
33
|
export { Drawer, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerOverlay, DrawerPortal, DrawerTitle, DrawerTrigger } from './components/ui/Drawer/Drawer.js';
|
|
33
34
|
export { DropdownMenu, DropdownMenuCheckboxItem, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLabel, DropdownMenuPortal, DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator, DropdownMenuShortcut, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger, DropdownMenuTrigger } from './components/ui/DropdownMenu/DropdownMenu.js';
|
|
@@ -72,6 +72,8 @@ export interface ForecastVisualizationRow {
|
|
|
72
72
|
}
|
|
73
73
|
export interface QuantileBandConfig {
|
|
74
74
|
key: string;
|
|
75
|
+
/** When set, band fill follows this forecast series line color (LW chart). */
|
|
76
|
+
forecastSeriesId?: number;
|
|
75
77
|
quantiles: [string, string];
|
|
76
78
|
opacity: number;
|
|
77
79
|
color?: string;
|
|
@@ -32,6 +32,8 @@ export declare const FORECAST_COLORS_MAP: {
|
|
|
32
32
|
export declare const FORECAST_LINE_COLORS: string[];
|
|
33
33
|
export declare const getForecastColor: (index: number) => string;
|
|
34
34
|
export declare const getForecastQuantileBandColor: (index: number) => any;
|
|
35
|
+
/** Same tint logic as intervals/threshold overlays: band fill follows forecast line hex when known. */
|
|
36
|
+
export declare function resolveQuantileBandFillForForecastLine(lineColor: string, forecastIndex: number): string;
|
|
35
37
|
export declare const ChartLines: import("react").MemoExoticComponent<({ chartData, forecastData, hiddenSeries, isDarkTheme, shouldAnimate, historicalLineColor, showLegend, forecastLineStyle, disableHistoricalAnimation, }: {
|
|
36
38
|
chartData: ChartDataPoint[];
|
|
37
39
|
forecastData?: ForecastItemData[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
import type { ButtonVariant } from '#uilib/components/ui/Button/Button.types';
|
|
3
|
+
export interface ConfirmProps {
|
|
4
|
+
children: ReactNode;
|
|
5
|
+
open: boolean;
|
|
6
|
+
onOpenChange: (open: boolean) => void;
|
|
7
|
+
onConfirm: () => void;
|
|
8
|
+
onCancel?: () => void;
|
|
9
|
+
title?: ReactNode;
|
|
10
|
+
confirmLabel?: string;
|
|
11
|
+
cancelLabel?: string;
|
|
12
|
+
trigger?: ReactNode;
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
confirmVariant?: Extract<ButtonVariant, 'default' | 'destructive'>;
|
|
15
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export default function ConfirmPage(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -17,6 +17,7 @@ export * from './components/ui/Chart';
|
|
|
17
17
|
export * from './components/ui/ChartAreaInteractive';
|
|
18
18
|
export * from './components/ui/Chat';
|
|
19
19
|
export * from './components/ui/Checkbox';
|
|
20
|
+
export * from './components/ui/Confirm';
|
|
20
21
|
export * from './components/ui/Dialog';
|
|
21
22
|
export * from './components/ui/Drawer';
|
|
22
23
|
export * from './components/ui/DropdownMenu';
|
package/package.json
CHANGED
|
@@ -78,6 +78,8 @@ export interface ForecastVisualizationRow {
|
|
|
78
78
|
|
|
79
79
|
export interface QuantileBandConfig {
|
|
80
80
|
key: string;
|
|
81
|
+
/** When set, band fill follows this forecast series line color (LW chart). */
|
|
82
|
+
forecastSeriesId?: number;
|
|
81
83
|
quantiles: [string, string];
|
|
82
84
|
opacity: number;
|
|
83
85
|
color?: string;
|
|
@@ -19,7 +19,7 @@ import type { ChartDataPoint } from '#uilib/components/ui/ChartAreaInteractive/C
|
|
|
19
19
|
import {
|
|
20
20
|
ForecastItemData,
|
|
21
21
|
getForecastColor,
|
|
22
|
-
|
|
22
|
+
resolveQuantileBandFillForForecastLine,
|
|
23
23
|
} from '#uilib/components/ui/ChartAreaInteractive/ChartLines';
|
|
24
24
|
import { Skeleton } from '#uilib/components/ui/Skeleton';
|
|
25
25
|
import { ensureChartForecastBridge } from '#uilib/utils/chartConnectionPoint';
|
|
@@ -55,6 +55,27 @@ type TooltipRow = {
|
|
|
55
55
|
dataKey?: string;
|
|
56
56
|
};
|
|
57
57
|
|
|
58
|
+
function forecastIndexForQuantileBand(
|
|
59
|
+
band: QuantileBandConfig,
|
|
60
|
+
forecastData: ForecastItemData[],
|
|
61
|
+
): number {
|
|
62
|
+
if (!forecastData.length) return 0;
|
|
63
|
+
if (band.forecastSeriesId != null) {
|
|
64
|
+
const idx = forecastData.findIndex(f => f.id === band.forecastSeriesId);
|
|
65
|
+
if (idx !== -1) return idx;
|
|
66
|
+
}
|
|
67
|
+
return 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function quantileBandFillForConfig(
|
|
71
|
+
band: QuantileBandConfig,
|
|
72
|
+
forecastData: ForecastItemData[],
|
|
73
|
+
): string {
|
|
74
|
+
const fi = forecastIndexForQuantileBand(band, forecastData);
|
|
75
|
+
const lineColor = forecastData[fi]?.color?.toString() ?? getForecastColor(fi);
|
|
76
|
+
return resolveQuantileBandFillForForecastLine(lineColor, fi);
|
|
77
|
+
}
|
|
78
|
+
|
|
58
79
|
function clampTooltipTranslate(args: {
|
|
59
80
|
coordinate: { x: number; y: number };
|
|
60
81
|
viewW: number;
|
|
@@ -218,10 +239,10 @@ export function LightweightForecastChart(props: LightweightForecastChartProps) {
|
|
|
218
239
|
};
|
|
219
240
|
});
|
|
220
241
|
|
|
221
|
-
quantileBands?.forEach(
|
|
242
|
+
quantileBands?.forEach(band => {
|
|
222
243
|
base[band.key] = {
|
|
223
244
|
label: band.name,
|
|
224
|
-
color: band
|
|
245
|
+
color: quantileBandFillForConfig(band, forecastData),
|
|
225
246
|
};
|
|
226
247
|
});
|
|
227
248
|
|
|
@@ -353,8 +374,8 @@ export function LightweightForecastChart(props: LightweightForecastChartProps) {
|
|
|
353
374
|
{ api: ISeriesApi<'Custom'>; view: QuantileBandPaneView }
|
|
354
375
|
>();
|
|
355
376
|
|
|
356
|
-
quantileBands?.forEach(
|
|
357
|
-
const fill = band
|
|
377
|
+
quantileBands?.forEach(band => {
|
|
378
|
+
const fill = quantileBandFillForConfig(band, forecastData);
|
|
358
379
|
const view = new QuantileBandPaneView({
|
|
359
380
|
fill,
|
|
360
381
|
stroke: band.strokeWidth ? fill : undefined,
|
|
@@ -460,7 +481,7 @@ export function LightweightForecastChart(props: LightweightForecastChartProps) {
|
|
|
460
481
|
});
|
|
461
482
|
});
|
|
462
483
|
|
|
463
|
-
bandsCfg?.forEach(
|
|
484
|
+
bandsCfg?.forEach(band => {
|
|
464
485
|
if (hid.has(band.key)) return;
|
|
465
486
|
const tuple = row[band.key];
|
|
466
487
|
if (
|
|
@@ -469,7 +490,7 @@ export function LightweightForecastChart(props: LightweightForecastChartProps) {
|
|
|
469
490
|
typeof tuple[0] === 'number' &&
|
|
470
491
|
typeof tuple[1] === 'number'
|
|
471
492
|
) {
|
|
472
|
-
const color = band
|
|
493
|
+
const color = quantileBandFillForConfig(band, forecastsList);
|
|
473
494
|
payload.push({
|
|
474
495
|
type: 'line',
|
|
475
496
|
name: band.name,
|
|
@@ -539,10 +560,10 @@ export function LightweightForecastChart(props: LightweightForecastChartProps) {
|
|
|
539
560
|
api.setData(buildForecastLineData(bridgedChartData, key));
|
|
540
561
|
}
|
|
541
562
|
|
|
542
|
-
quantileBands?.forEach(
|
|
563
|
+
quantileBands?.forEach(band => {
|
|
543
564
|
const entry = model.bands.get(band.key);
|
|
544
565
|
if (!entry) return;
|
|
545
|
-
const fill = band
|
|
566
|
+
const fill = quantileBandFillForConfig(band, forecastData);
|
|
546
567
|
entry.view.updateStyle({
|
|
547
568
|
fill,
|
|
548
569
|
stroke: band.strokeWidth ? fill : undefined,
|
|
@@ -557,7 +578,7 @@ export function LightweightForecastChart(props: LightweightForecastChartProps) {
|
|
|
557
578
|
});
|
|
558
579
|
|
|
559
580
|
scheduleFitTimeScale(model.chart);
|
|
560
|
-
}, [bridgedChartData, quantileBands]);
|
|
581
|
+
}, [bridgedChartData, quantileBands, forecastData]);
|
|
561
582
|
|
|
562
583
|
// Visibility toggles
|
|
563
584
|
useEffect(() => {
|
|
@@ -52,6 +52,16 @@ export const getForecastQuantileBandColor = (index: number) =>
|
|
|
52
52
|
FORECAST_LINE_COLORS[index % FORECAST_LINE_COLORS.length]
|
|
53
53
|
];
|
|
54
54
|
|
|
55
|
+
/** Same tint logic as intervals/threshold overlays: band fill follows forecast line hex when known. */
|
|
56
|
+
export function resolveQuantileBandFillForForecastLine(
|
|
57
|
+
lineColor: string,
|
|
58
|
+
forecastIndex: number,
|
|
59
|
+
): string {
|
|
60
|
+
const mapped =
|
|
61
|
+
FORECAST_COLORS_MAP[lineColor as keyof typeof FORECAST_COLORS_MAP];
|
|
62
|
+
return mapped ?? getForecastQuantileBandColor(forecastIndex);
|
|
63
|
+
}
|
|
64
|
+
|
|
55
65
|
// Memoized component for chart lines - only re-renders when data/analyses/hiddenSeries change
|
|
56
66
|
export const ChartLines = memo(
|
|
57
67
|
({
|
|
@@ -4,10 +4,9 @@ import { DEFAULT_QUANTILE_BAND_COLOR } from '#uilib/components/ui/Chart/componen
|
|
|
4
4
|
|
|
5
5
|
import { Analysis } from '../ChartAreaInteractive.types';
|
|
6
6
|
import {
|
|
7
|
-
FORECAST_COLORS_MAP,
|
|
8
7
|
FORECAST_LINE_COLORS,
|
|
9
8
|
ForecastItemData,
|
|
10
|
-
|
|
9
|
+
resolveQuantileBandFillForForecastLine,
|
|
11
10
|
} from '../ChartLines';
|
|
12
11
|
|
|
13
12
|
const DEFAULT_FORECAST_COLORS = {
|
|
@@ -37,9 +36,10 @@ export function useForecastColor(
|
|
|
37
36
|
forecastItem.color ||
|
|
38
37
|
FORECAST_LINE_COLORS[forecastIndex % FORECAST_LINE_COLORS.length];
|
|
39
38
|
|
|
40
|
-
const quantileBandColor =
|
|
41
|
-
|
|
42
|
-
|
|
39
|
+
const quantileBandColor = resolveQuantileBandFillForForecastLine(
|
|
40
|
+
lineColor,
|
|
41
|
+
forecastIndex,
|
|
42
|
+
);
|
|
43
43
|
|
|
44
44
|
return {
|
|
45
45
|
lineColor,
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Button } from '#uilib/components/ui/Button';
|
|
4
|
+
import { Dialog } from '#uilib/components/ui/Dialog';
|
|
5
|
+
|
|
6
|
+
import type { ConfirmProps } from './Confirm.types';
|
|
7
|
+
|
|
8
|
+
export function Confirm({
|
|
9
|
+
children,
|
|
10
|
+
open,
|
|
11
|
+
onOpenChange,
|
|
12
|
+
onConfirm,
|
|
13
|
+
onCancel,
|
|
14
|
+
title = 'Confirm',
|
|
15
|
+
confirmLabel = 'Confirm',
|
|
16
|
+
cancelLabel = 'Cancel',
|
|
17
|
+
trigger,
|
|
18
|
+
disabled,
|
|
19
|
+
confirmVariant = 'default',
|
|
20
|
+
}: ConfirmProps) {
|
|
21
|
+
const closedByConfirmRef = useRef(false);
|
|
22
|
+
|
|
23
|
+
useEffect(() => {
|
|
24
|
+
if (open) {
|
|
25
|
+
closedByConfirmRef.current = false;
|
|
26
|
+
}
|
|
27
|
+
}, [open]);
|
|
28
|
+
|
|
29
|
+
const handleOpenChange = useCallback(
|
|
30
|
+
(next: boolean) => {
|
|
31
|
+
if (!next) {
|
|
32
|
+
if (!closedByConfirmRef.current) {
|
|
33
|
+
onCancel?.();
|
|
34
|
+
}
|
|
35
|
+
closedByConfirmRef.current = false;
|
|
36
|
+
}
|
|
37
|
+
onOpenChange(next);
|
|
38
|
+
},
|
|
39
|
+
[onCancel, onOpenChange],
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
const handleConfirm = () => {
|
|
43
|
+
closedByConfirmRef.current = true;
|
|
44
|
+
onConfirm();
|
|
45
|
+
handleOpenChange(false);
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
return (
|
|
49
|
+
<Dialog
|
|
50
|
+
open={open}
|
|
51
|
+
onOpenChange={handleOpenChange}
|
|
52
|
+
disabled={disabled}
|
|
53
|
+
trigger={trigger}
|
|
54
|
+
title={title}
|
|
55
|
+
width="min(fit-content, calc(100vw - var(--p-4)))"
|
|
56
|
+
content={children}
|
|
57
|
+
footerAlignment="between"
|
|
58
|
+
footer={
|
|
59
|
+
<>
|
|
60
|
+
<Button
|
|
61
|
+
type="button"
|
|
62
|
+
variant="outline"
|
|
63
|
+
onClick={() => handleOpenChange(false)}
|
|
64
|
+
>
|
|
65
|
+
{cancelLabel}
|
|
66
|
+
</Button>
|
|
67
|
+
<Button
|
|
68
|
+
type="button"
|
|
69
|
+
variant={confirmVariant}
|
|
70
|
+
onClick={handleConfirm}
|
|
71
|
+
>
|
|
72
|
+
{confirmLabel}
|
|
73
|
+
</Button>
|
|
74
|
+
</>
|
|
75
|
+
}
|
|
76
|
+
/>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { ReactNode } from 'react';
|
|
2
|
+
|
|
3
|
+
import type { ButtonVariant } from '#uilib/components/ui/Button/Button.types';
|
|
4
|
+
|
|
5
|
+
export interface ConfirmProps {
|
|
6
|
+
children: ReactNode;
|
|
7
|
+
open: boolean;
|
|
8
|
+
onOpenChange: (open: boolean) => void;
|
|
9
|
+
onConfirm: () => void;
|
|
10
|
+
onCancel?: () => void;
|
|
11
|
+
title?: ReactNode;
|
|
12
|
+
confirmLabel?: string;
|
|
13
|
+
cancelLabel?: string;
|
|
14
|
+
trigger?: ReactNode;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
confirmVariant?: Extract<ButtonVariant, 'default' | 'destructive'>;
|
|
17
|
+
}
|
|
@@ -210,7 +210,11 @@ export function Dialog({
|
|
|
210
210
|
|
|
211
211
|
{footer && (
|
|
212
212
|
<CardFooter
|
|
213
|
-
className={cn(
|
|
213
|
+
className={cn(
|
|
214
|
+
S.footer,
|
|
215
|
+
S[`align-${footerAlignment}`],
|
|
216
|
+
footerClassName,
|
|
217
|
+
)}
|
|
214
218
|
>
|
|
215
219
|
{footer}
|
|
216
220
|
</CardFooter>
|
|
@@ -52,6 +52,28 @@ export default (env, argv) => {
|
|
|
52
52
|
alias.theme = themeStyl;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
+
const docsHtmlMinify = isDev
|
|
56
|
+
? false
|
|
57
|
+
: {
|
|
58
|
+
removeComments: true,
|
|
59
|
+
collapseWhitespace: true,
|
|
60
|
+
removeRedundantAttributes: true,
|
|
61
|
+
useShortDoctype: true,
|
|
62
|
+
removeEmptyAttributes: true,
|
|
63
|
+
removeStyleLinkTypeAttributes: true,
|
|
64
|
+
keepClosingSlash: true,
|
|
65
|
+
minifyJS: true,
|
|
66
|
+
minifyCSS: true,
|
|
67
|
+
minifyURLs: true,
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const docsHtmlPluginBase = {
|
|
71
|
+
lang: 'en',
|
|
72
|
+
baseUrl: publicPath,
|
|
73
|
+
template: `${paths.assets}/index.html`,
|
|
74
|
+
minify: docsHtmlMinify,
|
|
75
|
+
};
|
|
76
|
+
|
|
55
77
|
const config = {
|
|
56
78
|
entry: [paths.docs],
|
|
57
79
|
output: {
|
|
@@ -193,24 +215,13 @@ export default (env, argv) => {
|
|
|
193
215
|
}),
|
|
194
216
|
|
|
195
217
|
new HtmlWebpackPlugin({
|
|
196
|
-
|
|
197
|
-
baseUrl: publicPath,
|
|
218
|
+
...docsHtmlPluginBase,
|
|
198
219
|
filename: 'index.html',
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
collapseWhitespace: true,
|
|
205
|
-
removeRedundantAttributes: true,
|
|
206
|
-
useShortDoctype: true,
|
|
207
|
-
removeEmptyAttributes: true,
|
|
208
|
-
removeStyleLinkTypeAttributes: true,
|
|
209
|
-
keepClosingSlash: true,
|
|
210
|
-
minifyJS: true,
|
|
211
|
-
minifyCSS: true,
|
|
212
|
-
minifyURLs: true,
|
|
213
|
-
},
|
|
220
|
+
}),
|
|
221
|
+
/** GitHub Pages serves this for missing paths; same shell as index.html so SPA routes work. */
|
|
222
|
+
new HtmlWebpackPlugin({
|
|
223
|
+
...docsHtmlPluginBase,
|
|
224
|
+
filename: '404.html',
|
|
214
225
|
}),
|
|
215
226
|
existsSync(logoSvgPath) &&
|
|
216
227
|
new FaviconWebpackPlugin({
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
|
|
3
|
+
import { Button } from '#uilib/components/ui/Button';
|
|
4
|
+
import { Confirm } from '#uilib/components/ui/Confirm';
|
|
5
|
+
import { PageContentSection } from '#uilib/components/ui/Page';
|
|
6
|
+
|
|
7
|
+
import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
|
|
8
|
+
import { DocsHeaderActions } from '../docsHeaderActions';
|
|
9
|
+
|
|
10
|
+
export default function ConfirmPage() {
|
|
11
|
+
const [openDefault, setOpenDefault] = useState(false);
|
|
12
|
+
const [openDestructive, setOpenDestructive] = useState(false);
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<>
|
|
16
|
+
<AppPageHeader
|
|
17
|
+
breadcrumbs={[{ label: 'Confirm' }]}
|
|
18
|
+
title="Confirm"
|
|
19
|
+
subheader="Confirmation dialog built on Dialog with primary and cancel actions."
|
|
20
|
+
actions={<DocsHeaderActions />}
|
|
21
|
+
/>
|
|
22
|
+
<PageContentSection>
|
|
23
|
+
<div
|
|
24
|
+
style={{
|
|
25
|
+
display: 'flex',
|
|
26
|
+
flexWrap: 'wrap',
|
|
27
|
+
gap: 'var(--p-4)',
|
|
28
|
+
alignItems: 'center',
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<Confirm
|
|
32
|
+
open={openDefault}
|
|
33
|
+
onOpenChange={setOpenDefault}
|
|
34
|
+
trigger={<Button type="button">Open confirm</Button>}
|
|
35
|
+
title="Discard changes?"
|
|
36
|
+
confirmLabel="Discard"
|
|
37
|
+
cancelLabel="Keep editing"
|
|
38
|
+
onConfirm={() => setOpenDefault(false)}
|
|
39
|
+
>
|
|
40
|
+
You have unsaved changes. They will be lost if you continue.
|
|
41
|
+
</Confirm>
|
|
42
|
+
|
|
43
|
+
<Confirm
|
|
44
|
+
open={openDestructive}
|
|
45
|
+
onOpenChange={setOpenDestructive}
|
|
46
|
+
trigger={
|
|
47
|
+
<Button type="button" variant="destructive">
|
|
48
|
+
Delete item
|
|
49
|
+
</Button>
|
|
50
|
+
}
|
|
51
|
+
title="Delete item?"
|
|
52
|
+
confirmLabel="Delete"
|
|
53
|
+
cancelLabel="Cancel"
|
|
54
|
+
confirmVariant="destructive"
|
|
55
|
+
onConfirm={() => setOpenDestructive(false)}
|
|
56
|
+
>
|
|
57
|
+
This action cannot be undone.
|
|
58
|
+
</Confirm>
|
|
59
|
+
</div>
|
|
60
|
+
</PageContentSection>
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
@@ -85,7 +85,6 @@ const DEMO_QUANTILE_BANDS: QuantileBandConfig[] = [
|
|
|
85
85
|
opacity: 0.35,
|
|
86
86
|
name: 'P10–P90',
|
|
87
87
|
type: 'monotone',
|
|
88
|
-
color: 'rgba(100,190,220,0.35)',
|
|
89
88
|
strokeWidth: 0,
|
|
90
89
|
},
|
|
91
90
|
{
|
|
@@ -94,7 +93,6 @@ const DEMO_QUANTILE_BANDS: QuantileBandConfig[] = [
|
|
|
94
93
|
opacity: 0.45,
|
|
95
94
|
name: 'P25–P75',
|
|
96
95
|
type: 'monotone',
|
|
97
|
-
color: 'rgba(65,165,238,0.45)',
|
|
98
96
|
strokeWidth: 0,
|
|
99
97
|
},
|
|
100
98
|
];
|
package/src/docs/registry.ts
CHANGED
|
@@ -121,6 +121,12 @@ export const DOC_REGISTRY: DocEntry[] = [
|
|
|
121
121
|
section: 'Overlays',
|
|
122
122
|
load: () => import('./pages/DialogPage'),
|
|
123
123
|
},
|
|
124
|
+
{
|
|
125
|
+
slug: 'confirm',
|
|
126
|
+
title: 'Confirm',
|
|
127
|
+
section: 'Overlays',
|
|
128
|
+
load: () => import('./pages/ConfirmPage'),
|
|
129
|
+
},
|
|
124
130
|
{
|
|
125
131
|
slug: 'driver-map',
|
|
126
132
|
title: 'DriverMap & DriverCard',
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,7 @@ export * from './components/ui/Chart';
|
|
|
17
17
|
export * from './components/ui/ChartAreaInteractive';
|
|
18
18
|
export * from './components/ui/Chat';
|
|
19
19
|
export * from './components/ui/Checkbox';
|
|
20
|
+
export * from './components/ui/Confirm';
|
|
20
21
|
export * from './components/ui/Dialog';
|
|
21
22
|
export * from './components/ui/Drawer';
|
|
22
23
|
export * from './components/ui/DropdownMenu';
|