@gooddata/sdk-ui-dashboard 11.40.0-alpha.3 → 11.40.0-alpha.5
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/NOTICE +120 -80
- package/esm/__version.d.ts +1 -1
- package/esm/__version.js +1 -1
- package/esm/model/store/widgetDrills/widgetDrillSelectors.js +1 -4
- package/esm/presentation/dashboard/DashboardSidebar/DraggableInsightList/DraggableInsightList.js +1 -1
- package/esm/presentation/dashboard/DashboardSidebar/DraggableInsightList/DraggableInsightListItemWrapper.d.ts +1 -1
- package/esm/presentation/dashboard/DashboardSidebar/DraggableInsightList/DraggableInsightListItemWrapper.js +2 -1
- package/esm/presentation/dashboard/DashboardSidebar/SidebarConfigurationPanel.js +9 -2
- package/esm/presentation/dashboard/DashboardSidebar/SidebarResizeChrome.d.ts +21 -0
- package/esm/presentation/dashboard/DashboardSidebar/SidebarResizeChrome.js +112 -0
- package/esm/presentation/dragAndDrop/types.d.ts +1 -0
- package/esm/presentation/filterBar/filterBar/DefaultDashboardFilterGroup.js +7 -2
- package/esm/sdk-ui-dashboard.d.ts +1 -0
- package/package.json +24 -24
- package/styles/css/main.css +73 -0
- package/styles/css/main.css.map +1 -1
- package/styles/css/sidebar.css +73 -0
- package/styles/css/sidebar.css.map +1 -1
- package/styles/scss/sidebar.scss +94 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// (C) 2026 GoodData Corporation
|
|
3
|
+
import { useEffect, useRef, useState, } from "react";
|
|
4
|
+
import cx from "classnames";
|
|
5
|
+
import { clamp } from "lodash-es";
|
|
6
|
+
import { useLocalStorage } from "@gooddata/sdk-ui";
|
|
7
|
+
import { makeKeyboardNavigation, useCloseOnEscape } from "@gooddata/sdk-ui-kit";
|
|
8
|
+
const SIDEBAR_MIN_WIDTH = 230;
|
|
9
|
+
const SIDEBAR_MAX_WIDTH = 500;
|
|
10
|
+
const EDITOR_MIN_WIDTH = 960;
|
|
11
|
+
const KEYBOARD_STEP = 10;
|
|
12
|
+
const LOCAL_STORAGE_KEY = "gd-dashboard-sidebar-width";
|
|
13
|
+
const handleSeparatorKeyboardNavigation = makeKeyboardNavigation({
|
|
14
|
+
shrink: [{ code: "ArrowLeft" }],
|
|
15
|
+
grow: [{ code: "ArrowRight" }],
|
|
16
|
+
minimize: [{ code: "Home" }],
|
|
17
|
+
maximize: [{ code: "End" }],
|
|
18
|
+
});
|
|
19
|
+
/**
|
|
20
|
+
* Returns the current `window.innerWidth`, kept in sync with the `resize` event.
|
|
21
|
+
*/
|
|
22
|
+
function useWindowWidth() {
|
|
23
|
+
const [width, setWidth] = useState(() => window.innerWidth);
|
|
24
|
+
useEffect(() => {
|
|
25
|
+
const handleResize = () => setWidth(window.innerWidth);
|
|
26
|
+
window.addEventListener("resize", handleResize);
|
|
27
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
28
|
+
}, []);
|
|
29
|
+
return width;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Internal presentational wrapper that holds the dashboard sidebar drag-to-resize state.
|
|
33
|
+
*
|
|
34
|
+
* Owns: committed width (persisted to localStorage), live drag width (only used for the dashed
|
|
35
|
+
* indicator transform), drag phase, and a window-width tracker that enforces a minimum editor
|
|
36
|
+
* canvas width without overwriting the user's persisted preference.
|
|
37
|
+
*
|
|
38
|
+
* Renders `.gd-sidebar-container` itself so the resize handle can be positioned absolutely inside
|
|
39
|
+
* it — that element is sticky+100vh, so the handle (and the grip centered inside it) tracks the
|
|
40
|
+
* visible viewport rather than the full dashboard-root height.
|
|
41
|
+
*
|
|
42
|
+
* Drag uses `setPointerCapture` on the handle button so pointer events keep flowing to it even
|
|
43
|
+
* when the cursor leaves the 6 px hit area. No DOM overlay or window-level listener is needed.
|
|
44
|
+
*
|
|
45
|
+
* @internal
|
|
46
|
+
*/
|
|
47
|
+
export function SidebarResizeChrome({ onContainerClick, children, }) {
|
|
48
|
+
const [dragWidth, setDragWidth] = useState(null);
|
|
49
|
+
const dragOriginRef = useRef(null);
|
|
50
|
+
const containerWidth = useWindowWidth();
|
|
51
|
+
const [persistedWidth, setPersistedWidth] = useLocalStorage(LOCAL_STORAGE_KEY, SIDEBAR_MIN_WIDTH);
|
|
52
|
+
const effectiveMax = clamp(containerWidth - EDITOR_MIN_WIDTH, SIDEBAR_MIN_WIDTH, SIDEBAR_MAX_WIDTH);
|
|
53
|
+
const effectiveWidth = clamp(persistedWidth, SIDEBAR_MIN_WIDTH, effectiveMax);
|
|
54
|
+
const isDragging = dragWidth !== null;
|
|
55
|
+
const isResizable = effectiveMax > SIDEBAR_MIN_WIDTH;
|
|
56
|
+
const endDrag = () => {
|
|
57
|
+
dragOriginRef.current = null;
|
|
58
|
+
setDragWidth(null);
|
|
59
|
+
};
|
|
60
|
+
useCloseOnEscape(isDragging, endDrag);
|
|
61
|
+
const handleKeyDown = handleSeparatorKeyboardNavigation({
|
|
62
|
+
shrink: () => setPersistedWidth(clamp(effectiveWidth - KEYBOARD_STEP, SIDEBAR_MIN_WIDTH, effectiveMax)),
|
|
63
|
+
grow: () => setPersistedWidth(clamp(effectiveWidth + KEYBOARD_STEP, SIDEBAR_MIN_WIDTH, effectiveMax)),
|
|
64
|
+
minimize: () => setPersistedWidth(SIDEBAR_MIN_WIDTH),
|
|
65
|
+
maximize: () => setPersistedWidth(effectiveMax),
|
|
66
|
+
});
|
|
67
|
+
const handlePointerDown = (event) => {
|
|
68
|
+
event.preventDefault();
|
|
69
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
70
|
+
dragOriginRef.current = {
|
|
71
|
+
clientX: event.clientX,
|
|
72
|
+
width: effectiveWidth,
|
|
73
|
+
pointerId: event.pointerId,
|
|
74
|
+
};
|
|
75
|
+
setDragWidth(effectiveWidth);
|
|
76
|
+
};
|
|
77
|
+
const handlePointerMove = (event) => {
|
|
78
|
+
if (event.pointerId !== dragOriginRef.current?.pointerId) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const width = widthFromClientX(event.clientX);
|
|
82
|
+
if (width !== null) {
|
|
83
|
+
setDragWidth(width);
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
const handlePointerUp = (event) => {
|
|
87
|
+
if (event.pointerId !== dragOriginRef.current?.pointerId) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const width = widthFromClientX(event.clientX);
|
|
91
|
+
if (width !== null) {
|
|
92
|
+
setPersistedWidth(width);
|
|
93
|
+
}
|
|
94
|
+
endDrag();
|
|
95
|
+
};
|
|
96
|
+
const widthFromClientX = (clientX) => {
|
|
97
|
+
const origin = dragOriginRef.current;
|
|
98
|
+
if (!origin) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return clamp(origin.width + (clientX - origin.clientX), SIDEBAR_MIN_WIDTH, effectiveMax);
|
|
102
|
+
};
|
|
103
|
+
return (_jsx("div", { className: cx("gd-resizable-sidebar", {
|
|
104
|
+
"gd-resizable-sidebar--resizable": isResizable,
|
|
105
|
+
"gd-resizable-sidebar--dragging": isDragging,
|
|
106
|
+
}), style: { width: effectiveWidth }, children: _jsxs("div", { className: "col gd-flex-item gd-sidebar-container gd-sidebar-container--resizable", onClick: onContainerClick, children: [children, _jsx("button", { type: "button", style: {
|
|
107
|
+
"--drag-x": `${isDragging ? dragWidth : effectiveWidth}px`,
|
|
108
|
+
}, className: cx("gd-resizable-sidebar__handle", {
|
|
109
|
+
"gd-resizable-sidebar__handle--dragging": isDragging,
|
|
110
|
+
}), disabled: !isResizable, role: "separator", "aria-orientation": "vertical", "aria-valuemin": SIDEBAR_MIN_WIDTH, "aria-valuemax": effectiveMax, "aria-valuenow": effectiveWidth, onPointerDown: isResizable ? handlePointerDown : undefined, onPointerMove: handlePointerMove, onPointerUp: handlePointerUp, onPointerCancel: endDrag, onKeyDown: isDragging ? undefined : handleKeyDown, children: _jsx("span", { className: "gd-resizable-sidebar__handle-grip", "aria-hidden": "true" }) })
|
|
111
|
+
] }) }));
|
|
112
|
+
}
|
|
@@ -38,9 +38,14 @@ export function DefaultDashboardFilterGroup(props) {
|
|
|
38
38
|
}, []);
|
|
39
39
|
const isFilterActive = useCallback((filter) => {
|
|
40
40
|
if (isFilterBarMeasureValueFilter(filter)) {
|
|
41
|
+
// Measure value filters have no working selection, so they always reflect the
|
|
42
|
+
// committed filter regardless of the apply mode.
|
|
41
43
|
return !isAllDashboardMeasureValueFilter(filter.filter);
|
|
42
44
|
}
|
|
43
|
-
|
|
45
|
+
// In apply-all-at-once mode the uncommitted (working) selection should be reflected in
|
|
46
|
+
// the group button subtitle immediately, without waiting for the Apply button. Fall back
|
|
47
|
+
// to the committed filter when there is no working selection.
|
|
48
|
+
const dashboardFilter = isApplyAllAtOnceEnabledAndSet && filter.workingFilter ? filter.workingFilter : filter.filter;
|
|
44
49
|
if (isDashboardAttributeFilter(dashboardFilter)) {
|
|
45
50
|
return getSelectedElementsCount(dashboardFilter) > 0;
|
|
46
51
|
}
|
|
@@ -51,7 +56,7 @@ export function DefaultDashboardFilterGroup(props) {
|
|
|
51
56
|
return dashboardFilter.matchAttributeFilter.literal.length > 0;
|
|
52
57
|
}
|
|
53
58
|
return true;
|
|
54
|
-
}, []);
|
|
59
|
+
}, [isApplyAllAtOnceEnabledAndSet]);
|
|
55
60
|
const renderFilter = useCallback((filter, AttributeFilterComponent, MeasureValueFilterComponent) => {
|
|
56
61
|
if (isFilterBarMeasureValueFilter(filter)) {
|
|
57
62
|
const localId = dashboardFilterLocalIdentifier(filter.filter);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-dashboard",
|
|
3
|
-
"version": "11.40.0-alpha.
|
|
3
|
+
"version": "11.40.0-alpha.5",
|
|
4
4
|
"description": "GoodData SDK - Dashboard Component",
|
|
5
5
|
"license": "LicenseRef-LICENSE",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -60,19 +60,19 @@
|
|
|
60
60
|
"ts-invariant": "0.10.3",
|
|
61
61
|
"tslib": "2.8.1",
|
|
62
62
|
"uuid": "11.1.0",
|
|
63
|
-
"@gooddata/sdk-backend-base": "11.40.0-alpha.
|
|
64
|
-
"@gooddata/sdk-backend-spi": "11.40.0-alpha.
|
|
65
|
-
"@gooddata/sdk-ui": "11.40.0-alpha.
|
|
66
|
-
"@gooddata/sdk-model": "11.40.0-alpha.
|
|
67
|
-
"@gooddata/sdk-ui-charts": "11.40.0-alpha.
|
|
68
|
-
"@gooddata/sdk-ui-ext": "11.40.0-alpha.
|
|
69
|
-
"@gooddata/sdk-ui-
|
|
70
|
-
"@gooddata/sdk-ui-
|
|
71
|
-
"@gooddata/sdk-ui-
|
|
72
|
-
"@gooddata/sdk-ui-pivot": "11.40.0-alpha.
|
|
73
|
-
"@gooddata/sdk-ui-theme-provider": "11.40.0-alpha.
|
|
74
|
-
"@gooddata/sdk-ui-vis-commons": "11.40.0-alpha.
|
|
75
|
-
"@gooddata/util": "11.40.0-alpha.
|
|
63
|
+
"@gooddata/sdk-backend-base": "11.40.0-alpha.5",
|
|
64
|
+
"@gooddata/sdk-backend-spi": "11.40.0-alpha.5",
|
|
65
|
+
"@gooddata/sdk-ui": "11.40.0-alpha.5",
|
|
66
|
+
"@gooddata/sdk-model": "11.40.0-alpha.5",
|
|
67
|
+
"@gooddata/sdk-ui-charts": "11.40.0-alpha.5",
|
|
68
|
+
"@gooddata/sdk-ui-ext": "11.40.0-alpha.5",
|
|
69
|
+
"@gooddata/sdk-ui-filters": "11.40.0-alpha.5",
|
|
70
|
+
"@gooddata/sdk-ui-geo": "11.40.0-alpha.5",
|
|
71
|
+
"@gooddata/sdk-ui-kit": "11.40.0-alpha.5",
|
|
72
|
+
"@gooddata/sdk-ui-pivot": "11.40.0-alpha.5",
|
|
73
|
+
"@gooddata/sdk-ui-theme-provider": "11.40.0-alpha.5",
|
|
74
|
+
"@gooddata/sdk-ui-vis-commons": "11.40.0-alpha.5",
|
|
75
|
+
"@gooddata/util": "11.40.0-alpha.5"
|
|
76
76
|
},
|
|
77
77
|
"devDependencies": {
|
|
78
78
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -106,9 +106,9 @@
|
|
|
106
106
|
"eslint-plugin-sonarjs": "3.0.6",
|
|
107
107
|
"happy-dom": "18.0.1",
|
|
108
108
|
"npm-run-all": "^4.1.5",
|
|
109
|
-
"oxfmt": "0.
|
|
110
|
-
"oxlint": "
|
|
111
|
-
"oxlint-tsgolint": "0.
|
|
109
|
+
"oxfmt": "0.52.0",
|
|
110
|
+
"oxlint": "1.51.0",
|
|
111
|
+
"oxlint-tsgolint": "0.15.0",
|
|
112
112
|
"raf": "3.4.1",
|
|
113
113
|
"react": "19.1.1",
|
|
114
114
|
"react-dom": "19.1.1",
|
|
@@ -116,14 +116,14 @@
|
|
|
116
116
|
"stylelint": "^16.26.1",
|
|
117
117
|
"svgo": "^2.8.0",
|
|
118
118
|
"typescript": "5.9.3",
|
|
119
|
-
"vitest": "4.1.
|
|
119
|
+
"vitest": "4.1.8",
|
|
120
120
|
"vitest-dom": "0.1.1",
|
|
121
|
-
"@gooddata/
|
|
122
|
-
"@gooddata/
|
|
123
|
-
"@gooddata/oxlint-config": "11.40.0-alpha.
|
|
124
|
-
"@gooddata/
|
|
125
|
-
"@gooddata/
|
|
126
|
-
"@gooddata/stylelint-config": "11.40.0-alpha.
|
|
121
|
+
"@gooddata/eslint-config": "11.40.0-alpha.5",
|
|
122
|
+
"@gooddata/i18n-toolkit": "11.40.0-alpha.5",
|
|
123
|
+
"@gooddata/oxlint-config": "11.40.0-alpha.5",
|
|
124
|
+
"@gooddata/reference-workspace": "11.40.0-alpha.5",
|
|
125
|
+
"@gooddata/sdk-backend-mockingbird": "11.40.0-alpha.5",
|
|
126
|
+
"@gooddata/stylelint-config": "11.40.0-alpha.5"
|
|
127
127
|
},
|
|
128
128
|
"peerDependencies": {
|
|
129
129
|
"react": "^18.0.0 || ^19.0.0",
|
package/styles/css/main.css
CHANGED
|
@@ -30783,6 +30783,79 @@ figure {
|
|
|
30783
30783
|
height: 100vh;
|
|
30784
30784
|
border-right: 1px solid var(--gd-palette-complementary-3, #dde4eb);
|
|
30785
30785
|
}
|
|
30786
|
+
.gd-sidebar-container--resizable {
|
|
30787
|
+
min-width: 230px;
|
|
30788
|
+
width: 100%;
|
|
30789
|
+
}
|
|
30790
|
+
|
|
30791
|
+
.gd-resizable-sidebar {
|
|
30792
|
+
display: flex;
|
|
30793
|
+
flex-direction: column;
|
|
30794
|
+
flex: 0 0 auto;
|
|
30795
|
+
}
|
|
30796
|
+
.gd-resizable-sidebar--dragging, .gd-resizable-sidebar:has(.gd-resizable-sidebar__handle:focus) {
|
|
30797
|
+
z-index: 9999;
|
|
30798
|
+
}
|
|
30799
|
+
.gd-resizable-sidebar__handle {
|
|
30800
|
+
opacity: 0;
|
|
30801
|
+
position: absolute;
|
|
30802
|
+
top: 0;
|
|
30803
|
+
bottom: 0;
|
|
30804
|
+
transform: translateX(calc(var(--drag-x, 0) - 50%));
|
|
30805
|
+
z-index: 2;
|
|
30806
|
+
display: flex;
|
|
30807
|
+
align-items: center;
|
|
30808
|
+
justify-content: center;
|
|
30809
|
+
width: 6px;
|
|
30810
|
+
background: transparent;
|
|
30811
|
+
border: 0;
|
|
30812
|
+
cursor: col-resize;
|
|
30813
|
+
touch-action: none;
|
|
30814
|
+
}
|
|
30815
|
+
.gd-resizable-sidebar__handle:focus {
|
|
30816
|
+
outline: none;
|
|
30817
|
+
}
|
|
30818
|
+
.gd-resizable-sidebar__handle:disabled {
|
|
30819
|
+
cursor: initial;
|
|
30820
|
+
}
|
|
30821
|
+
.gd-resizable-sidebar__handle--dragging {
|
|
30822
|
+
opacity: 1;
|
|
30823
|
+
}
|
|
30824
|
+
.gd-resizable-sidebar--resizable:hover .gd-resizable-sidebar__handle, .gd-resizable-sidebar--resizable:focus-within .gd-resizable-sidebar__handle {
|
|
30825
|
+
opacity: 1;
|
|
30826
|
+
}
|
|
30827
|
+
.gd-resizable-sidebar__handle-grip {
|
|
30828
|
+
display: flex;
|
|
30829
|
+
align-items: center;
|
|
30830
|
+
justify-content: center;
|
|
30831
|
+
gap: 10px;
|
|
30832
|
+
height: 25px;
|
|
30833
|
+
padding: 5px 3px;
|
|
30834
|
+
background: var(--gd-palette-complementary-0);
|
|
30835
|
+
border: 1px solid var(--gd-palette-complementary-5);
|
|
30836
|
+
border-radius: 2px;
|
|
30837
|
+
}
|
|
30838
|
+
.gd-resizable-sidebar--dragging .gd-resizable-sidebar__handle-grip, .gd-resizable-sidebar__handle:focus .gd-resizable-sidebar__handle-grip {
|
|
30839
|
+
border: 2px solid #14b2e2;
|
|
30840
|
+
border-radius: 3px;
|
|
30841
|
+
}
|
|
30842
|
+
.gd-resizable-sidebar--dragging .gd-resizable-sidebar__handle-grip::after, .gd-resizable-sidebar__handle:focus .gd-resizable-sidebar__handle-grip::after {
|
|
30843
|
+
content: "";
|
|
30844
|
+
position: absolute;
|
|
30845
|
+
top: 0;
|
|
30846
|
+
bottom: 0;
|
|
30847
|
+
left: 50%;
|
|
30848
|
+
transform: translateX(-50%);
|
|
30849
|
+
z-index: -1;
|
|
30850
|
+
width: 2px;
|
|
30851
|
+
background: #14b2e2;
|
|
30852
|
+
box-shadow: 0 0 0 4px var(--gd-palette-primary-base-t85, rgba(20, 178, 226, 0.15));
|
|
30853
|
+
}
|
|
30854
|
+
|
|
30855
|
+
body:has(.gd-resizable-sidebar--dragging),
|
|
30856
|
+
body:has(.gd-resizable-sidebar--dragging) * {
|
|
30857
|
+
cursor: col-resize;
|
|
30858
|
+
}
|
|
30786
30859
|
|
|
30787
30860
|
.add-item-panel {
|
|
30788
30861
|
padding: 0 7px;
|