@neo4j-ndl/react-charts 1.1.0 → 1.1.2
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/lib/cjs/charts/Chart.js +56 -462
- package/lib/cjs/charts/Chart.js.map +1 -1
- package/lib/cjs/charts/ChartContainer.js +71 -0
- package/lib/cjs/charts/ChartContainer.js.map +1 -0
- package/lib/cjs/charts/ChartEmpty.js.map +1 -1
- package/lib/cjs/charts/ChartRender.js +97 -0
- package/lib/cjs/charts/ChartRender.js.map +1 -0
- package/lib/cjs/charts/ChartTooltip.js.map +1 -1
- package/lib/cjs/charts/Legend.js +32 -246
- package/lib/cjs/charts/Legend.js.map +1 -1
- package/lib/cjs/charts/LegendItem.js +68 -0
- package/lib/cjs/charts/LegendItem.js.map +1 -0
- package/lib/cjs/charts/LegendLayout.js +363 -0
- package/lib/cjs/charts/LegendLayout.js.map +1 -0
- package/lib/cjs/charts/hooks/use-chart-instance.js +133 -0
- package/lib/cjs/charts/hooks/use-chart-instance.js.map +1 -0
- package/lib/cjs/charts/hooks/use-chart-option.js +79 -0
- package/lib/cjs/charts/hooks/use-chart-option.js.map +1 -0
- package/lib/cjs/charts/hooks/use-chart-refs.js +52 -0
- package/lib/cjs/charts/hooks/use-chart-refs.js.map +1 -0
- package/lib/cjs/charts/hooks/use-chart-zoom.js +117 -0
- package/lib/cjs/charts/hooks/use-chart-zoom.js.map +1 -0
- package/lib/cjs/charts/hooks/use-legend-interactions.js +149 -0
- package/lib/cjs/charts/hooks/use-legend-interactions.js.map +1 -0
- package/lib/cjs/charts/hooks/use-legend-series.js +181 -0
- package/lib/cjs/charts/hooks/use-legend-series.js.map +1 -0
- package/lib/cjs/charts/hooks/use-legend-visibility.js +91 -0
- package/lib/cjs/charts/hooks/use-legend-visibility.js.map +1 -0
- package/lib/cjs/charts/index.js +1 -1
- package/lib/cjs/charts/index.js.map +1 -1
- package/lib/cjs/charts/tests/chart-test-utils.js +56 -9
- package/lib/cjs/charts/tests/chart-test-utils.js.map +1 -1
- package/lib/cjs/charts/themes/ndl-echarts-theme.js.map +1 -1
- package/lib/cjs/charts/{aria-description.js → utils/aria-description.js} +4 -45
- package/lib/cjs/charts/utils/aria-description.js.map +1 -0
- package/lib/cjs/charts/utils/build-chart-option.js +74 -0
- package/lib/cjs/charts/utils/build-chart-option.js.map +1 -0
- package/lib/cjs/charts/utils/chart-tooltip-formatter.js +86 -0
- package/lib/cjs/charts/utils/chart-tooltip-formatter.js.map +1 -0
- package/lib/cjs/charts/utils/chart-types.js.map +1 -0
- package/lib/cjs/charts/utils/defaults.js.map +1 -0
- package/lib/cjs/charts/{utils.js → utils/format-utils.js} +3 -19
- package/lib/cjs/charts/utils/format-utils.js.map +1 -0
- package/lib/cjs/charts/utils/legend-layout.js +65 -0
- package/lib/cjs/charts/utils/legend-layout.js.map +1 -0
- package/lib/cjs/charts/{legend-utils.js → utils/legend-utils.js} +1 -78
- package/lib/cjs/charts/utils/legend-utils.js.map +1 -0
- package/lib/cjs/charts/utils/threshold.js +114 -0
- package/lib/cjs/charts/utils/threshold.js.map +1 -0
- package/lib/cjs/charts/{user-option-utils.js → utils/user-option-utils.js} +7 -16
- package/lib/cjs/charts/utils/user-option-utils.js.map +1 -0
- package/lib/esm/charts/Chart.js +50 -457
- package/lib/esm/charts/Chart.js.map +1 -1
- package/lib/esm/charts/ChartContainer.js +67 -0
- package/lib/esm/charts/ChartContainer.js.map +1 -0
- package/lib/esm/charts/ChartEmpty.js.map +1 -1
- package/lib/esm/charts/ChartRender.js +93 -0
- package/lib/esm/charts/ChartRender.js.map +1 -0
- package/lib/esm/charts/ChartTooltip.js.map +1 -1
- package/lib/esm/charts/Legend.js +32 -243
- package/lib/esm/charts/Legend.js.map +1 -1
- package/lib/esm/charts/LegendItem.js +61 -0
- package/lib/esm/charts/LegendItem.js.map +1 -0
- package/lib/esm/charts/LegendLayout.js +323 -0
- package/lib/esm/charts/LegendLayout.js.map +1 -0
- package/lib/esm/charts/hooks/use-chart-instance.js +128 -0
- package/lib/esm/charts/hooks/use-chart-instance.js.map +1 -0
- package/lib/esm/charts/hooks/use-chart-option.js +76 -0
- package/lib/esm/charts/hooks/use-chart-option.js.map +1 -0
- package/lib/esm/charts/hooks/use-chart-refs.js +48 -0
- package/lib/esm/charts/hooks/use-chart-refs.js.map +1 -0
- package/lib/esm/charts/hooks/use-chart-zoom.js +114 -0
- package/lib/esm/charts/hooks/use-chart-zoom.js.map +1 -0
- package/lib/esm/charts/hooks/use-legend-interactions.js +145 -0
- package/lib/esm/charts/hooks/use-legend-interactions.js.map +1 -0
- package/lib/esm/charts/hooks/use-legend-series.js +178 -0
- package/lib/esm/charts/hooks/use-legend-series.js.map +1 -0
- package/lib/esm/charts/hooks/use-legend-visibility.js +87 -0
- package/lib/esm/charts/hooks/use-legend-visibility.js.map +1 -0
- package/lib/esm/charts/index.js +1 -1
- package/lib/esm/charts/index.js.map +1 -1
- package/lib/esm/charts/tests/chart-test-utils.js +53 -8
- package/lib/esm/charts/tests/chart-test-utils.js.map +1 -1
- package/lib/esm/charts/themes/ndl-echarts-theme.js.map +1 -1
- package/lib/esm/charts/{aria-description.js → utils/aria-description.js} +4 -45
- package/lib/esm/charts/utils/aria-description.js.map +1 -0
- package/lib/esm/charts/utils/build-chart-option.js +69 -0
- package/lib/esm/charts/utils/build-chart-option.js.map +1 -0
- package/lib/esm/charts/utils/chart-tooltip-formatter.js +82 -0
- package/lib/esm/charts/utils/chart-tooltip-formatter.js.map +1 -0
- package/lib/esm/charts/utils/chart-types.js.map +1 -0
- package/lib/esm/charts/utils/defaults.js.map +1 -0
- package/lib/esm/charts/{utils.js → utils/format-utils.js} +2 -17
- package/lib/esm/charts/utils/format-utils.js.map +1 -0
- package/lib/esm/charts/utils/legend-layout.js +59 -0
- package/lib/esm/charts/utils/legend-layout.js.map +1 -0
- package/lib/esm/charts/{legend-utils.js → utils/legend-utils.js} +1 -75
- package/lib/esm/charts/utils/legend-utils.js.map +1 -0
- package/lib/esm/charts/utils/threshold.js +106 -0
- package/lib/esm/charts/utils/threshold.js.map +1 -0
- package/lib/esm/charts/{user-option-utils.js → utils/user-option-utils.js} +5 -14
- package/lib/esm/charts/utils/user-option-utils.js.map +1 -0
- package/lib/types/charts/Chart.d.ts +2 -2
- package/lib/types/charts/Chart.d.ts.map +1 -1
- package/lib/{esm/charts/types.js → types/charts/ChartContainer.d.ts} +14 -1
- package/lib/types/charts/ChartContainer.d.ts.map +1 -0
- package/lib/types/charts/ChartEmpty.d.ts +1 -1
- package/lib/types/charts/ChartEmpty.d.ts.map +1 -1
- package/lib/types/charts/ChartRender.d.ts +36 -0
- package/lib/types/charts/ChartRender.d.ts.map +1 -0
- package/lib/types/charts/ChartTooltip.d.ts +1 -1
- package/lib/types/charts/ChartTooltip.d.ts.map +1 -1
- package/lib/types/charts/Legend.d.ts +15 -3
- package/lib/types/charts/Legend.d.ts.map +1 -1
- package/lib/{cjs/charts/types.js → types/charts/LegendItem.d.ts} +10 -3
- package/lib/types/charts/LegendItem.d.ts.map +1 -0
- package/lib/types/charts/LegendLayout.d.ts +38 -0
- package/lib/types/charts/LegendLayout.d.ts.map +1 -0
- package/lib/types/charts/hooks/use-chart-instance.d.ts +62 -0
- package/lib/types/charts/hooks/use-chart-instance.d.ts.map +1 -0
- package/lib/types/charts/hooks/use-chart-option.d.ts +48 -0
- package/lib/types/charts/hooks/use-chart-option.d.ts.map +1 -0
- package/lib/types/charts/hooks/use-chart-refs.d.ts +38 -0
- package/lib/types/charts/hooks/use-chart-refs.d.ts.map +1 -0
- package/lib/types/charts/hooks/use-chart-zoom.d.ts +36 -0
- package/lib/types/charts/hooks/use-chart-zoom.d.ts.map +1 -0
- package/lib/types/charts/hooks/use-legend-interactions.d.ts +56 -0
- package/lib/types/charts/hooks/use-legend-interactions.d.ts.map +1 -0
- package/lib/types/charts/hooks/use-legend-series.d.ts +42 -0
- package/lib/types/charts/hooks/use-legend-series.d.ts.map +1 -0
- package/lib/types/charts/hooks/use-legend-visibility.d.ts +24 -0
- package/lib/types/charts/hooks/use-legend-visibility.d.ts.map +1 -0
- package/lib/types/charts/index.d.ts +2 -2
- package/lib/types/charts/index.d.ts.map +1 -1
- package/lib/types/charts/tests/chart-test-utils.d.ts +7 -1
- package/lib/types/charts/tests/chart-test-utils.d.ts.map +1 -1
- package/lib/types/charts/themes/ndl-echarts-theme.d.ts +1 -1
- package/lib/types/charts/themes/ndl-echarts-theme.d.ts.map +1 -1
- package/lib/types/charts/utils/aria-description.d.ts.map +1 -0
- package/lib/types/charts/utils/build-chart-option.d.ts +52 -0
- package/lib/types/charts/utils/build-chart-option.d.ts.map +1 -0
- package/lib/types/charts/utils/chart-tooltip-formatter.d.ts +37 -0
- package/lib/types/charts/utils/chart-tooltip-formatter.d.ts.map +1 -0
- package/lib/types/charts/{chart-types.d.ts → utils/chart-types.d.ts} +23 -22
- package/lib/types/charts/utils/chart-types.d.ts.map +1 -0
- package/lib/types/charts/utils/defaults.d.ts.map +1 -0
- package/lib/types/charts/{utils.d.ts → utils/format-utils.d.ts} +2 -4
- package/lib/types/charts/utils/format-utils.d.ts.map +1 -0
- package/lib/types/charts/utils/legend-layout.d.ts +37 -0
- package/lib/types/charts/utils/legend-layout.d.ts.map +1 -0
- package/lib/types/charts/{legend-utils.d.ts → utils/legend-utils.d.ts} +1 -11
- package/lib/types/charts/utils/legend-utils.d.ts.map +1 -0
- package/lib/types/charts/utils/threshold.d.ts +45 -0
- package/lib/types/charts/utils/threshold.d.ts.map +1 -0
- package/lib/types/charts/utils/user-option-utils.d.ts.map +1 -0
- package/package.json +3 -3
- package/lib/cjs/charts/aria-description.js.map +0 -1
- package/lib/cjs/charts/chart-types.js.map +0 -1
- package/lib/cjs/charts/defaults.js.map +0 -1
- package/lib/cjs/charts/legend-utils.js.map +0 -1
- package/lib/cjs/charts/types.js.map +0 -1
- package/lib/cjs/charts/user-option-utils.js.map +0 -1
- package/lib/cjs/charts/utils.js.map +0 -1
- package/lib/esm/charts/aria-description.js.map +0 -1
- package/lib/esm/charts/chart-types.js.map +0 -1
- package/lib/esm/charts/defaults.js.map +0 -1
- package/lib/esm/charts/legend-utils.js.map +0 -1
- package/lib/esm/charts/types.js.map +0 -1
- package/lib/esm/charts/user-option-utils.js.map +0 -1
- package/lib/esm/charts/utils.js.map +0 -1
- package/lib/types/charts/aria-description.d.ts.map +0 -1
- package/lib/types/charts/chart-types.d.ts.map +0 -1
- package/lib/types/charts/defaults.d.ts.map +0 -1
- package/lib/types/charts/legend-utils.d.ts.map +0 -1
- package/lib/types/charts/types.d.ts +0 -44
- package/lib/types/charts/types.d.ts.map +0 -1
- package/lib/types/charts/user-option-utils.d.ts.map +0 -1
- package/lib/types/charts/utils.d.ts.map +0 -1
- /package/lib/cjs/charts/{chart-types.js → utils/chart-types.js} +0 -0
- /package/lib/cjs/charts/{defaults.js → utils/defaults.js} +0 -0
- /package/lib/esm/charts/{chart-types.js → utils/chart-types.js} +0 -0
- /package/lib/esm/charts/{defaults.js → utils/defaults.js} +0 -0
- /package/lib/types/charts/{aria-description.d.ts → utils/aria-description.d.ts} +0 -0
- /package/lib/types/charts/{defaults.d.ts → utils/defaults.d.ts} +0 -0
- /package/lib/types/charts/{user-option-utils.d.ts → utils/user-option-utils.d.ts} +0 -0
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
36
|
+
var t = {};
|
|
37
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
38
|
+
t[p] = s[p];
|
|
39
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
40
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
41
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
42
|
+
t[p[i]] = s[p[i]];
|
|
43
|
+
}
|
|
44
|
+
return t;
|
|
45
|
+
};
|
|
46
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
47
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.LegendLayout = void 0;
|
|
51
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
|
52
|
+
/**
|
|
53
|
+
*
|
|
54
|
+
* Copyright (c) "Neo4j"
|
|
55
|
+
* Neo4j Sweden AB [http://neo4j.com]
|
|
56
|
+
*
|
|
57
|
+
* This file is part of Neo4j.
|
|
58
|
+
*
|
|
59
|
+
* Neo4j is free software: you can redistribute it and/or modify
|
|
60
|
+
* it under the terms of the GNU General Public License as published by
|
|
61
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
62
|
+
* (at your option) any later version.
|
|
63
|
+
*
|
|
64
|
+
* This program is distributed in the hope that it will be useful,
|
|
65
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
66
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
67
|
+
* GNU General Public License for more details.
|
|
68
|
+
*
|
|
69
|
+
* You should have received a copy of the GNU General Public License
|
|
70
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
71
|
+
*/
|
|
72
|
+
const react_1 = require("@neo4j-ndl/react");
|
|
73
|
+
const classnames_1 = __importDefault(require("classnames"));
|
|
74
|
+
const react_2 = __importStar(require("react"));
|
|
75
|
+
const legend_layout_1 = require("./utils/legend-layout");
|
|
76
|
+
const getLegendElementsContentHeight = (legendContent, elements) => {
|
|
77
|
+
const legendContentStyle = getComputedStyle(legendContent);
|
|
78
|
+
const paddingBottom = parseFloat(legendContentStyle.paddingBottom) || 0;
|
|
79
|
+
const elementsBottom = Math.max(...elements.map((element) => element.offsetTop + element.offsetHeight));
|
|
80
|
+
return elementsBottom + paddingBottom;
|
|
81
|
+
};
|
|
82
|
+
const getCollapsedLegendContentHeight = ({ availableRowWidth, elements, legendContent, }) => {
|
|
83
|
+
const legendContentStyle = getComputedStyle(legendContent);
|
|
84
|
+
const paddingTop = parseFloat(legendContentStyle.paddingTop) || 0;
|
|
85
|
+
const paddingBottom = parseFloat(legendContentStyle.paddingBottom) || 0;
|
|
86
|
+
const rowGap = parseFloat(legendContentStyle.rowGap) || 0;
|
|
87
|
+
let currentRowHeight = 0;
|
|
88
|
+
let currentRowWidth = 0;
|
|
89
|
+
const rowHeights = [];
|
|
90
|
+
elements.forEach((element) => {
|
|
91
|
+
const elementWidth = (0, legend_layout_1.getComputedElementWidth)(element);
|
|
92
|
+
const elementHeight = element.getBoundingClientRect().height;
|
|
93
|
+
const shouldWrap = currentRowWidth > 0 && currentRowWidth + elementWidth > availableRowWidth;
|
|
94
|
+
if (shouldWrap) {
|
|
95
|
+
rowHeights.push(currentRowHeight);
|
|
96
|
+
currentRowHeight = 0;
|
|
97
|
+
currentRowWidth = 0;
|
|
98
|
+
}
|
|
99
|
+
currentRowWidth += elementWidth;
|
|
100
|
+
currentRowHeight = Math.max(currentRowHeight, elementHeight);
|
|
101
|
+
});
|
|
102
|
+
if (currentRowHeight > 0) {
|
|
103
|
+
rowHeights.push(currentRowHeight);
|
|
104
|
+
}
|
|
105
|
+
const rowsHeight = rowHeights.reduce((height, rowHeight) => {
|
|
106
|
+
return height + rowHeight;
|
|
107
|
+
}, 0);
|
|
108
|
+
return (paddingTop +
|
|
109
|
+
rowsHeight +
|
|
110
|
+
rowGap * Math.max(rowHeights.length - 1, 0) +
|
|
111
|
+
paddingBottom);
|
|
112
|
+
};
|
|
113
|
+
/**
|
|
114
|
+
* Tracks legend container width for responsive collapsed-layout recalculation.
|
|
115
|
+
*
|
|
116
|
+
* The width is kept in state so `useCollapsibleLegendLayout` can re-measure item
|
|
117
|
+
* wrapping whenever the available legend width changes.
|
|
118
|
+
*/
|
|
119
|
+
const useLegendContainerWidth = (legendContainerRef) => {
|
|
120
|
+
const [legendWidth, setLegendWidth] = (0, react_2.useState)(Infinity);
|
|
121
|
+
const updateLegendWidth = (0, react_2.useCallback)(() => {
|
|
122
|
+
var _a;
|
|
123
|
+
const nextWidth = (_a = legendContainerRef.current) === null || _a === void 0 ? void 0 : _a.clientWidth;
|
|
124
|
+
if (nextWidth === undefined) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
setLegendWidth(nextWidth);
|
|
128
|
+
}, [legendContainerRef]);
|
|
129
|
+
(0, react_2.useEffect)(() => {
|
|
130
|
+
updateLegendWidth();
|
|
131
|
+
const legendContainer = legendContainerRef.current;
|
|
132
|
+
if (!legendContainer) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const resizeObserver = new ResizeObserver(updateLegendWidth);
|
|
136
|
+
resizeObserver.observe(legendContainer);
|
|
137
|
+
return () => {
|
|
138
|
+
resizeObserver.disconnect();
|
|
139
|
+
};
|
|
140
|
+
}, [legendContainerRef, updateLegendWidth]);
|
|
141
|
+
return legendWidth;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Owns the collapsed, measuring, and expanded layout state for wrapping legends.
|
|
145
|
+
*
|
|
146
|
+
* Collapsed legends only render the visible subset of items. When the item count
|
|
147
|
+
* or container width changes, the hook temporarily renders every item in an
|
|
148
|
+
* invisible measuring pass so it can calculate wrapping, overflow, and the next
|
|
149
|
+
* visible item count. The last collapsed height is preserved during that pass so
|
|
150
|
+
* the chart area does not shrink while the hidden full legend is being measured.
|
|
151
|
+
*/
|
|
152
|
+
const useCollapsibleLegendLayout = ({ itemCount, legendContainerRef, legendContentRef, legendMeasurementRef, viewMoreButtonMeasurementRef, }) => {
|
|
153
|
+
const [isExpanded, setIsExpanded] = (0, react_2.useState)(false);
|
|
154
|
+
const [isMeasuring, setIsMeasuring] = (0, react_2.useState)(false);
|
|
155
|
+
const [layoutSnapshot, setLayoutSnapshot] = (0, react_2.useState)({
|
|
156
|
+
contentHeight: 0,
|
|
157
|
+
hasOverflow: false,
|
|
158
|
+
visibleItemCount: itemCount,
|
|
159
|
+
});
|
|
160
|
+
const skipNextCollapseMeasurementRef = (0, react_2.useRef)(false);
|
|
161
|
+
const legendWidth = useLegendContainerWidth(legendContainerRef);
|
|
162
|
+
const updateVisibleItems = (0, react_2.useCallback)(() => {
|
|
163
|
+
var _a;
|
|
164
|
+
const legendContent = legendMeasurementRef.current;
|
|
165
|
+
const viewMoreButton = viewMoreButtonMeasurementRef.current;
|
|
166
|
+
if (!legendContent || !viewMoreButton) {
|
|
167
|
+
setIsMeasuring(false);
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
const legendItems = Array.from(legendContent.querySelectorAll('.ndl-chart-legend-item')).filter((element) => element.offsetParent !== null);
|
|
171
|
+
if (legendItems.length === 0) {
|
|
172
|
+
setLayoutSnapshot((snapshot) => (Object.assign(Object.assign({}, snapshot), { contentHeight: 0, hasOverflow: false, visibleItemCount: itemCount })));
|
|
173
|
+
setIsMeasuring(false);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
const rowTops = Array.from(new Set(legendItems.map((element) => element.offsetTop))).sort((a, b) => a - b);
|
|
177
|
+
const nextLegendContentHeight = legendContent.scrollHeight;
|
|
178
|
+
const nextLegendItemsContentHeight = getLegendElementsContentHeight(legendContent, legendItems);
|
|
179
|
+
if (rowTops.length <= legend_layout_1.COLLAPSED_LEGEND_ROWS) {
|
|
180
|
+
setLayoutSnapshot((snapshot) => (Object.assign(Object.assign({}, snapshot), { contentHeight: nextLegendItemsContentHeight, hasOverflow: false, visibleItemCount: itemCount })));
|
|
181
|
+
setIsMeasuring(false);
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const legendContainer = legendContainerRef.current;
|
|
185
|
+
const legendContentStyle = getComputedStyle(legendContent);
|
|
186
|
+
const availableRowWidth = ((_a = legendContainer === null || legendContainer === void 0 ? void 0 : legendContainer.clientWidth) !== null && _a !== void 0 ? _a : legendContent.clientWidth) -
|
|
187
|
+
(parseFloat(legendContentStyle.paddingLeft) || 0) -
|
|
188
|
+
(parseFloat(legendContentStyle.paddingRight) || 0);
|
|
189
|
+
const viewMoreButtonWidth = (0, legend_layout_1.getComputedElementWidth)(viewMoreButton);
|
|
190
|
+
const legendItemWidths = legendItems.map(legend_layout_1.getComputedElementWidth);
|
|
191
|
+
const nextVisibleItemCount = (0, legend_layout_1.getCollapsedVisibleItemCount)(legendItemWidths, availableRowWidth, viewMoreButtonWidth);
|
|
192
|
+
const nextCollapsedContentHeight = getCollapsedLegendContentHeight({
|
|
193
|
+
availableRowWidth,
|
|
194
|
+
elements: [...legendItems.slice(0, nextVisibleItemCount), viewMoreButton],
|
|
195
|
+
legendContent,
|
|
196
|
+
});
|
|
197
|
+
setLayoutSnapshot((snapshot) => (Object.assign(Object.assign({}, snapshot), { collapsedHeight: Math.min(nextCollapsedContentHeight, legend_layout_1.COLLAPSED_LEGEND_MAX_HEIGHT), contentHeight: nextLegendContentHeight, hasOverflow: nextVisibleItemCount < itemCount, visibleItemCount: nextVisibleItemCount })));
|
|
198
|
+
setIsMeasuring(false);
|
|
199
|
+
}, [
|
|
200
|
+
itemCount,
|
|
201
|
+
legendContainerRef,
|
|
202
|
+
legendMeasurementRef,
|
|
203
|
+
viewMoreButtonMeasurementRef,
|
|
204
|
+
]);
|
|
205
|
+
(0, react_2.useEffect)(() => {
|
|
206
|
+
setIsExpanded(false);
|
|
207
|
+
}, [itemCount]);
|
|
208
|
+
(0, react_2.useEffect)(() => {
|
|
209
|
+
if (isExpanded) {
|
|
210
|
+
setIsMeasuring(false);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
if (skipNextCollapseMeasurementRef.current) {
|
|
214
|
+
skipNextCollapseMeasurementRef.current = false;
|
|
215
|
+
setIsMeasuring(false);
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
setIsMeasuring(true);
|
|
219
|
+
}, [isExpanded, itemCount, legendWidth]);
|
|
220
|
+
(0, react_2.useEffect)(() => {
|
|
221
|
+
const isMeasuringCollapsed = !isExpanded && isMeasuring;
|
|
222
|
+
const animationFrame = requestAnimationFrame(() => {
|
|
223
|
+
if (isMeasuringCollapsed) {
|
|
224
|
+
updateVisibleItems();
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
setLayoutSnapshot((snapshot) => {
|
|
228
|
+
var _a, _b;
|
|
229
|
+
return (Object.assign(Object.assign({}, snapshot), { contentHeight: (_b = (_a = legendContentRef.current) === null || _a === void 0 ? void 0 : _a.scrollHeight) !== null && _b !== void 0 ? _b : 0 }));
|
|
230
|
+
});
|
|
231
|
+
if (!isMeasuring && !isExpanded && layoutSnapshot.hasOverflow) {
|
|
232
|
+
setLayoutSnapshot((snapshot) => {
|
|
233
|
+
var _a;
|
|
234
|
+
return (Object.assign(Object.assign({}, snapshot), { collapsedHeight: (_a = legendContentRef.current) === null || _a === void 0 ? void 0 : _a.getBoundingClientRect().height }));
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
return () => {
|
|
240
|
+
cancelAnimationFrame(animationFrame);
|
|
241
|
+
};
|
|
242
|
+
}, [
|
|
243
|
+
isExpanded,
|
|
244
|
+
isMeasuring,
|
|
245
|
+
legendContentRef,
|
|
246
|
+
layoutSnapshot.hasOverflow,
|
|
247
|
+
updateVisibleItems,
|
|
248
|
+
]);
|
|
249
|
+
const expandLegend = (0, react_2.useCallback)(() => {
|
|
250
|
+
setIsMeasuring(false);
|
|
251
|
+
setIsExpanded(true);
|
|
252
|
+
}, []);
|
|
253
|
+
const collapseLegend = (0, react_2.useCallback)(() => {
|
|
254
|
+
skipNextCollapseMeasurementRef.current = true;
|
|
255
|
+
setIsExpanded(false);
|
|
256
|
+
}, []);
|
|
257
|
+
return {
|
|
258
|
+
collapseLegend,
|
|
259
|
+
expandLegend,
|
|
260
|
+
isExpanded,
|
|
261
|
+
isMeasuring,
|
|
262
|
+
layoutSnapshot,
|
|
263
|
+
};
|
|
264
|
+
};
|
|
265
|
+
/**
|
|
266
|
+
* Renders the responsive legend layout shell.
|
|
267
|
+
*
|
|
268
|
+
* The component switches between a two-row collapsed view, an invisible
|
|
269
|
+
* measurement view, and an expanded scrollable view while keeping the
|
|
270
|
+
* "View more"/"View less" action wired to the measured overflow state.
|
|
271
|
+
*/
|
|
272
|
+
const LegendLayout = (_a) => {
|
|
273
|
+
var { children, className, isLayoutReady = true, itemCount, onLayoutReady, htmlAttributes } = _a, restProps = __rest(_a, ["children", "className", "isLayoutReady", "itemCount", "onLayoutReady", "htmlAttributes"]);
|
|
274
|
+
const legendContainerRef = (0, react_2.useRef)(null);
|
|
275
|
+
const legendContentRef = (0, react_2.useRef)(null);
|
|
276
|
+
const legendMeasurementRef = (0, react_2.useRef)(null);
|
|
277
|
+
const pendingFocusLegendItemIndexRef = (0, react_2.useRef)(null);
|
|
278
|
+
const viewMoreButtonMeasurementRef = (0, react_2.useRef)(null);
|
|
279
|
+
const { collapseLegend, expandLegend, isExpanded, isMeasuring, layoutSnapshot, } = useCollapsibleLegendLayout({
|
|
280
|
+
itemCount,
|
|
281
|
+
legendContainerRef,
|
|
282
|
+
legendContentRef,
|
|
283
|
+
legendMeasurementRef,
|
|
284
|
+
viewMoreButtonMeasurementRef,
|
|
285
|
+
});
|
|
286
|
+
const childList = react_2.default.Children.toArray(children);
|
|
287
|
+
const childrenToRender = !isExpanded
|
|
288
|
+
? childList.slice(0, layoutSnapshot.visibleItemCount)
|
|
289
|
+
: childList;
|
|
290
|
+
const legendHeight = !isMeasuring && !isExpanded && layoutSnapshot.hasOverflow
|
|
291
|
+
? layoutSnapshot.collapsedHeight
|
|
292
|
+
: !isMeasuring &&
|
|
293
|
+
!layoutSnapshot.hasOverflow &&
|
|
294
|
+
layoutSnapshot.contentHeight
|
|
295
|
+
? layoutSnapshot.contentHeight
|
|
296
|
+
: undefined;
|
|
297
|
+
(0, react_2.useEffect)(() => {
|
|
298
|
+
if (!isMeasuring && layoutSnapshot.contentHeight > 0) {
|
|
299
|
+
let secondFrame;
|
|
300
|
+
const firstFrame = requestAnimationFrame(() => {
|
|
301
|
+
secondFrame = requestAnimationFrame(() => {
|
|
302
|
+
onLayoutReady === null || onLayoutReady === void 0 ? void 0 : onLayoutReady();
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
return () => {
|
|
306
|
+
cancelAnimationFrame(firstFrame);
|
|
307
|
+
if (secondFrame !== undefined) {
|
|
308
|
+
cancelAnimationFrame(secondFrame);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
}, [isMeasuring, layoutSnapshot.contentHeight, onLayoutReady]);
|
|
313
|
+
(0, react_2.useEffect)(() => {
|
|
314
|
+
var _a, _b;
|
|
315
|
+
const pendingFocusLegendItemIndex = pendingFocusLegendItemIndexRef.current;
|
|
316
|
+
if (!isExpanded || pendingFocusLegendItemIndex === null) {
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
const legendItems = (_a = legendContentRef.current) === null || _a === void 0 ? void 0 : _a.querySelectorAll('.ndl-chart-legend-item');
|
|
320
|
+
(_b = legendItems === null || legendItems === void 0 ? void 0 : legendItems[pendingFocusLegendItemIndex]) === null || _b === void 0 ? void 0 : _b.focus();
|
|
321
|
+
pendingFocusLegendItemIndexRef.current = null;
|
|
322
|
+
}, [isExpanded]);
|
|
323
|
+
const handleLegendActionClick = (0, react_2.useCallback)(() => {
|
|
324
|
+
if (isExpanded) {
|
|
325
|
+
collapseLegend();
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
pendingFocusLegendItemIndexRef.current = layoutSnapshot.visibleItemCount;
|
|
329
|
+
expandLegend();
|
|
330
|
+
}, [
|
|
331
|
+
collapseLegend,
|
|
332
|
+
expandLegend,
|
|
333
|
+
isExpanded,
|
|
334
|
+
layoutSnapshot.visibleItemCount,
|
|
335
|
+
]);
|
|
336
|
+
const classes = (0, classnames_1.default)('ndl-chart-legend', {
|
|
337
|
+
'ndl-chart-legend-calculating': !isExpanded && isMeasuring,
|
|
338
|
+
'ndl-chart-legend-collapsed': layoutSnapshot.hasOverflow && !isExpanded,
|
|
339
|
+
'ndl-chart-legend-expanded': layoutSnapshot.hasOverflow && isExpanded,
|
|
340
|
+
'ndl-chart-legend-hidden': !isLayoutReady,
|
|
341
|
+
'ndl-chart-legend-scrollable': layoutSnapshot.hasOverflow &&
|
|
342
|
+
isExpanded &&
|
|
343
|
+
layoutSnapshot.contentHeight > legend_layout_1.COLLAPSED_LEGEND_MAX_HEIGHT,
|
|
344
|
+
'ndl-chart-legend-wrapping': true,
|
|
345
|
+
}, className);
|
|
346
|
+
return ((0, jsx_runtime_1.jsx)("div", Object.assign({ ref: legendContainerRef, className: "ndl-chart-legend-container" }, restProps, htmlAttributes, { children: (0, jsx_runtime_1.jsxs)("div", { className: classes, ref: legendContentRef, style: {
|
|
347
|
+
height: legendHeight,
|
|
348
|
+
maxHeight: layoutSnapshot.hasOverflow && isExpanded
|
|
349
|
+
? 'var(--ndl-chart-legend-expanded-max-height)'
|
|
350
|
+
: layoutSnapshot.hasOverflow
|
|
351
|
+
? legend_layout_1.COLLAPSED_LEGEND_MAX_HEIGHT
|
|
352
|
+
: undefined,
|
|
353
|
+
}, children: [childrenToRender, layoutSnapshot.hasOverflow && ((0, jsx_runtime_1.jsx)(react_1.TextLink, { as: "button", className: "ndl-chart-legend-action", htmlAttributes: {
|
|
354
|
+
'aria-expanded': isExpanded,
|
|
355
|
+
onClick: handleLegendActionClick,
|
|
356
|
+
type: 'button',
|
|
357
|
+
}, children: isExpanded ? 'View less' : 'View more' })), isMeasuring && ((0, jsx_runtime_1.jsxs)("div", { "aria-hidden": "true", className: "ndl-chart-legend-measurement", ref: legendMeasurementRef, children: [childList, (0, jsx_runtime_1.jsx)(react_1.TextLink, { as: "button", ref: viewMoreButtonMeasurementRef, className: "ndl-chart-legend-action", htmlAttributes: {
|
|
358
|
+
tabIndex: -1,
|
|
359
|
+
type: 'button',
|
|
360
|
+
}, children: "View more" })] }))] }) })));
|
|
361
|
+
};
|
|
362
|
+
exports.LegendLayout = LegendLayout;
|
|
363
|
+
//# sourceMappingURL=LegendLayout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LegendLayout.js","sourceRoot":"","sources":["../../../src/charts/LegendLayout.tsx"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport { TextLink } from '@neo4j-ndl/react';\nimport classNames from 'classnames';\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { type CommonProps } from './utils/chart-types';\nimport {\n COLLAPSED_LEGEND_MAX_HEIGHT,\n COLLAPSED_LEGEND_ROWS,\n getCollapsedVisibleItemCount,\n getComputedElementWidth,\n} from './utils/legend-layout';\n\ntype LegendLayoutProps = {\n children: React.ReactNode;\n isLayoutReady?: boolean;\n itemCount: number;\n onLayoutReady?: () => void;\n};\n\ntype LegendLayoutSnapshot = {\n collapsedHeight?: number;\n contentHeight: number;\n hasOverflow: boolean;\n visibleItemCount: number;\n};\n\nconst getLegendElementsContentHeight = (\n legendContent: HTMLElement,\n elements: HTMLElement[],\n) => {\n const legendContentStyle = getComputedStyle(legendContent);\n const paddingBottom = parseFloat(legendContentStyle.paddingBottom) || 0;\n const elementsBottom = Math.max(\n ...elements.map((element) => element.offsetTop + element.offsetHeight),\n );\n\n return elementsBottom + paddingBottom;\n};\n\nconst getCollapsedLegendContentHeight = ({\n availableRowWidth,\n elements,\n legendContent,\n}: {\n availableRowWidth: number;\n elements: HTMLElement[];\n legendContent: HTMLElement;\n}) => {\n const legendContentStyle = getComputedStyle(legendContent);\n const paddingTop = parseFloat(legendContentStyle.paddingTop) || 0;\n const paddingBottom = parseFloat(legendContentStyle.paddingBottom) || 0;\n const rowGap = parseFloat(legendContentStyle.rowGap) || 0;\n let currentRowHeight = 0;\n let currentRowWidth = 0;\n const rowHeights: number[] = [];\n\n elements.forEach((element) => {\n const elementWidth = getComputedElementWidth(element);\n const elementHeight = element.getBoundingClientRect().height;\n const shouldWrap =\n currentRowWidth > 0 && currentRowWidth + elementWidth > availableRowWidth;\n\n if (shouldWrap) {\n rowHeights.push(currentRowHeight);\n currentRowHeight = 0;\n currentRowWidth = 0;\n }\n\n currentRowWidth += elementWidth;\n currentRowHeight = Math.max(currentRowHeight, elementHeight);\n });\n\n if (currentRowHeight > 0) {\n rowHeights.push(currentRowHeight);\n }\n\n const rowsHeight = rowHeights.reduce((height, rowHeight) => {\n return height + rowHeight;\n }, 0);\n\n return (\n paddingTop +\n rowsHeight +\n rowGap * Math.max(rowHeights.length - 1, 0) +\n paddingBottom\n );\n};\n\n/**\n * Tracks legend container width for responsive collapsed-layout recalculation.\n *\n * The width is kept in state so `useCollapsibleLegendLayout` can re-measure item\n * wrapping whenever the available legend width changes.\n */\nconst useLegendContainerWidth = (\n legendContainerRef: React.RefObject<HTMLDivElement | null>,\n) => {\n const [legendWidth, setLegendWidth] = useState(Infinity);\n\n const updateLegendWidth = useCallback(() => {\n const nextWidth = legendContainerRef.current?.clientWidth;\n if (nextWidth === undefined) {\n return;\n }\n\n setLegendWidth(nextWidth);\n }, [legendContainerRef]);\n\n useEffect(() => {\n updateLegendWidth();\n\n const legendContainer = legendContainerRef.current;\n if (!legendContainer) {\n return;\n }\n\n const resizeObserver = new ResizeObserver(updateLegendWidth);\n resizeObserver.observe(legendContainer);\n\n return () => {\n resizeObserver.disconnect();\n };\n }, [legendContainerRef, updateLegendWidth]);\n\n return legendWidth;\n};\n\n/**\n * Owns the collapsed, measuring, and expanded layout state for wrapping legends.\n *\n * Collapsed legends only render the visible subset of items. When the item count\n * or container width changes, the hook temporarily renders every item in an\n * invisible measuring pass so it can calculate wrapping, overflow, and the next\n * visible item count. The last collapsed height is preserved during that pass so\n * the chart area does not shrink while the hidden full legend is being measured.\n */\nconst useCollapsibleLegendLayout = ({\n itemCount,\n legendContainerRef,\n legendContentRef,\n legendMeasurementRef,\n viewMoreButtonMeasurementRef,\n}: {\n itemCount: number;\n legendContainerRef: React.RefObject<HTMLDivElement | null>;\n legendContentRef: React.RefObject<HTMLDivElement | null>;\n legendMeasurementRef: React.RefObject<HTMLDivElement | null>;\n viewMoreButtonMeasurementRef: React.RefObject<HTMLButtonElement | null>;\n}) => {\n const [isExpanded, setIsExpanded] = useState(false);\n const [isMeasuring, setIsMeasuring] = useState(false);\n const [layoutSnapshot, setLayoutSnapshot] = useState<LegendLayoutSnapshot>({\n contentHeight: 0,\n hasOverflow: false,\n visibleItemCount: itemCount,\n });\n const skipNextCollapseMeasurementRef = useRef(false);\n const legendWidth = useLegendContainerWidth(legendContainerRef);\n\n const updateVisibleItems = useCallback(() => {\n const legendContent = legendMeasurementRef.current;\n const viewMoreButton = viewMoreButtonMeasurementRef.current;\n if (!legendContent || !viewMoreButton) {\n setIsMeasuring(false);\n return;\n }\n\n const legendItems = Array.from(\n legendContent.querySelectorAll<HTMLElement>('.ndl-chart-legend-item'),\n ).filter((element) => element.offsetParent !== null);\n\n if (legendItems.length === 0) {\n setLayoutSnapshot((snapshot) => ({\n ...snapshot,\n contentHeight: 0,\n hasOverflow: false,\n visibleItemCount: itemCount,\n }));\n setIsMeasuring(false);\n return;\n }\n\n const rowTops = Array.from(\n new Set(legendItems.map((element) => element.offsetTop)),\n ).sort((a, b) => a - b);\n const nextLegendContentHeight = legendContent.scrollHeight;\n const nextLegendItemsContentHeight = getLegendElementsContentHeight(\n legendContent,\n legendItems,\n );\n\n if (rowTops.length <= COLLAPSED_LEGEND_ROWS) {\n setLayoutSnapshot((snapshot) => ({\n ...snapshot,\n contentHeight: nextLegendItemsContentHeight,\n hasOverflow: false,\n visibleItemCount: itemCount,\n }));\n setIsMeasuring(false);\n return;\n }\n\n const legendContainer = legendContainerRef.current;\n const legendContentStyle = getComputedStyle(legendContent);\n const availableRowWidth =\n (legendContainer?.clientWidth ?? legendContent.clientWidth) -\n (parseFloat(legendContentStyle.paddingLeft) || 0) -\n (parseFloat(legendContentStyle.paddingRight) || 0);\n const viewMoreButtonWidth = getComputedElementWidth(viewMoreButton);\n const legendItemWidths = legendItems.map(getComputedElementWidth);\n const nextVisibleItemCount = getCollapsedVisibleItemCount(\n legendItemWidths,\n availableRowWidth,\n viewMoreButtonWidth,\n );\n const nextCollapsedContentHeight = getCollapsedLegendContentHeight({\n availableRowWidth,\n elements: [...legendItems.slice(0, nextVisibleItemCount), viewMoreButton],\n legendContent,\n });\n\n setLayoutSnapshot((snapshot) => ({\n ...snapshot,\n collapsedHeight: Math.min(\n nextCollapsedContentHeight,\n COLLAPSED_LEGEND_MAX_HEIGHT,\n ),\n contentHeight: nextLegendContentHeight,\n hasOverflow: nextVisibleItemCount < itemCount,\n visibleItemCount: nextVisibleItemCount,\n }));\n setIsMeasuring(false);\n }, [\n itemCount,\n legendContainerRef,\n legendMeasurementRef,\n viewMoreButtonMeasurementRef,\n ]);\n\n useEffect(() => {\n setIsExpanded(false);\n }, [itemCount]);\n\n useEffect(() => {\n if (isExpanded) {\n setIsMeasuring(false);\n return;\n }\n\n if (skipNextCollapseMeasurementRef.current) {\n skipNextCollapseMeasurementRef.current = false;\n setIsMeasuring(false);\n return;\n }\n\n setIsMeasuring(true);\n }, [isExpanded, itemCount, legendWidth]);\n\n useEffect(() => {\n const isMeasuringCollapsed = !isExpanded && isMeasuring;\n\n const animationFrame = requestAnimationFrame(() => {\n if (isMeasuringCollapsed) {\n updateVisibleItems();\n } else {\n setLayoutSnapshot((snapshot) => ({\n ...snapshot,\n contentHeight: legendContentRef.current?.scrollHeight ?? 0,\n }));\n\n if (!isMeasuring && !isExpanded && layoutSnapshot.hasOverflow) {\n setLayoutSnapshot((snapshot) => ({\n ...snapshot,\n collapsedHeight:\n legendContentRef.current?.getBoundingClientRect().height,\n }));\n }\n }\n });\n\n return () => {\n cancelAnimationFrame(animationFrame);\n };\n }, [\n isExpanded,\n isMeasuring,\n legendContentRef,\n layoutSnapshot.hasOverflow,\n updateVisibleItems,\n ]);\n\n const expandLegend = useCallback(() => {\n setIsMeasuring(false);\n setIsExpanded(true);\n }, []);\n\n const collapseLegend = useCallback(() => {\n skipNextCollapseMeasurementRef.current = true;\n setIsExpanded(false);\n }, []);\n\n return {\n collapseLegend,\n expandLegend,\n isExpanded,\n isMeasuring,\n layoutSnapshot,\n };\n};\n\n/**\n * Renders the responsive legend layout shell.\n *\n * The component switches between a two-row collapsed view, an invisible\n * measurement view, and an expanded scrollable view while keeping the\n * \"View more\"/\"View less\" action wired to the measured overflow state.\n */\nexport const LegendLayout = ({\n children,\n className,\n isLayoutReady = true,\n itemCount,\n onLayoutReady,\n htmlAttributes,\n ...restProps\n}: Omit<CommonProps<'div', LegendLayoutProps>, 'ref'>) => {\n const legendContainerRef = useRef<HTMLDivElement>(null);\n const legendContentRef = useRef<HTMLDivElement>(null);\n const legendMeasurementRef = useRef<HTMLDivElement>(null);\n const pendingFocusLegendItemIndexRef = useRef<number | null>(null);\n const viewMoreButtonMeasurementRef = useRef<HTMLButtonElement>(null);\n const {\n collapseLegend,\n expandLegend,\n isExpanded,\n isMeasuring,\n layoutSnapshot,\n } = useCollapsibleLegendLayout({\n itemCount,\n legendContainerRef,\n legendContentRef,\n legendMeasurementRef,\n viewMoreButtonMeasurementRef,\n });\n\n const childList = React.Children.toArray(children);\n const childrenToRender = !isExpanded\n ? childList.slice(0, layoutSnapshot.visibleItemCount)\n : childList;\n const legendHeight =\n !isMeasuring && !isExpanded && layoutSnapshot.hasOverflow\n ? layoutSnapshot.collapsedHeight\n : !isMeasuring &&\n !layoutSnapshot.hasOverflow &&\n layoutSnapshot.contentHeight\n ? layoutSnapshot.contentHeight\n : undefined;\n\n useEffect(() => {\n if (!isMeasuring && layoutSnapshot.contentHeight > 0) {\n let secondFrame: number | undefined;\n const firstFrame = requestAnimationFrame(() => {\n secondFrame = requestAnimationFrame(() => {\n onLayoutReady?.();\n });\n });\n\n return () => {\n cancelAnimationFrame(firstFrame);\n if (secondFrame !== undefined) {\n cancelAnimationFrame(secondFrame);\n }\n };\n }\n }, [isMeasuring, layoutSnapshot.contentHeight, onLayoutReady]);\n\n useEffect(() => {\n const pendingFocusLegendItemIndex = pendingFocusLegendItemIndexRef.current;\n if (!isExpanded || pendingFocusLegendItemIndex === null) {\n return;\n }\n\n const legendItems = legendContentRef.current?.querySelectorAll<HTMLElement>(\n '.ndl-chart-legend-item',\n );\n legendItems?.[pendingFocusLegendItemIndex]?.focus();\n pendingFocusLegendItemIndexRef.current = null;\n }, [isExpanded]);\n\n const handleLegendActionClick = useCallback(() => {\n if (isExpanded) {\n collapseLegend();\n return;\n }\n\n pendingFocusLegendItemIndexRef.current = layoutSnapshot.visibleItemCount;\n expandLegend();\n }, [\n collapseLegend,\n expandLegend,\n isExpanded,\n layoutSnapshot.visibleItemCount,\n ]);\n\n const classes = classNames(\n 'ndl-chart-legend',\n {\n 'ndl-chart-legend-calculating': !isExpanded && isMeasuring,\n 'ndl-chart-legend-collapsed': layoutSnapshot.hasOverflow && !isExpanded,\n 'ndl-chart-legend-expanded': layoutSnapshot.hasOverflow && isExpanded,\n 'ndl-chart-legend-hidden': !isLayoutReady,\n 'ndl-chart-legend-scrollable':\n layoutSnapshot.hasOverflow &&\n isExpanded &&\n layoutSnapshot.contentHeight > COLLAPSED_LEGEND_MAX_HEIGHT,\n 'ndl-chart-legend-wrapping': true,\n },\n className,\n );\n return (\n <div\n ref={legendContainerRef}\n className=\"ndl-chart-legend-container\"\n {...restProps}\n {...htmlAttributes}\n >\n <div\n className={classes}\n ref={legendContentRef}\n style={{\n height: legendHeight,\n maxHeight:\n layoutSnapshot.hasOverflow && isExpanded\n ? 'var(--ndl-chart-legend-expanded-max-height)'\n : layoutSnapshot.hasOverflow\n ? COLLAPSED_LEGEND_MAX_HEIGHT\n : undefined,\n }}\n >\n {childrenToRender}\n {layoutSnapshot.hasOverflow && (\n <TextLink\n as=\"button\"\n className=\"ndl-chart-legend-action\"\n htmlAttributes={{\n 'aria-expanded': isExpanded,\n onClick: handleLegendActionClick,\n type: 'button',\n }}\n >\n {isExpanded ? 'View less' : 'View more'}\n </TextLink>\n )}\n {isMeasuring && (\n <div\n aria-hidden=\"true\"\n className=\"ndl-chart-legend-measurement\"\n ref={legendMeasurementRef}\n >\n {childList}\n <TextLink\n as=\"button\"\n ref={viewMoreButtonMeasurementRef}\n className=\"ndl-chart-legend-action\"\n htmlAttributes={{\n tabIndex: -1,\n type: 'button',\n }}\n >\n View more\n </TextLink>\n </div>\n )}\n </div>\n </div>\n );\n};\n"]}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) "Neo4j"
|
|
5
|
+
* Neo4j Sweden AB [http://neo4j.com]
|
|
6
|
+
*
|
|
7
|
+
* This file is part of Neo4j.
|
|
8
|
+
*
|
|
9
|
+
* Neo4j is free software: you can redistribute it and/or modify
|
|
10
|
+
* it under the terms of the GNU General Public License as published by
|
|
11
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
12
|
+
* (at your option) any later version.
|
|
13
|
+
*
|
|
14
|
+
* This program is distributed in the hope that it will be useful,
|
|
15
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
* GNU General Public License for more details.
|
|
18
|
+
*
|
|
19
|
+
* You should have received a copy of the GNU General Public License
|
|
20
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.useChartLifecycle = useChartLifecycle;
|
|
24
|
+
exports.useChartLoading = useChartLoading;
|
|
25
|
+
exports.useChartResize = useChartResize;
|
|
26
|
+
const base_1 = require("@neo4j-ndl/base");
|
|
27
|
+
const echarts_1 = require("echarts");
|
|
28
|
+
const react_1 = require("react");
|
|
29
|
+
const ndl_echarts_theme_1 = require("../themes/ndl-echarts-theme");
|
|
30
|
+
const use_chart_refs_1 = require("./use-chart-refs");
|
|
31
|
+
/**
|
|
32
|
+
* Registers Needle ECharts themes and initializes the chart instance.
|
|
33
|
+
*
|
|
34
|
+
* Theme registration runs with the active palette so ECharts can resolve Needle
|
|
35
|
+
* colors before options are applied. The hook only calls `init` when the DOM
|
|
36
|
+
* element does not already have an ECharts instance, allowing later renders to
|
|
37
|
+
* update registered theme data without replacing the existing chart.
|
|
38
|
+
*/
|
|
39
|
+
function useChartLifecycle({ palette, theme }) {
|
|
40
|
+
const { chartEchartRef } = (0, use_chart_refs_1.useChartRefsContext)();
|
|
41
|
+
(0, react_1.useEffect)(() => {
|
|
42
|
+
if (chartEchartRef.current === null) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
(0, echarts_1.registerTheme)('ndl-light', (0, ndl_echarts_theme_1.ndlEchartsTheme)('light', palette));
|
|
46
|
+
(0, echarts_1.registerTheme)('ndl-dark', (0, ndl_echarts_theme_1.ndlEchartsTheme)('dark', palette));
|
|
47
|
+
const currentChart = (0, echarts_1.getInstanceByDom)(chartEchartRef.current);
|
|
48
|
+
if (currentChart) {
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
const echartsTheme = theme === 'light' ? 'ndl-light' : 'ndl-dark';
|
|
52
|
+
(0, echarts_1.init)(chartEchartRef.current, echartsTheme, {
|
|
53
|
+
renderer: 'svg',
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Mirrors React loading state into ECharts' loading overlay.
|
|
59
|
+
*
|
|
60
|
+
* The overlay also stays visible while the chart waits for its first resize,
|
|
61
|
+
* preventing users from seeing an unmeasured SVG before ECharts has been sized
|
|
62
|
+
* to its container. Loading colors come from the active Needle theme.
|
|
63
|
+
*/
|
|
64
|
+
function useChartLoading({ isLoading, isWaitingForFirstResize, theme, }) {
|
|
65
|
+
const { chartEchartRef } = (0, use_chart_refs_1.useChartRefsContext)();
|
|
66
|
+
(0, react_1.useEffect)(() => {
|
|
67
|
+
if (chartEchartRef.current === null) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const chart = (0, echarts_1.getInstanceByDom)(chartEchartRef.current);
|
|
71
|
+
if (isLoading === true || isWaitingForFirstResize) {
|
|
72
|
+
chart === null || chart === void 0 ? void 0 : chart.showLoading({
|
|
73
|
+
color: base_1.tokens.theme[theme].color.primary.bg.status,
|
|
74
|
+
fontFamily: base_1.tokens.typography['label'].fontFamily,
|
|
75
|
+
fontSize: base_1.tokens.typography['label'].fontSize,
|
|
76
|
+
fontWeight: base_1.tokens.typography['label'].fontWeight,
|
|
77
|
+
maskColor: `rgb( from ${base_1.tokens.theme[theme].color.neutral.text.inverse} r g b / 0.8)`,
|
|
78
|
+
text: 'Loading',
|
|
79
|
+
textColor: base_1.tokens.theme[theme].color.neutral.text.default,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
chart === null || chart === void 0 ? void 0 : chart.hideLoading();
|
|
84
|
+
}
|
|
85
|
+
}, [chartEchartRef, isLoading, isWaitingForFirstResize, theme]);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Keeps the ECharts canvas sized to the DOM box assigned by the chart layout.
|
|
89
|
+
*
|
|
90
|
+
* The hook listens to both window resize events and direct element resize
|
|
91
|
+
* observations because the chart can change size through parent layout changes
|
|
92
|
+
* that do not emit a window resize. It exposes `isWaitingForFirstResize` so the
|
|
93
|
+
* rest of the chart can delay rendering dependent UI until ECharts has been
|
|
94
|
+
* given its initial dimensions.
|
|
95
|
+
*/
|
|
96
|
+
function useChartResize() {
|
|
97
|
+
const { chartEchartRef } = (0, use_chart_refs_1.useChartRefsContext)();
|
|
98
|
+
const [isWaitingForFirstResize, setIsWaitingForFirstResize] = (0, react_1.useState)(true);
|
|
99
|
+
const resizeChart = (0, react_1.useCallback)(() => {
|
|
100
|
+
if (chartEchartRef.current === null) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
const chart = (0, echarts_1.getInstanceByDom)(chartEchartRef.current);
|
|
104
|
+
const { clientHeight: height, clientWidth: width } = chartEchartRef.current;
|
|
105
|
+
chart === null || chart === void 0 ? void 0 : chart.resize({
|
|
106
|
+
height,
|
|
107
|
+
width,
|
|
108
|
+
});
|
|
109
|
+
}, [chartEchartRef]);
|
|
110
|
+
(0, react_1.useEffect)(() => {
|
|
111
|
+
window.addEventListener('resize', resizeChart);
|
|
112
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
113
|
+
resizeChart();
|
|
114
|
+
});
|
|
115
|
+
if (chartEchartRef.current) {
|
|
116
|
+
resizeObserver.observe(chartEchartRef.current);
|
|
117
|
+
}
|
|
118
|
+
const animationFrame = requestAnimationFrame(() => {
|
|
119
|
+
resizeChart();
|
|
120
|
+
setIsWaitingForFirstResize(false);
|
|
121
|
+
});
|
|
122
|
+
return () => {
|
|
123
|
+
cancelAnimationFrame(animationFrame);
|
|
124
|
+
window.removeEventListener('resize', resizeChart);
|
|
125
|
+
resizeObserver.disconnect();
|
|
126
|
+
};
|
|
127
|
+
}, [chartEchartRef, resizeChart]);
|
|
128
|
+
return {
|
|
129
|
+
isWaitingForFirstResize,
|
|
130
|
+
resizeChart,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=use-chart-instance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-chart-instance.js","sourceRoot":"","sources":["../../../../src/charts/hooks/use-chart-instance.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n *\n * Copyright (c) \"Neo4j\"\n * Neo4j Sweden AB [http://neo4j.com]\n *\n * This file is part of Neo4j.\n *\n * Neo4j is free software: you can redistribute it and/or modify\n * it under the terms of the GNU General Public License as published by\n * the Free Software Foundation, either version 3 of the License, or\n * (at your option) any later version.\n *\n * This program is distributed in the hope that it will be useful,\n * but WITHOUT ANY WARRANTY; without even the implied warranty of\n * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n * GNU General Public License for more details.\n *\n * You should have received a copy of the GNU General Public License\n * along with this program. If not, see <http://www.gnu.org/licenses/>.\n */\n\nimport { tokens } from '@neo4j-ndl/base';\nimport { getInstanceByDom, init, registerTheme } from 'echarts';\nimport { useCallback, useEffect, useState } from 'react';\n\nimport { ndlEchartsTheme } from '../themes/ndl-echarts-theme';\nimport type { HexColor } from '../utils/chart-types';\nimport { useChartRefsContext } from './use-chart-refs';\n\ntype UseChartLifecycleParams = {\n palette?: HexColor[];\n theme: 'light' | 'dark';\n};\n\ntype UseChartLoadingParams = {\n isLoading?: boolean;\n isWaitingForFirstResize: boolean;\n theme: 'light' | 'dark';\n};\n\n/**\n * Registers Needle ECharts themes and initializes the chart instance.\n *\n * Theme registration runs with the active palette so ECharts can resolve Needle\n * colors before options are applied. The hook only calls `init` when the DOM\n * element does not already have an ECharts instance, allowing later renders to\n * update registered theme data without replacing the existing chart.\n */\nexport function useChartLifecycle({ palette, theme }: UseChartLifecycleParams) {\n const { chartEchartRef } = useChartRefsContext();\n\n useEffect(() => {\n if (chartEchartRef.current === null) {\n return;\n }\n\n registerTheme('ndl-light', ndlEchartsTheme('light', palette));\n registerTheme('ndl-dark', ndlEchartsTheme('dark', palette));\n\n const currentChart = getInstanceByDom(chartEchartRef.current);\n if (currentChart) {\n return;\n }\n\n const echartsTheme = theme === 'light' ? 'ndl-light' : 'ndl-dark';\n init(chartEchartRef.current, echartsTheme, {\n renderer: 'svg',\n });\n });\n}\n\n/**\n * Mirrors React loading state into ECharts' loading overlay.\n *\n * The overlay also stays visible while the chart waits for its first resize,\n * preventing users from seeing an unmeasured SVG before ECharts has been sized\n * to its container. Loading colors come from the active Needle theme.\n */\nexport function useChartLoading({\n isLoading,\n isWaitingForFirstResize,\n theme,\n}: UseChartLoadingParams) {\n const { chartEchartRef } = useChartRefsContext();\n\n useEffect(() => {\n if (chartEchartRef.current === null) {\n return;\n }\n\n const chart = getInstanceByDom(chartEchartRef.current);\n\n if (isLoading === true || isWaitingForFirstResize) {\n chart?.showLoading({\n color: tokens.theme[theme].color.primary.bg.status,\n fontFamily: tokens.typography['label'].fontFamily,\n fontSize: tokens.typography['label'].fontSize,\n fontWeight: tokens.typography['label'].fontWeight,\n maskColor: `rgb( from ${tokens.theme[theme].color.neutral.text.inverse} r g b / 0.8)`,\n text: 'Loading',\n textColor: tokens.theme[theme].color.neutral.text.default,\n });\n } else {\n chart?.hideLoading();\n }\n }, [chartEchartRef, isLoading, isWaitingForFirstResize, theme]);\n}\n\n/**\n * Keeps the ECharts canvas sized to the DOM box assigned by the chart layout.\n *\n * The hook listens to both window resize events and direct element resize\n * observations because the chart can change size through parent layout changes\n * that do not emit a window resize. It exposes `isWaitingForFirstResize` so the\n * rest of the chart can delay rendering dependent UI until ECharts has been\n * given its initial dimensions.\n */\nexport function useChartResize() {\n const { chartEchartRef } = useChartRefsContext();\n const [isWaitingForFirstResize, setIsWaitingForFirstResize] = useState(true);\n\n const resizeChart = useCallback(() => {\n if (chartEchartRef.current === null) {\n return;\n }\n\n const chart = getInstanceByDom(chartEchartRef.current);\n const { clientHeight: height, clientWidth: width } = chartEchartRef.current;\n\n chart?.resize({\n height,\n width,\n });\n }, [chartEchartRef]);\n\n useEffect(() => {\n window.addEventListener('resize', resizeChart);\n const resizeObserver = new ResizeObserver(() => {\n resizeChart();\n });\n if (chartEchartRef.current) {\n resizeObserver.observe(chartEchartRef.current);\n }\n const animationFrame = requestAnimationFrame(() => {\n resizeChart();\n setIsWaitingForFirstResize(false);\n });\n\n return () => {\n cancelAnimationFrame(animationFrame);\n window.removeEventListener('resize', resizeChart);\n resizeObserver.disconnect();\n };\n }, [chartEchartRef, resizeChart]);\n\n return {\n isWaitingForFirstResize,\n resizeChart,\n };\n}\n"]}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) "Neo4j"
|
|
5
|
+
* Neo4j Sweden AB [http://neo4j.com]
|
|
6
|
+
*
|
|
7
|
+
* This file is part of Neo4j.
|
|
8
|
+
*
|
|
9
|
+
* Neo4j is free software: you can redistribute it and/or modify
|
|
10
|
+
* it under the terms of the GNU General Public License as published by
|
|
11
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
12
|
+
* (at your option) any later version.
|
|
13
|
+
*
|
|
14
|
+
* This program is distributed in the hope that it will be useful,
|
|
15
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
16
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
17
|
+
* GNU General Public License for more details.
|
|
18
|
+
*
|
|
19
|
+
* You should have received a copy of the GNU General Public License
|
|
20
|
+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
21
|
+
*/
|
|
22
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
23
|
+
exports.useChartOption = useChartOption;
|
|
24
|
+
const echarts_1 = require("echarts");
|
|
25
|
+
const react_1 = require("react");
|
|
26
|
+
const build_chart_option_1 = require("../utils/build-chart-option");
|
|
27
|
+
const use_chart_refs_1 = require("./use-chart-refs");
|
|
28
|
+
/**
|
|
29
|
+
* Builds, applies, and exposes the ECharts option for the current React props.
|
|
30
|
+
*
|
|
31
|
+
* `buildChartOption` merges Needle defaults, normalized axes/series, threshold
|
|
32
|
+
* lines, zoom settings, toolbox options, user overrides, and the current legend
|
|
33
|
+
* selection. After `setOption`, the hook returns ECharts' normalized option so
|
|
34
|
+
* downstream code, especially the custom legend, can read the final series and
|
|
35
|
+
* dataset shape ECharts is actually using.
|
|
36
|
+
*/
|
|
37
|
+
function useChartOption({ dataZoom, dataset, hasCategoryXAxis, hasSliderZoom, propsSeries, series, settings, thresholdLines, toolboxOptions, userOption, xAxis, yAxis, }) {
|
|
38
|
+
const { chartEchartRef, legendSelectedRef } = (0, use_chart_refs_1.useChartRefsContext)();
|
|
39
|
+
const [chartOption, setChartOption] = (0, react_1.useState)();
|
|
40
|
+
(0, react_1.useEffect)(() => {
|
|
41
|
+
if (chartEchartRef.current === null) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const chart = (0, echarts_1.getInstanceByDom)(chartEchartRef.current);
|
|
45
|
+
const option = (0, build_chart_option_1.buildChartOption)({
|
|
46
|
+
dataZoom,
|
|
47
|
+
dataset,
|
|
48
|
+
hasCategoryXAxis,
|
|
49
|
+
hasSliderZoom,
|
|
50
|
+
legendSelected: legendSelectedRef.current || {},
|
|
51
|
+
propsSeries,
|
|
52
|
+
series,
|
|
53
|
+
thresholdLines,
|
|
54
|
+
toolboxOptions,
|
|
55
|
+
userOption,
|
|
56
|
+
xAxis,
|
|
57
|
+
yAxis,
|
|
58
|
+
});
|
|
59
|
+
chart === null || chart === void 0 ? void 0 : chart.setOption(option, settings);
|
|
60
|
+
setChartOption(chart === null || chart === void 0 ? void 0 : chart.getOption());
|
|
61
|
+
}, [
|
|
62
|
+
chartEchartRef,
|
|
63
|
+
dataZoom,
|
|
64
|
+
dataset,
|
|
65
|
+
hasCategoryXAxis,
|
|
66
|
+
hasSliderZoom,
|
|
67
|
+
legendSelectedRef,
|
|
68
|
+
propsSeries,
|
|
69
|
+
series,
|
|
70
|
+
settings,
|
|
71
|
+
thresholdLines,
|
|
72
|
+
toolboxOptions,
|
|
73
|
+
userOption,
|
|
74
|
+
xAxis,
|
|
75
|
+
yAxis,
|
|
76
|
+
]);
|
|
77
|
+
return chartOption;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=use-chart-option.js.map
|