@galaxy-io/dls 2.0.0 → 2.0.1
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/charts/BarChart.js +29 -13
- package/dist/charts/ChartCategoryTargets.d.ts +2 -2
- package/dist/charts/ChartCategoryTargets.js +2 -1
- package/dist/charts/ChartFrame.d.ts +7 -5
- package/dist/charts/ChartFrame.js +151 -76
- package/dist/charts/ChartLegend.d.ts +14 -4
- package/dist/charts/ChartLegend.js +90 -53
- package/dist/charts/ChartMarkTargets.d.ts +2 -2
- package/dist/charts/ChartMarkTargets.js +2 -1
- package/dist/charts/Heatmap.js +19 -7
- package/dist/charts/LineChart.js +19 -8
- package/dist/charts/PieChart.js +16 -7
- package/dist/charts/chartSelection.d.ts +15 -0
- package/dist/charts/chartSelection.js +22 -0
- package/dist/charts/constants.d.ts +4 -0
- package/dist/charts/constants.js +6 -2
- package/dist/charts/types.d.ts +10 -1
- package/dist/charts/useChartInteraction.d.ts +25 -3
- package/dist/charts/useChartInteraction.js +56 -10
- package/dist/drawer/Drawer.d.ts +3 -1
- package/dist/drawer/Drawer.js +43 -14
- package/dist/feedback/Alert.d.ts +1 -1
- package/dist/inputs/CheckboxGroup.js +1 -1
- package/dist/inputs/CheckboxInput.js +1 -1
- package/dist/inputs/ColorInput.js +1 -1
- package/dist/inputs/CronInput.js +1 -1
- package/dist/inputs/DateInput.js +1 -1
- package/dist/inputs/KeyValueInput.js +1 -1
- package/dist/inputs/SelectInput.js +1 -1
- package/dist/inputs/SwitchInput.js +1 -1
- package/dist/inputs/TextAreaInput.js +6 -0
- package/dist/inputs/internal/ownField.js +1 -1
- package/dist/styles.css +1 -1
- package/dist/table/TableCore.js +6 -1
- package/dist/timeline/Timeline.d.ts +22 -1
- package/dist/timeline/Timeline.js +75 -43
- package/package.json +5 -1
package/dist/charts/BarChart.js
CHANGED
|
@@ -49,7 +49,7 @@ function visualOrder(components) {
|
|
|
49
49
|
return [...indexed].sort((a, b) => rank(a) - rank(b) || a.index - b.index).map(({ component }) => component);
|
|
50
50
|
}
|
|
51
51
|
function BarChartInner(props, ref) {
|
|
52
|
-
const { series, groups, normalization = "NONE", minSegmentLength = 0, valueFormatter, labelFormatter, valueDomain, axisLabels, hasLegend = true, hasTooltip = true, renderTooltip, isLoading = false, placeholder = DEFAULT_PLACEHOLDER, onSelect, selection, ariaLabel, id, className, style, ...rest } = props;
|
|
52
|
+
const { series, groups, normalization = "NONE", minSegmentLength = 0, valueFormatter, labelFormatter, valueDomain, axisLabels, hasLegend = true, hasTooltip = true, renderTooltip, isLoading = false, placeholder = DEFAULT_PLACEHOLDER, onSelect, selection, isFilterable = false, defaultSelection, onSelectionChange, ariaLabel, id, className, style, ...rest } = props;
|
|
53
53
|
const plotRef = useRef(null);
|
|
54
54
|
const colors = useSeriesColorResolver(series);
|
|
55
55
|
const axisValueFormatter = normalization === "PERCENT" && valueFormatter === void 0 ? PERCENT_AXIS_FORMATTER : valueFormatter;
|
|
@@ -107,7 +107,10 @@ function BarChartInner(props, ref) {
|
|
|
107
107
|
categoryKeys,
|
|
108
108
|
categoryMuteState: ChartMarkState.DIMMED,
|
|
109
109
|
selection,
|
|
110
|
-
|
|
110
|
+
isFilterable,
|
|
111
|
+
defaultSelection,
|
|
112
|
+
onSelectionChange,
|
|
113
|
+
isDisabled: !(hasTooltip || onSelect || isFilterable) || isLoading || isEmpty,
|
|
111
114
|
isLoading
|
|
112
115
|
});
|
|
113
116
|
const seriesKeyOf = useCallback((rect) => isStacked ? rect.componentKey : rect.metric, [isStacked]);
|
|
@@ -174,29 +177,41 @@ function BarChartInner(props, ref) {
|
|
|
174
177
|
width: rect.width,
|
|
175
178
|
height: rect.height
|
|
176
179
|
})), [geometry.rects]);
|
|
177
|
-
const
|
|
180
|
+
const { toggleSelection } = interaction;
|
|
181
|
+
const handleCategorySelect = useCallback((index, isAdditive = false) => {
|
|
178
182
|
const group = groups[index];
|
|
179
|
-
if (!group
|
|
180
|
-
onSelect({
|
|
183
|
+
if (!group) return;
|
|
184
|
+
onSelect?.({
|
|
181
185
|
categoryIndex: index,
|
|
182
186
|
categoryKey: group.label
|
|
183
187
|
});
|
|
184
|
-
|
|
185
|
-
|
|
188
|
+
toggleSelection({ categoryKey: group.label }, isAdditive);
|
|
189
|
+
}, [
|
|
190
|
+
groups,
|
|
191
|
+
onSelect,
|
|
192
|
+
toggleSelection
|
|
193
|
+
]);
|
|
194
|
+
const handleMarkSelect = useCallback((index, isAdditive = false) => {
|
|
186
195
|
const rect = geometry.rects[index];
|
|
187
196
|
const group = groups[rect?.groupIndex ?? -1];
|
|
188
|
-
if (!rect || !group
|
|
189
|
-
|
|
197
|
+
if (!rect || !group) return;
|
|
198
|
+
const seriesKey = seriesKeyOf(rect);
|
|
199
|
+
onSelect?.({
|
|
190
200
|
categoryIndex: rect.groupIndex,
|
|
191
201
|
categoryKey: group.label,
|
|
192
|
-
seriesKey
|
|
202
|
+
seriesKey,
|
|
193
203
|
value: rect.value
|
|
194
204
|
});
|
|
205
|
+
toggleSelection({
|
|
206
|
+
categoryKey: group.label,
|
|
207
|
+
seriesKey
|
|
208
|
+
}, isAdditive);
|
|
195
209
|
}, [
|
|
196
210
|
geometry.rects,
|
|
197
211
|
groups,
|
|
198
212
|
onSelect,
|
|
199
|
-
seriesKeyOf
|
|
213
|
+
seriesKeyOf,
|
|
214
|
+
toggleSelection
|
|
200
215
|
]);
|
|
201
216
|
const activeBand = interaction.activeIndex === null ? void 0 : geometry.bands[interaction.activeIndex];
|
|
202
217
|
return /* @__PURE__ */ jsxs(ChartFrame, {
|
|
@@ -236,13 +251,14 @@ function BarChartInner(props, ref) {
|
|
|
236
251
|
renderTooltip,
|
|
237
252
|
categoryTargets,
|
|
238
253
|
markTargets,
|
|
239
|
-
onCategorySelect: onSelect
|
|
240
|
-
onMarkSelect: onSelect
|
|
254
|
+
onCategorySelect: onSelect || isFilterable ? handleCategorySelect : void 0,
|
|
255
|
+
onMarkSelect: onSelect || isFilterable ? handleMarkSelect : void 0,
|
|
241
256
|
anchorHalfWidth: categoryStep / 2,
|
|
242
257
|
isEmpty,
|
|
243
258
|
isLoading,
|
|
244
259
|
placeholder,
|
|
245
260
|
hasLegend,
|
|
261
|
+
formatCategoryKey: formatLabel,
|
|
246
262
|
legendItems,
|
|
247
263
|
legendPlacement: ChartLegendPlacement.BOTTOM,
|
|
248
264
|
legendSwatch: ChartLegendSwatch.SQUARE,
|
|
@@ -7,8 +7,8 @@ export interface ChartCategoryTargetsProps {
|
|
|
7
7
|
onEnter: (categoryIndex: number) => void;
|
|
8
8
|
/** Pointer left the target layers (moving between targets is not leaving). */
|
|
9
9
|
onLeave: () => void;
|
|
10
|
-
/** Click on a category; supplying it makes the targets clickable. */
|
|
11
|
-
onSelect?: ((categoryIndex: number) => void) | undefined;
|
|
10
|
+
/** Click on a category (additive with ⌘ / Ctrl / Shift); supplying it makes the targets clickable. */
|
|
11
|
+
onSelect?: ((categoryIndex: number, isAdditive: boolean) => void) | undefined;
|
|
12
12
|
}
|
|
13
13
|
/** @internal The category hit layer. */
|
|
14
14
|
export declare function ChartCategoryTargets({ targets, onEnter, onLeave, onSelect, }: ChartCategoryTargetsProps): import("react").JSX.Element;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ChartTargetShape } from "./types.js";
|
|
2
2
|
import { CHART_HIT_TARGET_CSS, leaveUnlessTarget } from "./ChartPrimitives.js";
|
|
3
|
+
import { isAdditiveEvent } from "./chartSelection.js";
|
|
3
4
|
import { Fragment, jsx } from "react/jsx-runtime";
|
|
4
5
|
import { cx } from "@linaria/core";
|
|
5
6
|
//#region src/charts/ChartCategoryTargets.tsx
|
|
@@ -16,7 +17,7 @@ function ChartCategoryTargets({ targets, onEnter, onLeave, onSelect }) {
|
|
|
16
17
|
const handlers = {
|
|
17
18
|
onMouseEnter: () => onEnter(index),
|
|
18
19
|
onMouseLeave: (event) => leaveUnlessTarget(event, onLeave),
|
|
19
|
-
...onSelect && { onClick: () => onSelect(index) }
|
|
20
|
+
...onSelect && { onClick: (event) => onSelect(index, isAdditiveEvent(event)) }
|
|
20
21
|
};
|
|
21
22
|
return target.shape === ChartTargetShape.RECT ? /* @__PURE__ */ jsx("rect", {
|
|
22
23
|
x: target.x,
|
|
@@ -48,10 +48,10 @@ export interface ChartFrameProps {
|
|
|
48
48
|
markTargets?: ChartMarkTarget[];
|
|
49
49
|
/** Transform applied to both target layers (radial charts: their center). */
|
|
50
50
|
targetsTransform?: string;
|
|
51
|
-
/** Category chosen by click, Enter or Space. Supplying it makes the plot selectable. */
|
|
52
|
-
onCategorySelect?: ((categoryIndex: number) => void) | undefined;
|
|
53
|
-
/** Mark clicked, by index in `markTargets
|
|
54
|
-
onMarkSelect?: ((markIndex: number) => void) | undefined;
|
|
51
|
+
/** Category chosen by click, Enter or Space (additive with ⌘ / Ctrl / Shift). Supplying it makes the plot selectable. */
|
|
52
|
+
onCategorySelect?: ((categoryIndex: number, isAdditive: boolean) => void) | undefined;
|
|
53
|
+
/** Mark clicked, by index in `markTargets` (additive with ⌘ / Ctrl / Shift). */
|
|
54
|
+
onMarkSelect?: ((markIndex: number, isAdditive: boolean) => void) | undefined;
|
|
55
55
|
/** Half a category's width (tooltip sits beside it). */
|
|
56
56
|
anchorHalfWidth?: number;
|
|
57
57
|
/** Radial charts: their center x, in plot coordinates. */
|
|
@@ -76,10 +76,12 @@ export interface ChartFrameProps {
|
|
|
76
76
|
tooltipSwatch?: ChartLegendSwatch | undefined;
|
|
77
77
|
/** A chart's own legend in place of the series legend (Heatmap's step legend). */
|
|
78
78
|
legend?: ReactNode;
|
|
79
|
+
/** Names a raw category key in the filter chip (the chart's `labelFormatter`). @default the key */
|
|
80
|
+
formatCategoryKey?: ((key: string) => string) | undefined;
|
|
79
81
|
/** Passthrough: `className` on the root. */
|
|
80
82
|
className?: string | undefined;
|
|
81
83
|
/** Passthrough: `style` on the root. */
|
|
82
84
|
style?: CSSProperties | undefined;
|
|
83
85
|
}
|
|
84
86
|
/** @internal The chart shell. */
|
|
85
|
-
export declare function ChartFrame({ rootRef, plotRef, id, className, style, rest, dimensions, interaction, kind, categoryCount, ariaLabel, aspectRatio, axes, children, plotOverlay, plotClassName, describeCategory, hasTooltip, buildCategoryTooltip, renderTooltip, categoryTargets, markTargets, targetsTransform, onCategorySelect, onMarkSelect, anchorHalfWidth, placeAwayFromX, verticalAlign, isEmpty, isLoading, placeholder, hasLegend, legendItems, legendPlacement, legendSwatch, tooltipSwatch, legend, }: ChartFrameProps): import("react").JSX.Element;
|
|
87
|
+
export declare function ChartFrame({ rootRef, plotRef, id, className, style, rest, dimensions, interaction, kind, categoryCount, ariaLabel, aspectRatio, axes, children, plotOverlay, plotClassName, describeCategory, hasTooltip, buildCategoryTooltip, renderTooltip, categoryTargets, markTargets, targetsTransform, onCategorySelect, onMarkSelect, anchorHalfWidth, placeAwayFromX, verticalAlign, isEmpty, isLoading, placeholder, hasLegend, legendItems, legendPlacement, legendSwatch, tooltipSwatch, legend, formatCategoryKey, }: ChartFrameProps): import("react").JSX.Element;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import Skeleton, { SkeletonVariant } from "../feedback/Skeleton.js";
|
|
2
2
|
import { ChartKind, ChartLegendPlacement } from "./types.js";
|
|
3
|
-
import { CHART_LEGEND_SIDE_GAP } from "./constants.js";
|
|
3
|
+
import { CHART_LEGEND_FILTER_EXTENT, CHART_LEGEND_SIDE_GAP } from "./constants.js";
|
|
4
|
+
import Chip, { ChipSize } from "../chips/Chip.js";
|
|
4
5
|
import EmptyState, { EmptyStateSize } from "../feedback/EmptyState.js";
|
|
6
|
+
import { isAdditiveEvent } from "./chartSelection.js";
|
|
5
7
|
import { ChartCategoryTargets } from "./ChartCategoryTargets.js";
|
|
6
8
|
import { ChartLegend } from "./ChartLegend.js";
|
|
7
9
|
import { ChartMarkTargets } from "./ChartMarkTargets.js";
|
|
@@ -11,12 +13,16 @@ import { styled } from "@linaria/react";
|
|
|
11
13
|
import { useCallback, useMemo, useState } from "react";
|
|
12
14
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
15
|
import { cx } from "@linaria/core";
|
|
16
|
+
import { FunnelSimpleIcon } from "@phosphor-icons/react";
|
|
14
17
|
//#region src/charts/ChartFrame.tsx
|
|
15
18
|
/**
|
|
16
19
|
* @internal The shell every chart renders into: the root (sizing, legend placement, passthrough),
|
|
17
20
|
* the measured plot box (one tab stop when interactive), the SVG and its inset translate, axes,
|
|
18
21
|
* marks, hit targets, the in-chart tooltip, the empty and loading overlays, the live region and
|
|
19
|
-
* the legend.
|
|
22
|
+
* the legend. On a filterable chart dismissible filter chips follow the legend entries while
|
|
23
|
+
* something is pinned. One pin shows a chip per part ("06:00" and "Failed" for one segment): a
|
|
24
|
+
* chip's × drops that part and keeps the other. Several pins collapse into one "3 filters" chip
|
|
25
|
+
* (the list in its tooltip) whose × clears them all. It knows nothing about scales or geometry: axes and marks arrive as nodes, and every
|
|
20
26
|
* coordinate handed to it is in plot space (the frame adds the insets once).
|
|
21
27
|
*
|
|
22
28
|
* Sizing: the root fills its parent (`width` / `height: 100%`); against a parent of indefinite
|
|
@@ -54,9 +60,27 @@ var Overlay = /*#__PURE__*/ styled("div")({
|
|
|
54
60
|
});
|
|
55
61
|
/** A standalone `Skeleton RECT` that takes the whole plot box. */
|
|
56
62
|
var LOADING_SKELETON_CSS = "gx-ChartFrame-LOADING_SKELETON_CSS-l1oi7u1q";
|
|
63
|
+
/**
|
|
64
|
+
* A chart's own legend (Heatmap's steps) with the filter chip after it. Both carry the legend's 8px
|
|
65
|
+
* top padding and center on each other, so the chip centers on the legend's text line.
|
|
66
|
+
*/
|
|
67
|
+
var CustomLegendBar = /*#__PURE__*/ styled("div")({
|
|
68
|
+
name: "CustomLegendBar",
|
|
69
|
+
class: "gx-ChartFrame-CustomLegendBar-c1jrxj0u",
|
|
70
|
+
propsAsIs: false
|
|
71
|
+
});
|
|
72
|
+
/**
|
|
73
|
+
* The chips after a chart's own legend. Its height (the 8px top padding and a 20px chip) is kept
|
|
74
|
+
* while nothing is pinned, so the plot above never moves when a chip appears.
|
|
75
|
+
*/
|
|
76
|
+
var CustomFilterSlot = /*#__PURE__*/ styled("div")({
|
|
77
|
+
name: "CustomFilterSlot",
|
|
78
|
+
class: "gx-ChartFrame-CustomFilterSlot-celuo85",
|
|
79
|
+
propsAsIs: false
|
|
80
|
+
});
|
|
57
81
|
var LiveRegion = /*#__PURE__*/ styled("div")({
|
|
58
82
|
name: "LiveRegion",
|
|
59
|
-
class: "gx-ChartFrame-LiveRegion-
|
|
83
|
+
class: "gx-ChartFrame-LiveRegion-lvgwxyl",
|
|
60
84
|
propsAsIs: false
|
|
61
85
|
});
|
|
62
86
|
/** The default accessible name, phrased once so the charts cannot drift. */
|
|
@@ -85,7 +109,7 @@ var NAVIGATION_KEYS = new Set([
|
|
|
85
109
|
"End"
|
|
86
110
|
]);
|
|
87
111
|
/** @internal The chart shell. */
|
|
88
|
-
function ChartFrame({ rootRef, plotRef, id, className, style, rest, dimensions, interaction, kind, categoryCount, ariaLabel, aspectRatio, axes, children, plotOverlay, plotClassName, describeCategory, hasTooltip, buildCategoryTooltip, renderTooltip, categoryTargets, markTargets, targetsTransform, onCategorySelect, onMarkSelect, anchorHalfWidth, placeAwayFromX, verticalAlign, isEmpty, isLoading, placeholder, hasLegend, legendItems, legendPlacement, legendSwatch, tooltipSwatch, legend }) {
|
|
112
|
+
function ChartFrame({ rootRef, plotRef, id, className, style, rest, dimensions, interaction, kind, categoryCount, ariaLabel, aspectRatio, axes, children, plotOverlay, plotClassName, describeCategory, hasTooltip, buildCategoryTooltip, renderTooltip, categoryTargets, markTargets, targetsTransform, onCategorySelect, onMarkSelect, anchorHalfWidth, placeAwayFromX, verticalAlign, isEmpty, isLoading, placeholder, hasLegend, legendItems, legendPlacement, legendSwatch, tooltipSwatch, legend, formatCategoryKey }) {
|
|
89
113
|
const { width, height, insets, isMeasured } = dimensions;
|
|
90
114
|
const [announcement, setAnnouncement] = useState("");
|
|
91
115
|
const { rootPassthrough, plotAria } = useMemo(() => {
|
|
@@ -138,17 +162,29 @@ function ChartFrame({ rootRef, plotRef, id, className, style, rest, dimensions,
|
|
|
138
162
|
if (event.key === " ") event.preventDefault();
|
|
139
163
|
if (onCategorySelect && interaction.activeIndex !== null) {
|
|
140
164
|
event.preventDefault();
|
|
141
|
-
onCategorySelect(interaction.activeIndex);
|
|
165
|
+
onCategorySelect(interaction.activeIndex, isAdditiveEvent(event));
|
|
142
166
|
}
|
|
143
167
|
return;
|
|
144
168
|
}
|
|
145
|
-
if (event.key
|
|
169
|
+
if (event.key !== "Escape") return;
|
|
170
|
+
if (interaction.activeIndex !== null) {
|
|
146
171
|
event.preventDefault();
|
|
147
172
|
event.stopPropagation();
|
|
148
173
|
interaction.onKeyboardClear();
|
|
149
174
|
setAnnouncement("");
|
|
175
|
+
} else if (interaction.isFilterable && interaction.hasSelection) {
|
|
176
|
+
event.preventDefault();
|
|
177
|
+
event.stopPropagation();
|
|
178
|
+
interaction.clearSelection();
|
|
179
|
+
setAnnouncement("Filter cleared.");
|
|
150
180
|
}
|
|
151
181
|
};
|
|
182
|
+
const handleLegendClick = (seriesKey, isAdditive) => interaction.toggleSelection({ seriesKey }, isAdditive);
|
|
183
|
+
const handleFilterDismiss = (rest) => {
|
|
184
|
+
if (rest === null) interaction.clearSelection();
|
|
185
|
+
else interaction.setSelection([rest]);
|
|
186
|
+
if (isInteractive) plotRef.current?.focus();
|
|
187
|
+
};
|
|
152
188
|
const handleFocus = (event) => {
|
|
153
189
|
if (event.target !== event.currentTarget) return;
|
|
154
190
|
let isKeyboardFocus = true;
|
|
@@ -174,6 +210,55 @@ function ChartFrame({ rootRef, plotRef, id, className, style, rest, dimensions,
|
|
|
174
210
|
"aria-label": resolvedAriaLabel
|
|
175
211
|
};
|
|
176
212
|
const isSkeleton = isLoading && isEmpty;
|
|
213
|
+
const isSideLegend = legendPlacement === ChartLegendPlacement.RIGHT;
|
|
214
|
+
const categoryLabel = (key) => formatCategoryKey?.(key) ?? key;
|
|
215
|
+
const seriesLabel = (key) => legendItems.find((item) => item.key === key)?.label ?? key;
|
|
216
|
+
const describePin = (pin) => [pin.categoryKey === void 0 ? void 0 : categoryLabel(pin.categoryKey), pin.seriesKey === void 0 ? void 0 : seriesLabel(pin.seriesKey)].filter((part) => part !== void 0).join(" · ");
|
|
217
|
+
/** One chip per part of a single pin; one "N filters" chip for several. */
|
|
218
|
+
const filterChipParts = (() => {
|
|
219
|
+
const pins = interaction.selection;
|
|
220
|
+
const [pin] = pins;
|
|
221
|
+
if (!interaction.isFilterable || pin === void 0) return [];
|
|
222
|
+
if (pins.length > 1) return [{
|
|
223
|
+
key: "all",
|
|
224
|
+
label: `${pins.length} filters`,
|
|
225
|
+
rest: null
|
|
226
|
+
}];
|
|
227
|
+
const parts = [];
|
|
228
|
+
if (pin.categoryKey !== void 0) parts.push({
|
|
229
|
+
key: "category",
|
|
230
|
+
label: categoryLabel(pin.categoryKey),
|
|
231
|
+
rest: pin.seriesKey === void 0 ? null : { seriesKey: pin.seriesKey }
|
|
232
|
+
});
|
|
233
|
+
if (pin.seriesKey !== void 0) parts.push({
|
|
234
|
+
key: "series",
|
|
235
|
+
label: seriesLabel(pin.seriesKey),
|
|
236
|
+
rest: pin.categoryKey === void 0 ? null : { categoryKey: pin.categoryKey }
|
|
237
|
+
});
|
|
238
|
+
return parts;
|
|
239
|
+
})();
|
|
240
|
+
const filterChip = filterChipParts.length === 0 ? null : filterChipParts.map((part, index) => /* @__PURE__ */ jsx(Chip, {
|
|
241
|
+
size: ChipSize.SMALL,
|
|
242
|
+
...index === 0 && { icon: FunnelSimpleIcon },
|
|
243
|
+
label: part.label,
|
|
244
|
+
tooltip: part.key === "all" ? interaction.selection.map(describePin).join(", ") : "",
|
|
245
|
+
onDismiss: () => handleFilterDismiss(part.rest)
|
|
246
|
+
}, part.key));
|
|
247
|
+
const legendNode = !hasLegend || isSkeleton ? null : legend ?? /* @__PURE__ */ jsx(ChartLegend, {
|
|
248
|
+
items: legendItems,
|
|
249
|
+
placement: legendPlacement,
|
|
250
|
+
swatch: legendSwatch,
|
|
251
|
+
inset: isSideLegend ? CHART_LEGEND_SIDE_GAP : insets.left,
|
|
252
|
+
extent: isSideLegend ? Math.max(0, height - (interaction.isFilterable ? CHART_LEGEND_FILTER_EXTENT : 0)) : 0,
|
|
253
|
+
isFixedExtent: !interaction.isFilterable,
|
|
254
|
+
hasFilterSlot: interaction.isFilterable,
|
|
255
|
+
filter: filterChip,
|
|
256
|
+
getEntryState: interaction.getSeriesState,
|
|
257
|
+
isEntryPinned: interaction.isSeriesPinned,
|
|
258
|
+
onItemClick: interaction.isFilterable ? handleLegendClick : void 0,
|
|
259
|
+
onItemEnter: interaction.onSeriesEnter,
|
|
260
|
+
onItemLeave: interaction.onSeriesLeave
|
|
261
|
+
});
|
|
177
262
|
const hasTargets = isMeasured && isInteractive && categoryTargets.length > 0;
|
|
178
263
|
const rootStyle = {
|
|
179
264
|
"--gx-chart-aspect-ratio": aspectRatio,
|
|
@@ -186,77 +271,67 @@ function ChartFrame({ rootRef, plotRef, id, className, style, rest, dimensions,
|
|
|
186
271
|
"aria-busy": isLoading || void 0,
|
|
187
272
|
className: cx(CHART_LEGEND_PLACEMENT_TO_CSS_MAP[legendPlacement], className),
|
|
188
273
|
style: rootStyle,
|
|
189
|
-
children: [
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
]
|
|
220
|
-
})
|
|
221
|
-
}),
|
|
222
|
-
isMeasured && !isSkeleton && plotOverlay,
|
|
223
|
-
isMeasured && isEmpty && !isLoading && /* @__PURE__ */ jsx(Overlay, { children: /* @__PURE__ */ jsx(EmptyState, {
|
|
224
|
-
size: EmptyStateSize.SMALL,
|
|
225
|
-
header: placeholder,
|
|
226
|
-
role: "status"
|
|
227
|
-
}) }),
|
|
228
|
-
isSkeleton && /* @__PURE__ */ jsx(Skeleton, {
|
|
229
|
-
variant: SkeletonVariant.RECT,
|
|
230
|
-
className: LOADING_SKELETON_CSS
|
|
231
|
-
}),
|
|
232
|
-
isMeasured && hasTooltip && !isSkeleton && /* @__PURE__ */ jsx(ChartTooltip, {
|
|
233
|
-
model: tooltipModel,
|
|
234
|
-
containerWidth: width,
|
|
235
|
-
containerHeight: height,
|
|
236
|
-
anchorHalfWidth,
|
|
237
|
-
placeAwayFromX: placeAwayFromX === void 0 ? void 0 : placeAwayFromX + insets.left,
|
|
238
|
-
verticalAlign,
|
|
239
|
-
renderTooltip,
|
|
240
|
-
swatch: tooltipSwatch
|
|
241
|
-
}),
|
|
242
|
-
/* @__PURE__ */ jsx(LiveRegion, {
|
|
243
|
-
"aria-live": "polite",
|
|
244
|
-
children: announcement
|
|
274
|
+
children: [/* @__PURE__ */ jsxs(PlotBox, {
|
|
275
|
+
...plotAriaRest,
|
|
276
|
+
...plotA11yProps,
|
|
277
|
+
ref: plotRef,
|
|
278
|
+
className: cx(isInteractive && PLOT_INTERACTIVE_CSS, plotClassName),
|
|
279
|
+
children: [
|
|
280
|
+
isMeasured && !isSkeleton && /* @__PURE__ */ jsx(ChartSvg, {
|
|
281
|
+
"aria-hidden": "true",
|
|
282
|
+
width,
|
|
283
|
+
height,
|
|
284
|
+
children: /* @__PURE__ */ jsxs("g", {
|
|
285
|
+
transform: `translate(${insets.left}, ${insets.top})`,
|
|
286
|
+
children: [
|
|
287
|
+
axes,
|
|
288
|
+
/* @__PURE__ */ jsx("g", { children }),
|
|
289
|
+
hasTargets && /* @__PURE__ */ jsxs("g", {
|
|
290
|
+
transform: targetsTransform,
|
|
291
|
+
children: [/* @__PURE__ */ jsx(ChartCategoryTargets, {
|
|
292
|
+
targets: categoryTargets,
|
|
293
|
+
onEnter: interaction.onCategoryEnter,
|
|
294
|
+
onLeave: interaction.onCategoryLeave,
|
|
295
|
+
onSelect: onCategorySelect
|
|
296
|
+
}), onMarkSelect && markTargets && markTargets.length > 0 && /* @__PURE__ */ jsx(ChartMarkTargets, {
|
|
297
|
+
targets: markTargets,
|
|
298
|
+
onEnter: interaction.onCategoryEnter,
|
|
299
|
+
onLeave: interaction.onCategoryLeave,
|
|
300
|
+
onSelect: onMarkSelect
|
|
301
|
+
})]
|
|
302
|
+
})
|
|
303
|
+
]
|
|
245
304
|
})
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
305
|
+
}),
|
|
306
|
+
isMeasured && !isSkeleton && plotOverlay,
|
|
307
|
+
isMeasured && isEmpty && !isLoading && /* @__PURE__ */ jsx(Overlay, { children: /* @__PURE__ */ jsx(EmptyState, {
|
|
308
|
+
size: EmptyStateSize.SMALL,
|
|
309
|
+
header: placeholder,
|
|
310
|
+
role: "status"
|
|
311
|
+
}) }),
|
|
312
|
+
isSkeleton && /* @__PURE__ */ jsx(Skeleton, {
|
|
313
|
+
variant: SkeletonVariant.RECT,
|
|
314
|
+
className: LOADING_SKELETON_CSS
|
|
315
|
+
}),
|
|
316
|
+
isMeasured && hasTooltip && !isSkeleton && /* @__PURE__ */ jsx(ChartTooltip, {
|
|
317
|
+
model: tooltipModel,
|
|
318
|
+
containerWidth: width,
|
|
319
|
+
containerHeight: height,
|
|
320
|
+
anchorHalfWidth,
|
|
321
|
+
placeAwayFromX: placeAwayFromX === void 0 ? void 0 : placeAwayFromX + insets.left,
|
|
322
|
+
verticalAlign,
|
|
323
|
+
renderTooltip,
|
|
324
|
+
swatch: tooltipSwatch
|
|
325
|
+
}),
|
|
326
|
+
/* @__PURE__ */ jsx(LiveRegion, {
|
|
327
|
+
"aria-live": "polite",
|
|
328
|
+
children: announcement
|
|
329
|
+
})
|
|
330
|
+
]
|
|
331
|
+
}), legendNode !== null && (interaction.isFilterable && legend !== void 0 ? /* @__PURE__ */ jsxs(CustomLegendBar, { children: [legendNode, /* @__PURE__ */ jsx(CustomFilterSlot, {
|
|
332
|
+
"aria-hidden": filterChip === null || void 0,
|
|
333
|
+
children: filterChip
|
|
334
|
+
})] }) : legendNode)]
|
|
260
335
|
});
|
|
261
336
|
}
|
|
262
337
|
//#endregion
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ReactNode } from "react";
|
|
2
|
-
import { type ChartLegendItem, ChartLegendPlacement } from "./types.js";
|
|
2
|
+
import { type ChartLegendItem, ChartLegendPlacement, ChartMarkState } from "./types.js";
|
|
3
3
|
/** @internal Swatch shape: a dot for line series, a square for filled series. */
|
|
4
4
|
export declare enum ChartLegendSwatch {
|
|
5
5
|
/** `Circle SMALL`: line series. */
|
|
@@ -19,12 +19,22 @@ export interface ChartLegendProps {
|
|
|
19
19
|
inset: number;
|
|
20
20
|
/** RIGHT: the plot height the column fits into (0 = unconstrained). */
|
|
21
21
|
extent?: number;
|
|
22
|
-
/**
|
|
23
|
-
|
|
22
|
+
/** RIGHT: the column is `extent` tall with its entries centered; off, it hugs the entries (a Reset follows them). @default true */
|
|
23
|
+
isFixedExtent?: boolean;
|
|
24
|
+
/** An entry's emphasis: the hovered entry, else whether the selection covers its series. */
|
|
25
|
+
getEntryState: (key: string) => ChartMarkState;
|
|
26
|
+
/** The entry's series is pinned on its own: its toggle reads pressed. */
|
|
27
|
+
isEntryPinned?: (key: string) => boolean;
|
|
28
|
+
/** Filterable charts: keep a slot after the entries for the filter chip. @default false */
|
|
29
|
+
hasFilterSlot?: boolean;
|
|
30
|
+
/** The filter chip, or `null` while nothing is pinned (the slot keeps its space). */
|
|
31
|
+
filter?: ReactNode;
|
|
32
|
+
/** Click on an entry (filterable charts); supplying it makes each inline entry a toggle button. */
|
|
33
|
+
onItemClick?: ((key: string, isAdditive: boolean) => void) | undefined;
|
|
24
34
|
/** Pointer entered an entry. */
|
|
25
35
|
onItemEnter: (key: string) => void;
|
|
26
36
|
/** Pointer left an entry. */
|
|
27
37
|
onItemLeave: () => void;
|
|
28
38
|
}
|
|
29
39
|
/** @internal The chart legend. */
|
|
30
|
-
export declare function ChartLegend({ items, placement, swatch, inset, extent,
|
|
40
|
+
export declare function ChartLegend({ items, placement, swatch, inset, extent, isFixedExtent, hasFilterSlot, filter, getEntryState, isEntryPinned, onItemClick, onItemEnter, onItemLeave, }: ChartLegendProps): ReactNode;
|