@lightdash/cli 2.262.0 → 2.263.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.
|
@@ -232,6 +232,90 @@ exactly ONE source row and ONE metric-slot field, and only when
|
|
|
232
232
|
show each action on its own flag (a viewer may have one permission but not
|
|
233
233
|
the other).
|
|
234
234
|
|
|
235
|
+
### Open the menu at the data point
|
|
236
|
+
|
|
237
|
+
Anchor this menu at the activated mark, not at an edge of the iframe or chart.
|
|
238
|
+
If neither action is enabled, do not open or render an empty menu and do not
|
|
239
|
+
give marks action-button semantics.
|
|
240
|
+
Keep the clicked datum's `sourceRow` and declared metric name (and `fieldId` for
|
|
241
|
+
a multiple input) in the menu state; the menu items must act on that exact
|
|
242
|
+
identity. Pass the helper a library-neutral anchor: the activating DOM mark,
|
|
243
|
+
whether activation was by pointer or keyboard, and pointer viewport coordinates
|
|
244
|
+
when available. For a pointer activation, use native `clientX` and `clientY`,
|
|
245
|
+
never chart-relative coordinates such as `chartX` or `chartY`. For keyboard
|
|
246
|
+
activation, anchor at the centre of the activating mark's
|
|
247
|
+
`getBoundingClientRect()` instead.
|
|
248
|
+
|
|
249
|
+
Adapt each chart library before calling the helper. Recharts' React click
|
|
250
|
+
handler supplies `event.currentTarget`, `event.clientX`, `event.clientY`, and
|
|
251
|
+
`event.detail === 0` for keyboard-originated clicks. For ECharts, extract the
|
|
252
|
+
native pointer event from its click parameters before reading `clientX` and
|
|
253
|
+
`clientY`; do not assume React fields exist. D3 already passes the native event.
|
|
254
|
+
|
|
255
|
+
**Make each eligible SVG mark keyboard reachable while either action is enabled.**
|
|
256
|
+
When neither is enabled, omit the button role, tab stop, and action handlers.
|
|
257
|
+
Otherwise give the mark `tabIndex={0}`,
|
|
258
|
+
`role="button"`, and an accessible name from its category and formatted value.
|
|
259
|
+
In Recharts, use a custom `shape` to wire `onClick` and `onKeyDown` on the rendered
|
|
260
|
+
mark; the chart-wide `accessibilityLayer` alone does not open per-mark menus.
|
|
261
|
+
On Enter or Space, prevent the default key action and call the same helper with
|
|
262
|
+
`keyboard: true` and the mark as `activator`. Verify Tab → mark → Enter/Space →
|
|
263
|
+
menu → Escape returns focus to that mark.
|
|
264
|
+
Register rendered marks in a ref map keyed by stable datum key, using a ref callback
|
|
265
|
+
on the SVG element: `ref={(node) => registerMark(datum.key, node)}`.
|
|
266
|
+
Resolve the current mark after the menu unmounts when restoring
|
|
267
|
+
focus: a saved DOM element can become detached during chart rerenders.
|
|
268
|
+
|
|
269
|
+
Use the existing shadcn/Radix `DropdownMenu`, rendered with
|
|
270
|
+
`createPortal(..., document.body)`. Its 1px fixed trigger is positioned at the
|
|
271
|
+
stored viewport coordinates; this avoids transformed iframe ancestors changing
|
|
272
|
+
the containing block for `position: fixed`. Let `DropdownMenuContent` use its
|
|
273
|
+
normal Radix collision handling so a menu near a viewport edge flips or shifts
|
|
274
|
+
onscreen. The placement state is small; the existing `underlyingData.open` and
|
|
275
|
+
`drillDown.open` calls remain the menu items' host actions:
|
|
276
|
+
|
|
277
|
+
```tsx
|
|
278
|
+
const markElements = useRef(new Map());
|
|
279
|
+
const registerMark = (key, node) => {
|
|
280
|
+
if (node) markElements.current.set(key, node);
|
|
281
|
+
else markElements.current.delete(key);
|
|
282
|
+
};
|
|
283
|
+
const openPointMenu = (datum, anchor) => {
|
|
284
|
+
if (!underlyingData.enabled && !drillDown.enabled) return;
|
|
285
|
+
const rect = anchor.activator.getBoundingClientRect();
|
|
286
|
+
setTooltipVisible(false);
|
|
287
|
+
setMenu({
|
|
288
|
+
sourceRow: datum.sourceRow,
|
|
289
|
+
metric: datum.metric,
|
|
290
|
+
fieldId: datum.fieldId,
|
|
291
|
+
pointKey: datum.key,
|
|
292
|
+
keyboard: anchor.keyboard,
|
|
293
|
+
x: anchor.keyboard ? rect.left + rect.width / 2 : anchor.clientX,
|
|
294
|
+
y: anchor.keyboard ? rect.top + rect.height / 2 : anchor.clientY,
|
|
295
|
+
});
|
|
296
|
+
if (!anchor.keyboard) anchor.activator.blur();
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
{menu && (underlyingData.enabled || drillDown.enabled) && createPortal(
|
|
300
|
+
<DropdownMenu open onOpenChange={(open) => !open && setMenu(null)}>
|
|
301
|
+
<DropdownMenuTrigger asChild>
|
|
302
|
+
<span aria-hidden style={{ position: 'fixed', left: menu.x, top: menu.y, width: 1, height: 1 }} />
|
|
303
|
+
</DropdownMenuTrigger>
|
|
304
|
+
<DropdownMenuContent
|
|
305
|
+
onCloseAutoFocus={(event) => {
|
|
306
|
+
event.preventDefault();
|
|
307
|
+
if (menu.keyboard) {
|
|
308
|
+
requestAnimationFrame(() => markElements.current.get(menu.pointKey)?.focus());
|
|
309
|
+
}
|
|
310
|
+
}}
|
|
311
|
+
>
|
|
312
|
+
{/* independently gated action items */}
|
|
313
|
+
</DropdownMenuContent>
|
|
314
|
+
</DropdownMenu>,
|
|
315
|
+
document.body,
|
|
316
|
+
)}
|
|
317
|
+
```
|
|
318
|
+
|
|
235
319
|
### Interaction hygiene
|
|
236
320
|
|
|
237
321
|
One floating surface at a time, and no leftover emphasis — native Lightdash
|
|
@@ -245,8 +329,9 @@ highlighted:
|
|
|
245
329
|
reappear until the pointer moves again after the menu closes.
|
|
246
330
|
- **No persistent focus or active styling on a clicked mark.** Disable click
|
|
247
331
|
emphasis (recharts: no `activeShape` on click state; echarts: turn off
|
|
248
|
-
lingering `emphasis`/`select`)
|
|
249
|
-
|
|
332
|
+
lingering `emphasis`/`select`). A keyboard activator keeps its normal focus
|
|
333
|
+
affordance and receives focus again when the menu closes; it must not look
|
|
334
|
+
like a selected data point. Only hover may emphasise, and only while hovering.
|
|
250
335
|
- **Subtle hover, no cursor band.** The library-default full-height band
|
|
251
336
|
behind the hovered mark (recharts `<Tooltip cursor>`) is not native
|
|
252
337
|
behaviour — use `cursor={false}` or a faint theme-token fill.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lightdash/cli",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.263.1",
|
|
4
4
|
"description": "Lightdash CLI tool",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"@actions/core": "1.11.1",
|
|
23
23
|
"@aws-sdk/credential-providers": "3.995.0",
|
|
24
24
|
"@casl/ability": "6.8.0",
|
|
25
|
-
"@lightdash/common": "2.
|
|
26
|
-
"@lightdash/warehouses": "2.
|
|
25
|
+
"@lightdash/common": "2.263.1",
|
|
26
|
+
"@lightdash/warehouses": "2.263.1",
|
|
27
27
|
"@sidvind/better-ajv-errors": "7.0.0",
|
|
28
28
|
"@types/columnify": "1.5.1",
|
|
29
29
|
"ajv": "8.18.0",
|