basalt-ui 1.30.2 → 1.32.0
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/AGENTS.md +1 -1
- package/CHANGELOG.md +54 -0
- package/MIGRATING.md +256 -12
- package/agent/rules/basalt-controls.md +19 -19
- package/agent/rules/basalt-mantine.md +5 -5
- package/configs/oxlint-plugin.js +371 -4
- package/configs/oxlint-plugin.test.ts +327 -2
- package/configs/oxlint.json +2 -1
- package/dist/agent-chat/composer.d.ts.map +1 -1
- package/dist/agent-chat/composer.js +41 -43
- package/dist/agent-chat/thread-workspace.d.ts +2 -2
- package/dist/agent-chat/thread-workspace.d.ts.map +1 -1
- package/dist/agent-chat/thread-workspace.js +3 -4
- package/dist/agent-chat/use-keyboard-inset.d.ts +2 -0
- package/dist/agent-chat/use-keyboard-inset.d.ts.map +1 -0
- package/dist/agent-chat/use-keyboard-inset.js +34 -0
- package/dist/charts/cursor/touch-pin.d.ts +45 -0
- package/dist/charts/cursor/touch-pin.d.ts.map +1 -0
- package/dist/charts/cursor/touch-pin.js +79 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts +66 -0
- package/dist/charts/hooks/use-discrete-cursor.d.ts.map +1 -0
- package/dist/charts/hooks/use-discrete-cursor.js +198 -0
- package/dist/charts/hooks/use-hysteresis.d.ts +18 -0
- package/dist/charts/hooks/use-hysteresis.d.ts.map +1 -0
- package/dist/charts/hooks/use-hysteresis.js +12 -0
- package/dist/charts/hooks/useBandPlot.d.ts +7 -0
- package/dist/charts/hooks/useBandPlot.d.ts.map +1 -1
- package/dist/charts/hooks/useBandPlot.js +62 -18
- package/dist/charts/hooks/useChartCursor.d.ts +40 -11
- package/dist/charts/hooks/useChartCursor.d.ts.map +1 -1
- package/dist/charts/hooks/useChartCursor.js +102 -11
- package/dist/charts/index.d.ts +0 -1
- package/dist/charts/index.d.ts.map +1 -1
- package/dist/charts/index.js +0 -10
- package/dist/charts/kinds/BandStrip.d.ts.map +1 -1
- package/dist/charts/kinds/BandStrip.js +47 -82
- package/dist/charts/kinds/Donut.d.ts +9 -3
- package/dist/charts/kinds/Donut.d.ts.map +1 -1
- package/dist/charts/kinds/Donut.js +110 -48
- package/dist/charts/kinds/DualPanel.d.ts.map +1 -1
- package/dist/charts/kinds/DualPanel.js +138 -145
- package/dist/charts/kinds/Heatmap.d.ts +7 -0
- package/dist/charts/kinds/Heatmap.d.ts.map +1 -1
- package/dist/charts/kinds/Heatmap.js +37 -16
- package/dist/charts/kinds/MirroredBars.d.ts.map +1 -1
- package/dist/charts/kinds/MirroredBars.js +68 -111
- package/dist/charts/kinds/band-chrome.d.ts +31 -0
- package/dist/charts/kinds/band-chrome.d.ts.map +1 -0
- package/dist/charts/kinds/band-chrome.js +71 -0
- package/dist/charts/kinds/donut-layout.d.ts +47 -0
- package/dist/charts/kinds/donut-layout.d.ts.map +1 -0
- package/dist/charts/kinds/donut-layout.js +52 -0
- package/dist/charts/layout/auto-margin.d.ts +7 -2
- package/dist/charts/layout/auto-margin.d.ts.map +1 -1
- package/dist/charts/layout/auto-margin.js +12 -3
- package/dist/charts/layout/end-labels.d.ts +64 -0
- package/dist/charts/layout/end-labels.d.ts.map +1 -0
- package/dist/charts/layout/end-labels.js +76 -0
- package/dist/charts/primitives/Axes.d.ts +32 -4
- package/dist/charts/primitives/Axes.d.ts.map +1 -1
- package/dist/charts/primitives/Axes.js +62 -16
- package/dist/charts/primitives/CartesianChart.d.ts +7 -6
- package/dist/charts/primitives/CartesianChart.d.ts.map +1 -1
- package/dist/charts/primitives/CartesianChart.js +264 -145
- package/dist/charts/primitives/ChartCard.d.ts +0 -14
- package/dist/charts/primitives/ChartCard.d.ts.map +1 -1
- package/dist/charts/primitives/ChartCard.js +56 -21
- package/dist/charts/primitives/ChartFrame.d.ts +28 -22
- package/dist/charts/primitives/ChartFrame.d.ts.map +1 -1
- package/dist/charts/primitives/ChartFrame.js +116 -34
- package/dist/charts/primitives/ChartLegend.d.ts +19 -15
- package/dist/charts/primitives/ChartLegend.d.ts.map +1 -1
- package/dist/charts/primitives/ChartLegend.js +86 -73
- package/dist/charts/primitives/ChartTooltip.d.ts +5 -0
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +20 -4
- package/dist/charts/primitives/Crosshair.js +2 -2
- package/dist/charts/primitives/HoverOverlay.d.ts +29 -9
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +54 -27
- package/dist/charts/primitives/HoverOverlay.module.css +13 -0
- package/dist/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/dist/charts/primitives/chart-card-context.d.ts +33 -0
- package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
- package/dist/charts/primitives/chart-card-context.js +18 -0
- package/dist/charts/primitives/chart-frame-layout.d.ts +93 -113
- package/dist/charts/primitives/chart-frame-layout.d.ts.map +1 -1
- package/dist/charts/primitives/chart-frame-layout.js +75 -34
- package/dist/charts/primitives/chart-layout.d.ts +112 -0
- package/dist/charts/primitives/chart-layout.d.ts.map +1 -0
- package/dist/charts/primitives/chart-layout.js +175 -0
- package/dist/charts/primitives/chart-tier.d.ts +13 -11
- package/dist/charts/primitives/chart-tier.d.ts.map +1 -1
- package/dist/charts/primitives/chart-tier.js +42 -13
- package/dist/charts/primitives/legend-disclosure.d.ts +27 -0
- package/dist/charts/primitives/legend-disclosure.d.ts.map +1 -0
- package/dist/charts/primitives/legend-disclosure.js +153 -0
- package/dist/charts/series.d.ts +4 -1
- package/dist/charts/series.d.ts.map +1 -1
- package/dist/charts/utils/ticks.d.ts +27 -8
- package/dist/charts/utils/ticks.d.ts.map +1 -1
- package/dist/charts/utils/ticks.js +35 -11
- package/dist/common/errors.d.ts +11 -1
- package/dist/common/errors.d.ts.map +1 -1
- package/dist/common/errors.js +16 -2
- package/dist/common/hit-floor.d.ts +10 -0
- package/dist/common/hit-floor.d.ts.map +1 -0
- package/dist/common/hit-floor.js +6 -0
- package/dist/{shell → common}/isomorphic-layout-effect.d.ts +4 -3
- package/dist/common/isomorphic-layout-effect.d.ts.map +1 -0
- package/dist/common/use-measured-widths.d.ts +37 -0
- package/dist/common/use-measured-widths.d.ts.map +1 -0
- package/dist/common/use-measured-widths.js +51 -0
- package/dist/common/use-media-query.d.ts +6 -0
- package/dist/common/use-media-query.d.ts.map +1 -0
- package/dist/common/use-media-query.js +40 -0
- package/dist/common/validate.d.ts +9 -0
- package/dist/common/validate.d.ts.map +1 -1
- package/dist/common/validate.js +9 -4
- package/dist/content/article-layout.d.ts +4 -2
- package/dist/content/article-layout.d.ts.map +1 -1
- package/dist/content/article-layout.js +43 -3
- package/dist/content/article-layout.module.css +45 -4
- package/dist/content/article-layout.module.css.d.ts +3 -0
- package/dist/content/code-block.d.ts.map +1 -1
- package/dist/content/code-block.js +40 -2
- package/dist/content/code-block.module.css +32 -2
- package/dist/content/prose.module.css +13 -8
- package/dist/controls/actions.d.ts +29 -6
- package/dist/controls/actions.d.ts.map +1 -1
- package/dist/controls/actions.js +158 -27
- package/dist/controls/actions.module.css +14 -1
- package/dist/controls/actions.module.css.d.ts +1 -0
- package/dist/controls/controls.module.css +13 -31
- package/dist/controls/enum-filter.js +2 -2
- package/dist/controls/filter-context.d.ts +10 -0
- package/dist/controls/filter-context.d.ts.map +1 -1
- package/dist/controls/filter-context.js +2 -0
- package/dist/controls/filter-pill.d.ts.map +1 -1
- package/dist/controls/filter-pill.js +1 -0
- package/dist/controls/index.d.ts +1 -1
- package/dist/controls/index.d.ts.map +1 -1
- package/dist/controls/index.js +0 -2
- package/dist/controls/multi-select-filter.js +2 -2
- package/dist/controls/sync-button.module.css +2 -1
- package/dist/dashboard/section.d.ts.map +1 -1
- package/dist/dashboard/section.js +1 -0
- package/dist/dashboard/section.module.css +1 -26
- package/dist/dashboard/stat-card.d.ts +1 -1
- package/dist/dashboard/stat-card.d.ts.map +1 -1
- package/dist/dashboard/stat-card.js +4 -1
- package/dist/dashboard/stat-card.module.css +6 -9
- package/dist/dashboard/stat-group.module.css +33 -66
- package/dist/dashboard/widget-grid.d.ts.map +1 -1
- package/dist/dashboard/widget-grid.module.css +11 -38
- package/dist/dashboard/widget-header.d.ts +14 -4
- package/dist/dashboard/widget-header.d.ts.map +1 -1
- package/dist/dashboard/widget-header.js +23 -6
- package/dist/dashboard/widget-header.module.css +145 -133
- package/dist/dashboard/widget-header.module.css.d.ts +2 -0
- package/dist/data/data-table-state.d.ts +83 -0
- package/dist/data/data-table-state.d.ts.map +1 -0
- package/dist/data/data-table-state.js +139 -0
- package/dist/data/data-table.d.ts +56 -2
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +436 -336
- package/dist/data/data-table.module.css +94 -0
- package/dist/data/data-table.module.css.d.ts +11 -0
- package/dist/data/virtual-list.d.ts.map +1 -1
- package/dist/data/virtual-list.js +10 -0
- package/dist/forms/form-layout.d.ts.map +1 -1
- package/dist/forms/form-layout.js +3 -3
- package/dist/forms/form-layout.module.css +20 -5
- package/dist/forms/form-layout.module.css.d.ts +1 -0
- package/dist/guard/index.d.ts +8 -2
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +68 -2
- package/dist/guard/types.d.ts +3 -3
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -1
- package/dist/notifications/center.d.ts.map +1 -1
- package/dist/provider/index.d.ts +20 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +30 -8
- package/dist/shell/app-brand.d.ts.map +1 -1
- package/dist/shell/app-brand.js +1 -0
- package/dist/shell/app-brand.module.css +2 -2
- package/dist/shell/app-header.module.css +18 -8
- package/dist/shell/app-main.module.css +54 -3
- package/dist/shell/app-main.module.css.d.ts +1 -0
- package/dist/shell/app-mobile-nav.module.css +16 -4
- package/dist/shell/app-sidebar.module.css +4 -6
- package/dist/shell/aside-docking.d.ts +31 -0
- package/dist/shell/aside-docking.d.ts.map +1 -0
- package/dist/shell/aside-docking.js +19 -0
- package/dist/shell/index.d.ts +1 -0
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +56 -16
- package/dist/shell/mobile-nav-model.d.ts +1 -1
- package/dist/shell/page-aside.d.ts +22 -3
- package/dist/shell/page-aside.d.ts.map +1 -1
- package/dist/shell/page-aside.js +27 -13
- package/dist/shell/page-bar.d.ts.map +1 -1
- package/dist/shell/page-bar.js +10 -5
- package/dist/shell/page-bar.module.css +10 -34
- package/dist/shell/use-breakpoint.d.ts +3 -4
- package/dist/shell/use-breakpoint.d.ts.map +1 -1
- package/dist/shell/use-breakpoint.js +3 -25
- package/dist/shell/use-size-class.d.ts +6 -0
- package/dist/shell/use-size-class.d.ts.map +1 -0
- package/dist/shell/use-size-class.js +19 -0
- package/dist/state/persisted-or-local.d.ts +4 -1
- package/dist/state/persisted-or-local.d.ts.map +1 -1
- package/dist/state/persisted-or-local.js +4 -3
- package/dist/state/persisted.d.ts +10 -0
- package/dist/state/persisted.d.ts.map +1 -1
- package/dist/state/persisted.js +44 -14
- package/dist/styles.css +41 -0
- package/dist/surfaces.d.ts +4 -4
- package/dist/surfaces.d.ts.map +1 -1
- package/dist/surfaces.js +11 -3
- package/dist/theme/controls.module.css +7 -0
- package/dist/theme/ctl-theme.d.ts +1 -0
- package/dist/theme/ctl-theme.d.ts.map +1 -1
- package/dist/theme/ctl-theme.js +12 -4
- package/dist/theme/floating.module.css +37 -0
- package/dist/theme/floating.module.css.d.ts +3 -0
- package/dist/theme/index.d.ts +2 -2
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/theme/index.js +34 -5
- package/dist/theme/nav-link.module.css +7 -0
- package/dist/theme-lab/derive-controls.d.ts.map +1 -1
- package/dist/tokens/index.d.ts +7 -16
- package/dist/tokens/index.d.ts.map +1 -1
- package/dist/tokens/index.js +23 -28
- package/dist/tokens/palette.d.ts +5 -27
- package/dist/tokens/palette.d.ts.map +1 -1
- package/dist/tokens/palette.js +8 -30
- package/dist/tokens/size-classes.d.ts +40 -0
- package/dist/tokens/size-classes.d.ts.map +1 -0
- package/dist/tokens/size-classes.js +29 -0
- package/dist/tokens.css +8 -4
- package/llms.txt +3 -3
- package/package.json +18 -17
- package/src/agent-chat/composer.tsx +74 -47
- package/src/agent-chat/thread-workspace.tsx +8 -11
- package/src/agent-chat/use-keyboard-inset.ts +68 -0
- package/src/charts/cursor/touch-pin.ts +138 -0
- package/src/charts/hooks/use-discrete-cursor.ts +335 -0
- package/src/charts/hooks/use-hysteresis.ts +26 -0
- package/src/charts/hooks/useBandPlot.ts +90 -27
- package/src/charts/hooks/useChartCursor.ts +211 -26
- package/src/charts/index.ts +0 -8
- package/src/charts/kinds/BandStrip.tsx +25 -61
- package/src/charts/kinds/Donut.tsx +153 -62
- package/src/charts/kinds/DualPanel.tsx +21 -26
- package/src/charts/kinds/Heatmap.tsx +61 -22
- package/src/charts/kinds/MirroredBars.tsx +23 -65
- package/src/charts/kinds/band-chrome.tsx +91 -0
- package/src/charts/kinds/donut-layout.ts +82 -0
- package/src/charts/layout/auto-margin.ts +24 -5
- package/src/charts/layout/end-labels.ts +135 -0
- package/src/charts/primitives/Axes.tsx +112 -21
- package/src/charts/primitives/CartesianChart.tsx +282 -111
- package/src/charts/primitives/ChartCard.tsx +119 -48
- package/src/charts/primitives/ChartFrame.tsx +204 -60
- package/src/charts/primitives/ChartLegend.tsx +115 -78
- package/src/charts/primitives/ChartTooltip.tsx +24 -3
- package/src/charts/primitives/Crosshair.tsx +2 -2
- package/src/charts/primitives/HoverOverlay.module.css +13 -0
- package/src/charts/primitives/HoverOverlay.module.css.d.ts +8 -0
- package/src/charts/primitives/HoverOverlay.tsx +62 -20
- package/src/charts/primitives/chart-card-context.ts +46 -0
- package/src/charts/primitives/chart-frame-layout.ts +207 -182
- package/src/charts/primitives/chart-layout.ts +318 -0
- package/src/charts/primitives/chart-tier.tsx +66 -21
- package/src/charts/primitives/legend-disclosure.tsx +177 -0
- package/src/charts/series.ts +4 -1
- package/src/charts/utils/ticks.ts +95 -19
- package/src/common/errors.ts +25 -1
- package/src/common/hit-floor.ts +9 -0
- package/src/{shell → common}/isomorphic-layout-effect.ts +4 -3
- package/src/common/use-measured-widths.ts +88 -0
- package/src/common/use-media-query.ts +56 -0
- package/src/common/validate.ts +17 -4
- package/src/content/article-layout.module.css +45 -4
- package/src/content/article-layout.module.css.d.ts +3 -0
- package/src/content/article-layout.tsx +60 -5
- package/src/content/code-block.module.css +32 -2
- package/src/content/code-block.tsx +47 -3
- package/src/content/prose.module.css +13 -8
- package/src/controls/actions.module.css +14 -1
- package/src/controls/actions.module.css.d.ts +1 -0
- package/src/controls/actions.tsx +223 -75
- package/src/controls/controls.module.css +13 -31
- package/src/controls/enum-filter.tsx +2 -2
- package/src/controls/filter-context.tsx +11 -0
- package/src/controls/filter-pill.tsx +1 -0
- package/src/controls/index.ts +0 -1
- package/src/controls/multi-select-filter.tsx +2 -2
- package/src/controls/sync-button.module.css +2 -1
- package/src/dashboard/section.module.css +1 -26
- package/src/dashboard/section.tsx +1 -0
- package/src/dashboard/stat-card.module.css +6 -9
- package/src/dashboard/stat-card.tsx +6 -3
- package/src/dashboard/stat-group.module.css +33 -66
- package/src/dashboard/widget-grid.module.css +11 -38
- package/src/dashboard/widget-grid.tsx +7 -6
- package/src/dashboard/widget-header.module.css +145 -133
- package/src/dashboard/widget-header.module.css.d.ts +2 -0
- package/src/dashboard/widget-header.tsx +45 -11
- package/src/data/data-table-state.ts +218 -0
- package/src/data/data-table.module.css +94 -0
- package/src/data/data-table.module.css.d.ts +11 -0
- package/src/data/data-table.tsx +547 -299
- package/src/data/virtual-list.tsx +31 -0
- package/src/forms/form-layout.module.css +20 -5
- package/src/forms/form-layout.module.css.d.ts +1 -0
- package/src/forms/form-layout.tsx +12 -10
- package/src/guard/index.ts +188 -3
- package/src/guard/types.ts +3 -2
- package/src/index.ts +2 -0
- package/src/notifications/center.tsx +3 -0
- package/src/provider/index.tsx +60 -7
- package/src/shell/app-brand.module.css +2 -2
- package/src/shell/app-brand.tsx +1 -0
- package/src/shell/app-header.module.css +18 -8
- package/src/shell/app-main.module.css +54 -3
- package/src/shell/app-main.module.css.d.ts +1 -0
- package/src/shell/app-mobile-nav.module.css +16 -4
- package/src/shell/app-sidebar.module.css +4 -6
- package/src/shell/aside-docking.ts +54 -0
- package/src/shell/index.tsx +178 -129
- package/src/shell/mobile-nav-model.ts +1 -1
- package/src/shell/page-aside.tsx +70 -21
- package/src/shell/page-bar.module.css +10 -34
- package/src/shell/page-bar.tsx +10 -5
- package/src/shell/use-breakpoint.ts +9 -45
- package/src/shell/use-size-class.ts +31 -0
- package/src/state/persisted-or-local.ts +10 -4
- package/src/state/persisted.ts +76 -17
- package/src/styles.css +41 -0
- package/src/surfaces.ts +9 -1
- package/src/theme/controls.module.css +7 -0
- package/src/theme/ctl-theme.tsx +15 -3
- package/src/theme/floating.module.css +37 -0
- package/src/theme/floating.module.css.d.ts +3 -0
- package/src/theme/index.ts +46 -8
- package/src/theme/nav-link.module.css +7 -0
- package/src/theme-lab/derive-controls.tsx +2 -0
- package/src/tokens/index.ts +20 -30
- package/src/tokens/palette.ts +6 -28
- package/src/tokens/size-classes.ts +46 -0
- package/dist/shell/isomorphic-layout-effect.d.ts.map +0 -1
- /package/dist/{shell → common}/isomorphic-layout-effect.js +0 -0
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useState } from "react";
|
|
1
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
2
|
import { alpha, VX } from "../../tokens/index.js";
|
|
4
|
-
import {
|
|
3
|
+
import { DOTS_HIT_GAP, LEGEND_DOT_SIZE, LEGEND_ROW_GAP, orderEntries } from "./chart-frame-layout.js";
|
|
4
|
+
import { useChartMetrics, useCoarsePointer } from "./chart-tier.js";
|
|
5
|
+
import { LegendDisclosure, useLegendDisclosure } from "./legend-disclosure.js";
|
|
5
6
|
const LEGEND_ITEM_BASE = {
|
|
6
7
|
display: "flex",
|
|
7
8
|
alignItems: "center",
|
|
@@ -20,33 +21,26 @@ const LEGEND_ITEM_BUTTON = {
|
|
|
20
21
|
color: "inherit",
|
|
21
22
|
textAlign: "inherit"
|
|
22
23
|
};
|
|
23
|
-
const GROUP_ORDER = ["series", "overlay", "reference"];
|
|
24
24
|
const NO_HIDDEN = /* @__PURE__ */ new Set();
|
|
25
|
-
|
|
26
|
-
function orderEntries(items, groups) {
|
|
27
|
-
if (!groups) return { entries: items, dividerAfter: /* @__PURE__ */ new Set() };
|
|
28
|
-
const dividerAfter = /* @__PURE__ */ new Set();
|
|
29
|
-
const entries = [];
|
|
30
|
-
const nonEmptyGroups = GROUP_ORDER.map(
|
|
31
|
-
(role) => items.filter((item) => roleOf(item) === role)
|
|
32
|
-
).filter((group) => group.length > 0);
|
|
33
|
-
nonEmptyGroups.forEach((group, i) => {
|
|
34
|
-
entries.push(...group);
|
|
35
|
-
if (i < nonEmptyGroups.length - 1) dividerAfter.add(entries.length - 1);
|
|
36
|
-
});
|
|
37
|
-
return { entries, dividerAfter };
|
|
38
|
-
}
|
|
39
|
-
function wrapperStyle(placement, fontSize) {
|
|
25
|
+
function wrapperStyle(placement, fontSize, dots) {
|
|
40
26
|
const vertical = placement === "left" || placement === "right";
|
|
27
|
+
const gap = dots ? DOTS_HIT_GAP : VX.legendGap;
|
|
41
28
|
return {
|
|
42
29
|
display: "flex",
|
|
43
30
|
flexDirection: vertical ? "column" : "row",
|
|
44
31
|
flexWrap: vertical ? "nowrap" : "wrap",
|
|
45
32
|
alignItems: vertical ? "flex-start" : "center",
|
|
46
|
-
justifyContent:
|
|
47
|
-
columnGap:
|
|
48
|
-
|
|
49
|
-
|
|
33
|
+
justifyContent: "flex-start",
|
|
34
|
+
columnGap: gap,
|
|
35
|
+
// Always the tight row gap (R2C-9): the wider dots COLUMN gap is a hit-overlap cap, not
|
|
36
|
+
// breathing room between wrapped rows — a dots-mode header legend is 1 row by law
|
|
37
|
+
// (`LEGEND_ROWS.header` in `chart-layout.ts`) anyway, so this only ever shows in the band.
|
|
38
|
+
rowGap: LEGEND_ROW_GAP,
|
|
39
|
+
// Caps each entry's `[data-basalt-hit]` overlay at the real inter-entry gap (styles.css).
|
|
40
|
+
...{ "--vx-hit-gap": `${gap}px` },
|
|
41
|
+
// A dots-mode row has no text baseline to breathe around — the header-fold law (wave 8) is
|
|
42
|
+
// the reason this row exists at all, so it gets the same tight treatment.
|
|
43
|
+
padding: dots ? "4px 0 2px" : "8px 0 2px",
|
|
50
44
|
fontSize,
|
|
51
45
|
color: VX.muted
|
|
52
46
|
};
|
|
@@ -145,6 +139,21 @@ const LEGEND_CHILD_STYLE = {
|
|
|
145
139
|
fontSize: "0.85em",
|
|
146
140
|
opacity: 0.75
|
|
147
141
|
};
|
|
142
|
+
function LegendDot({ item }) {
|
|
143
|
+
return /* @__PURE__ */ jsx(
|
|
144
|
+
"span",
|
|
145
|
+
{
|
|
146
|
+
style: {
|
|
147
|
+
width: LEGEND_DOT_SIZE,
|
|
148
|
+
height: LEGEND_DOT_SIZE,
|
|
149
|
+
borderRadius: "50%",
|
|
150
|
+
// theme-allow raw-surface — a circle shape, not a surface corner
|
|
151
|
+
backgroundColor: item.color,
|
|
152
|
+
flexShrink: 0
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
}
|
|
148
157
|
function LegendChildSwatch({ item }) {
|
|
149
158
|
if (item.shape === "bar") {
|
|
150
159
|
return /* @__PURE__ */ jsx(
|
|
@@ -193,59 +202,57 @@ function ChartLegend({
|
|
|
193
202
|
placement = "bottom",
|
|
194
203
|
groups = false,
|
|
195
204
|
maxRows,
|
|
205
|
+
mode = "chips",
|
|
196
206
|
className,
|
|
197
207
|
style
|
|
198
208
|
}) {
|
|
199
|
-
const tier =
|
|
200
|
-
const
|
|
201
|
-
const
|
|
202
|
-
|
|
203
|
-
if (key !== void 0) onHighlight?.(key);
|
|
204
|
-
};
|
|
209
|
+
const tier = useChartMetrics();
|
|
210
|
+
const coarse = useCoarsePointer();
|
|
211
|
+
const { open, panelId, openFrom, close, panel } = useLegendDisclosure(coarse);
|
|
212
|
+
const handleEnter = (key) => onHighlight?.(key);
|
|
205
213
|
const handleLeave = () => onHighlight?.(null);
|
|
206
|
-
const handleToggle = (e) => {
|
|
207
|
-
const key = e.currentTarget.dataset["legendKey"];
|
|
208
|
-
if (key !== void 0) onToggle?.(key);
|
|
209
|
-
};
|
|
210
214
|
const idPrefix = chartId ? `${chartId}-` : "";
|
|
211
215
|
const vertical = placement === "left" || placement === "right";
|
|
212
216
|
const { entries, dividerAfter } = orderEntries(items, groups);
|
|
213
|
-
const
|
|
214
|
-
const
|
|
215
|
-
const
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
"button",
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
},
|
|
234
|
-
...onToggle !== void 0 && { onClick: handleToggle },
|
|
235
|
-
onMouseEnter: handleEnter,
|
|
236
|
-
onMouseLeave: handleLeave,
|
|
237
|
-
onFocus: handleEnter,
|
|
238
|
-
onBlur: handleLeave,
|
|
239
|
-
children: [
|
|
240
|
-
/* @__PURE__ */ jsx(LegendSwatch, { item, idPrefix }),
|
|
241
|
-
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
242
|
-
item.note ? /* @__PURE__ */ jsx("span", { style: LEGEND_NOTE_STYLE, children: item.note }) : null,
|
|
243
|
-
item.children?.map((child) => /* @__PURE__ */ jsx(LegendChild, { item: child }, child.key))
|
|
244
|
-
]
|
|
217
|
+
const rolledUp = maxRows === void 0 ? 0 : Math.max(entries.length - maxRows, 0);
|
|
218
|
+
const visible = rolledUp > 0 ? entries.slice(0, maxRows) : entries;
|
|
219
|
+
const entryButton = (item, inPanel = false) => {
|
|
220
|
+
const isDotTrigger = !inPanel && mode === "dots";
|
|
221
|
+
return /* @__PURE__ */ jsx(
|
|
222
|
+
"button",
|
|
223
|
+
{
|
|
224
|
+
type: "button",
|
|
225
|
+
"data-basalt-hit": true,
|
|
226
|
+
...!inPanel && { "data-legend-key": item.key },
|
|
227
|
+
"aria-label": item.note ? `${item.label} \u2014 ${item.note}` : item.label,
|
|
228
|
+
...isDotTrigger && { title: item.label, "aria-haspopup": "dialog" },
|
|
229
|
+
...isDotTrigger ? { "aria-expanded": open, "aria-controls": panelId } : onToggle !== void 0 && { "aria-pressed": !hidden.has(item.key) },
|
|
230
|
+
style: {
|
|
231
|
+
...LEGEND_ITEM_BUTTON,
|
|
232
|
+
cursor: onToggle === void 0 && !isDotTrigger ? "default" : "pointer",
|
|
233
|
+
// Toggled-off wins over hover-dimming: a hidden series must read as hidden even while
|
|
234
|
+
// it is the one being hovered.
|
|
235
|
+
opacity: hidden.has(item.key) ? 0.35 : highlighted === null || highlighted === item.key ? 1 : 0.3,
|
|
236
|
+
textDecoration: hidden.has(item.key) ? "line-through" : "none"
|
|
245
237
|
},
|
|
246
|
-
item.key
|
|
247
|
-
|
|
238
|
+
...isDotTrigger ? { onClick: (e) => openFrom(e.currentTarget) } : onToggle !== void 0 && { onClick: () => onToggle(item.key) },
|
|
239
|
+
onMouseEnter: () => handleEnter(item.key),
|
|
240
|
+
onMouseLeave: handleLeave,
|
|
241
|
+
onFocus: () => handleEnter(item.key),
|
|
242
|
+
onBlur: handleLeave,
|
|
243
|
+
children: !inPanel && mode === "dots" ? /* @__PURE__ */ jsx(LegendDot, { item }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
244
|
+
/* @__PURE__ */ jsx(LegendSwatch, { item, idPrefix: inPanel ? `${idPrefix}disclosure-` : idPrefix }),
|
|
245
|
+
/* @__PURE__ */ jsx("span", { children: item.label }),
|
|
246
|
+
item.note ? /* @__PURE__ */ jsx("span", { style: LEGEND_NOTE_STYLE, children: item.note }) : null,
|
|
247
|
+
item.children?.map((child) => /* @__PURE__ */ jsx(LegendChild, { item: child }, child.key))
|
|
248
|
+
] })
|
|
249
|
+
},
|
|
250
|
+
item.key
|
|
248
251
|
);
|
|
252
|
+
};
|
|
253
|
+
const nodes = [];
|
|
254
|
+
visible.forEach((item, i) => {
|
|
255
|
+
nodes.push(entryButton(item));
|
|
249
256
|
if (dividerAfter.has(i))
|
|
250
257
|
nodes.push(/* @__PURE__ */ jsx(LegendDivider, { columnLayout: vertical }, `divider-${item.key}`));
|
|
251
258
|
});
|
|
@@ -255,21 +262,27 @@ function ChartLegend({
|
|
|
255
262
|
"button",
|
|
256
263
|
{
|
|
257
264
|
type: "button",
|
|
258
|
-
"
|
|
259
|
-
|
|
265
|
+
"data-basalt-hit": true,
|
|
266
|
+
"aria-expanded": open,
|
|
267
|
+
"aria-haspopup": "dialog",
|
|
268
|
+
"aria-controls": panelId,
|
|
269
|
+
onClick: (e) => open ? close() : openFrom(e.currentTarget),
|
|
260
270
|
style: { ...LEGEND_ITEM_BUTTON, cursor: "pointer", textDecoration: "underline" },
|
|
261
|
-
children:
|
|
271
|
+
children: `All ${entries.length}`
|
|
262
272
|
},
|
|
263
273
|
"legend-more"
|
|
264
274
|
)
|
|
265
275
|
);
|
|
266
276
|
}
|
|
267
|
-
return /* @__PURE__ */
|
|
277
|
+
return /* @__PURE__ */ jsxs(
|
|
268
278
|
"div",
|
|
269
279
|
{
|
|
270
280
|
...className !== void 0 && { className },
|
|
271
|
-
style: { ...wrapperStyle(placement, tier.legendFontSize), ...style },
|
|
272
|
-
children:
|
|
281
|
+
style: { ...wrapperStyle(placement, tier.legendFontSize, mode === "dots"), ...style },
|
|
282
|
+
children: [
|
|
283
|
+
nodes,
|
|
284
|
+
/* @__PURE__ */ jsx(LegendDisclosure, { ...panel, fontSize: tier.legendFontSize, children: entries.map((item) => entryButton(item, true)) })
|
|
285
|
+
]
|
|
273
286
|
}
|
|
274
287
|
);
|
|
275
288
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
import type { TooltipRowData } from '../series.js';
|
|
2
3
|
/** Tooltip header — shows formatted date + optional right-aligned label with color. */
|
|
3
4
|
export declare function TooltipHeader({ date, label, labelColor, format, }: {
|
|
4
5
|
date: string;
|
|
@@ -21,6 +22,10 @@ export declare function TooltipRow({ color, label, value, valueColor, shape, str
|
|
|
21
22
|
/** Render the line swatch as dashed (only applies to shape='line'). */
|
|
22
23
|
dashed?: boolean;
|
|
23
24
|
}): import("react").JSX.Element;
|
|
25
|
+
/** The derived rows (`deriveTooltipRows`), one {@link TooltipRow} each. */
|
|
26
|
+
export declare function TooltipRows({ rows }: {
|
|
27
|
+
rows: readonly TooltipRowData[];
|
|
28
|
+
}): import("react").JSX.Element[];
|
|
24
29
|
export declare function TooltipBody({ children }: {
|
|
25
30
|
children: ReactNode;
|
|
26
31
|
}): import("react").JSX.Element;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChartTooltip.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/ChartTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"ChartTooltip.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/ChartTooltip.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,SAAS,EAAE,MAAM,OAAO,CAAA;AAIrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAoB/C,uFAAuF;AACvF,wBAAgB,aAAa,CAAC,EAC5B,IAAI,EACJ,KAAK,EACL,UAAU,EACV,MAAuB,GACxB,EAAE;IACD,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;sGAGkG;IAClG,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAClC,+BAoCA;AAED,4CAA4C;AAC5C,wBAAgB,UAAU,CAAC,EACzB,KAAK,EACL,KAAK,EACL,KAAK,EACL,UAAU,EACV,KAAK,EACL,WAAW,EACX,MAAM,GACP,EAAE;IACD,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,uEAAuE;IACvE,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB,+BA0CA;AAED,2EAA2E;AAC3E,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,SAAS,cAAc,EAAE,CAAA;CAAE,iCAYxE;AAED,wBAAgB,WAAW,CAAC,EAAE,QAAQ,EAAE,EAAE;IAAE,QAAQ,EAAE,SAAS,CAAA;CAAE,+BAEhE;AAsBD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,MAAM,EACN,QAAe,EACf,QAAQ,GACT,EAAE;IACD,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACvC;;;8CAG0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,SAAS,CAAA;CACpB,sCA2DA"}
|
|
@@ -3,11 +3,11 @@ import { useLayoutEffect, useRef, useState, useSyncExternalStore } from "react";
|
|
|
3
3
|
import { createPortal } from "react-dom";
|
|
4
4
|
import { VX } from "../../tokens/index.js";
|
|
5
5
|
import { fmtTooltipDate } from "../utils/format.js";
|
|
6
|
-
import {
|
|
6
|
+
import { useChartMetrics } from "./chart-tier.js";
|
|
7
7
|
const TOOLTIP_STYLES = {
|
|
8
8
|
position: "fixed",
|
|
9
9
|
pointerEvents: "none",
|
|
10
|
-
zIndex:
|
|
10
|
+
zIndex: VX.zIndexFloating,
|
|
11
11
|
backgroundColor: VX.surface.panel,
|
|
12
12
|
borderRadius: "var(--vx-radius-floating)",
|
|
13
13
|
padding: "0",
|
|
@@ -114,6 +114,20 @@ function TooltipRow({
|
|
|
114
114
|
}
|
|
115
115
|
);
|
|
116
116
|
}
|
|
117
|
+
function TooltipRows({ rows }) {
|
|
118
|
+
return rows.map((row) => /* @__PURE__ */ jsx(
|
|
119
|
+
TooltipRow,
|
|
120
|
+
{
|
|
121
|
+
color: row.color,
|
|
122
|
+
label: row.label,
|
|
123
|
+
value: row.value,
|
|
124
|
+
shape: row.shape,
|
|
125
|
+
dashed: row.dashed,
|
|
126
|
+
...row.strokeWidth !== void 0 && { strokeWidth: row.strokeWidth }
|
|
127
|
+
},
|
|
128
|
+
row.key
|
|
129
|
+
));
|
|
130
|
+
}
|
|
117
131
|
function TooltipBody({ children }) {
|
|
118
132
|
return /* @__PURE__ */ jsx("div", { style: { padding: "5px 0" }, children });
|
|
119
133
|
}
|
|
@@ -132,7 +146,7 @@ function ChartTooltipFloat({
|
|
|
132
146
|
const ref = useRef(null);
|
|
133
147
|
const [box, setBox] = useState(null);
|
|
134
148
|
const isClient = useIsClient();
|
|
135
|
-
const { tooltipMinWidth } =
|
|
149
|
+
const { tooltipMinWidth } = useChartMetrics();
|
|
136
150
|
useLayoutEffect(() => {
|
|
137
151
|
const el = ref.current;
|
|
138
152
|
if (el === null) return;
|
|
@@ -147,6 +161,7 @@ function ChartTooltipFloat({
|
|
|
147
161
|
const height = box?.height ?? 0;
|
|
148
162
|
const vw = window.innerWidth;
|
|
149
163
|
const vh = window.innerHeight;
|
|
164
|
+
if (anchor.y < 0 || anchor.y > vh) return null;
|
|
150
165
|
const flipsLeft = anchor.x + TOOLTIP_GAP + width + VIEWPORT_MARGIN > vw;
|
|
151
166
|
const left = flipsLeft ? Math.max(VIEWPORT_MARGIN, anchor.x - TOOLTIP_GAP - width) : anchor.x + TOOLTIP_GAP;
|
|
152
167
|
const top = Math.min(
|
|
@@ -177,5 +192,6 @@ export {
|
|
|
177
192
|
ChartTooltipFloat,
|
|
178
193
|
TooltipBody,
|
|
179
194
|
TooltipHeader,
|
|
180
|
-
TooltipRow
|
|
195
|
+
TooltipRow,
|
|
196
|
+
TooltipRows
|
|
181
197
|
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
2
|
import { VX } from "../../tokens/index.js";
|
|
3
|
-
import {
|
|
3
|
+
import { useChartMetrics } from "./chart-tier.js";
|
|
4
4
|
function Crosshair({
|
|
5
5
|
x,
|
|
6
6
|
top,
|
|
@@ -14,7 +14,7 @@ function SeriesDot({
|
|
|
14
14
|
color,
|
|
15
15
|
r
|
|
16
16
|
}) {
|
|
17
|
-
const { dotR } =
|
|
17
|
+
const { dotR } = useChartMetrics();
|
|
18
18
|
return /* @__PURE__ */ jsx("circle", { cx, cy, r: r ?? dotR, fill: color, stroke: VX.dotStroke, strokeWidth: 2 });
|
|
19
19
|
}
|
|
20
20
|
export {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { FocusEventHandler, KeyboardEventHandler, PointerEventHandler } from 'react';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
*
|
|
6
|
-
* With `onKeyDown` it also becomes the chart's keyboard affordance: the rect takes focus and
|
|
7
|
-
* ←/→ scrub the cursor, so a chart's values are reachable without a pointer.
|
|
8
|
-
*/
|
|
9
|
-
export declare function HoverOverlay({ width, height, onMove, onLeave, onKeyDown, onBlur, ariaLabel, valueNow, valueMax, valueText, }: {
|
|
2
|
+
import type { ChartCursor } from '../hooks/useChartCursor.js';
|
|
3
|
+
/** Props of {@link HoverOverlay}. */
|
|
4
|
+
export type HoverOverlayProps = {
|
|
10
5
|
width: number;
|
|
11
6
|
height: number;
|
|
12
7
|
onMove: PointerEventHandler<SVGRectElement>;
|
|
8
|
+
/** Coarse-pointer tap: resolves + shows the tooltip immediately, with no preceding `pointermove`
|
|
9
|
+
* (`docs/CHARTS-SPEC.md` §4, Tooltip). The press is provisional; `onUp` commits it. */
|
|
10
|
+
onDown?: PointerEventHandler<SVGRectElement>;
|
|
11
|
+
/** Commits the provisional touch press so the pin survives the lift. */
|
|
12
|
+
onUp?: PointerEventHandler<SVGRectElement>;
|
|
13
13
|
onLeave: PointerEventHandler<SVGRectElement>;
|
|
14
14
|
/** Present = the overlay is focusable and scrubs on ←/→. */
|
|
15
15
|
onKeyDown?: KeyboardEventHandler<SVGRectElement>;
|
|
@@ -21,5 +21,25 @@ export declare function HoverOverlay({ width, height, onMove, onLeave, onKeyDown
|
|
|
21
21
|
valueMax?: number;
|
|
22
22
|
/** Human-readable label for the focused point (the formatted x key). */
|
|
23
23
|
valueText?: string;
|
|
24
|
-
}
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Transparent <rect> that captures pointer events (mouse + touch + pen) for tooltip + crosshair
|
|
27
|
+
* sync.
|
|
28
|
+
*
|
|
29
|
+
* With `onKeyDown` it also becomes the chart's keyboard affordance: the rect takes focus and
|
|
30
|
+
* ←/→ scrub the cursor, so a chart's values are reachable without a pointer.
|
|
31
|
+
*/
|
|
32
|
+
export declare function HoverOverlay({ width, height, onMove, onDown, onUp, onLeave, onKeyDown, onBlur, ariaLabel, valueNow, valueMax, valueText, }: HoverOverlayProps): import("react").JSX.Element;
|
|
33
|
+
/**
|
|
34
|
+
* Everything a FOCUSABLE overlay over indexed data takes besides its rect: the cursor's pointer and
|
|
35
|
+
* keyboard handlers plus the slider label/position. `CartesianChart`, `DualPanel`'s top pane and
|
|
36
|
+
* the banded kinds all wire it identically, so it is stated once.
|
|
37
|
+
*/
|
|
38
|
+
export declare function cursorSliderProps<T>(input: {
|
|
39
|
+
cursor: ChartCursor<T>;
|
|
40
|
+
data: readonly T[];
|
|
41
|
+
getX: (d: T) => string;
|
|
42
|
+
formatX: (key: string) => string;
|
|
43
|
+
ariaLabel: string | undefined;
|
|
44
|
+
}): Omit<HoverOverlayProps, 'width' | 'height'>;
|
|
25
45
|
//# sourceMappingURL=HoverOverlay.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HoverOverlay.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/HoverOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"HoverOverlay.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/HoverOverlay.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAA;AACzF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAG1D,qCAAqC;AACrC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC3C;2FACuF;IACvF,MAAM,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC5C,wEAAwE;IACxE,IAAI,CAAC,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC1C,OAAO,EAAE,mBAAmB,CAAC,cAAc,CAAC,CAAA;IAC5C,4DAA4D;IAC5D,SAAS,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAA;IAChD,MAAM,CAAC,EAAE,iBAAiB,CAAC,cAAc,CAAC,CAAA;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,wEAAwE;IACxE,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAC3B,KAAK,EACL,MAAM,EACN,MAAM,EACN,MAAM,EACN,IAAI,EACJ,OAAO,EACP,SAAS,EACT,MAAM,EACN,SAAS,EACT,QAAQ,EACR,QAAQ,EACR,SAAS,GACV,EAAE,iBAAiB,+BAiCnB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,KAAK,EAAE;IAC1C,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,CAAA;IACtB,IAAI,EAAE,SAAS,CAAC,EAAE,CAAA;IAClB,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,MAAM,CAAA;IACtB,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAChC,SAAS,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,GAAG,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,QAAQ,CAAC,CAc9C"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import styles from "./HoverOverlay.module.css";
|
|
2
3
|
function HoverOverlay({
|
|
3
4
|
width,
|
|
4
5
|
height,
|
|
5
6
|
onMove,
|
|
7
|
+
onDown,
|
|
8
|
+
onUp,
|
|
6
9
|
onLeave,
|
|
7
10
|
onKeyDown,
|
|
8
11
|
onBlur,
|
|
@@ -11,34 +14,58 @@ function HoverOverlay({
|
|
|
11
14
|
valueMax,
|
|
12
15
|
valueText
|
|
13
16
|
}) {
|
|
14
|
-
return
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
17
|
+
return (
|
|
18
|
+
// `touch-action: pan-y` lives on the plot's `<svg>` (each kind's own), NOT here: Chrome ignores
|
|
19
|
+
// `touch-action` on an SVG child `<rect>`, so the browser claims a horizontal pan and cancels
|
|
20
|
+
// the pointer (`R2C-2`). The `overlay` class owns the focus ring: no UA outline on tap, a VX
|
|
21
|
+
// accent inset under `:focus-visible` (`R2C-15`).
|
|
22
|
+
/* @__PURE__ */ jsx(
|
|
23
|
+
"rect",
|
|
24
|
+
{
|
|
25
|
+
className: styles.overlay,
|
|
26
|
+
width,
|
|
27
|
+
height,
|
|
28
|
+
fill: "transparent",
|
|
29
|
+
...onKeyDown !== void 0 && {
|
|
30
|
+
tabIndex: 0,
|
|
31
|
+
// `slider`, not `application`: `application` would drop this node out of the screen
|
|
32
|
+
// reader's normal browse mode entirely, which is a far bigger hammer than an arrow-key
|
|
33
|
+
// scrub needs. A slider announces both the affordance and the focused point.
|
|
34
|
+
role: "slider",
|
|
35
|
+
"aria-label": ariaLabel ?? "Chart data \u2014 use arrow keys to scrub",
|
|
36
|
+
"aria-orientation": "horizontal",
|
|
37
|
+
"aria-valuemin": 0,
|
|
38
|
+
...valueMax !== void 0 && { "aria-valuemax": valueMax },
|
|
39
|
+
...valueNow !== void 0 && { "aria-valuenow": valueNow },
|
|
40
|
+
...valueText !== void 0 && { "aria-valuetext": valueText },
|
|
41
|
+
onKeyDown,
|
|
42
|
+
...onBlur !== void 0 && { onBlur }
|
|
43
|
+
},
|
|
44
|
+
onPointerMove: onMove,
|
|
45
|
+
...onDown !== void 0 && { onPointerDown: onDown },
|
|
46
|
+
...onUp !== void 0 && { onPointerUp: onUp },
|
|
47
|
+
onPointerLeave: onLeave,
|
|
48
|
+
onPointerCancel: onLeave
|
|
49
|
+
}
|
|
50
|
+
)
|
|
40
51
|
);
|
|
41
52
|
}
|
|
53
|
+
function cursorSliderProps(input) {
|
|
54
|
+
const { cursor, data, getX, formatX, ariaLabel } = input;
|
|
55
|
+
const { point } = cursor;
|
|
56
|
+
return {
|
|
57
|
+
onMove: cursor.onPointerMove,
|
|
58
|
+
onDown: cursor.onPointerDown,
|
|
59
|
+
onUp: cursor.onPointerUp,
|
|
60
|
+
onLeave: cursor.onPointerLeave,
|
|
61
|
+
onKeyDown: cursor.onKeyDown,
|
|
62
|
+
onBlur: cursor.onBlur,
|
|
63
|
+
valueMax: Math.max(data.length - 1, 0),
|
|
64
|
+
...point !== null && { valueNow: data.indexOf(point), valueText: formatX(getX(point)) },
|
|
65
|
+
...ariaLabel !== void 0 && { ariaLabel }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
42
68
|
export {
|
|
43
|
-
HoverOverlay
|
|
69
|
+
HoverOverlay,
|
|
70
|
+
cursorSliderProps
|
|
44
71
|
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* `HoverOverlay` — the transparent plot rect every cartesian kind scrubs through. A tap focuses it
|
|
3
|
+
* on pointerdown, so the UA's own outline would ring the whole plot on every phone tap (`R2C-15`);
|
|
4
|
+
* keyboard focus keeps a VX accent inset instead.
|
|
5
|
+
*/
|
|
6
|
+
.overlay {
|
|
7
|
+
outline: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.overlay:focus-visible {
|
|
11
|
+
outline: 1px solid var(--vx-accent);
|
|
12
|
+
outline-offset: -1px;
|
|
13
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Dispatch } from 'react';
|
|
2
|
+
/** One frame claiming or releasing the card's header legend slot. */
|
|
3
|
+
export type LegendSlotAction = {
|
|
4
|
+
type: 'claim' | 'release';
|
|
5
|
+
id: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* The ONE owner of the legend-slot protocol (`docs/waves/PLAN.md` wave 3, P2-9): claimants in claim
|
|
9
|
+
* order, and the head owns the slot. A later claimant is denied simply by not being the head, and
|
|
10
|
+
* it takes over the moment everything ahead of it releases — no retry signal, no ownership mirrored
|
|
11
|
+
* in a ref. Returns the same array on a no-op so a repeated claim/release never re-renders the card.
|
|
12
|
+
*/
|
|
13
|
+
export declare function legendSlotReducer(claimants: readonly string[], { type, id }: LegendSlotAction): readonly string[];
|
|
14
|
+
/**
|
|
15
|
+
* `ChartCard`'s internal context: `inCard` (a frame inside a card treats its computed height as a
|
|
16
|
+
* MINIMUM and grows into the card body), the legend slot — the empty header-row box a chart will portal its legend into
|
|
17
|
+
* (`docs/CHARTS-SPEC.md` §5, Legend), so a card has one chrome band, not two — and `short`, the same
|
|
18
|
+
* `measuredHeight < CARD_SHORT_HEIGHT` flag `ChartCard` already computes for the header-fold law
|
|
19
|
+
* (`data-basalt-card-short`), threaded through so `ChartFrame` can fold its header-slot legend to
|
|
20
|
+
* 'dots' before it eats the plot floor (`docs/CHARTS-SPEC.md` §5, wave 11). `null`/`false` until the slot
|
|
21
|
+
* mounts, and outside any card. Deliberately not exported from any barrel.
|
|
22
|
+
*
|
|
23
|
+
* `legendClaimants` is {@link legendSlotReducer}'s queue (its head owns the slot) and
|
|
24
|
+
* `dispatchLegendSlot` feeds it. Outside any card there is no slot, so nothing ever claims.
|
|
25
|
+
*/
|
|
26
|
+
export declare const ChartCardContext: import("react").Context<{
|
|
27
|
+
legendSlot: HTMLDivElement | null;
|
|
28
|
+
inCard: boolean;
|
|
29
|
+
short: boolean;
|
|
30
|
+
legendClaimants: readonly string[];
|
|
31
|
+
dispatchLegendSlot: Dispatch<LegendSlotAction>;
|
|
32
|
+
}>;
|
|
33
|
+
//# sourceMappingURL=chart-card-context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chart-card-context.d.ts","sourceRoot":"","sources":["../../../src/charts/primitives/chart-card-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAErC,qEAAqE;AACrE,MAAM,MAAM,gBAAgB,GAAG;IAAE,IAAI,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAA;AAExE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,MAAM,EAAE,EAC5B,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,gBAAgB,GAC7B,SAAS,MAAM,EAAE,CAInB;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,gBAAgB;gBACf,cAAc,GAAG,IAAI;YACzB,OAAO;WACR,OAAO;qBACG,SAAS,MAAM,EAAE;wBACd,QAAQ,CAAC,gBAAgB,CAAC;EAO9C,CAAA"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createContext } from "react";
|
|
2
|
+
function legendSlotReducer(claimants, { type, id }) {
|
|
3
|
+
const held = claimants.includes(id);
|
|
4
|
+
if (type === "claim") return held ? claimants : [...claimants, id];
|
|
5
|
+
return held ? claimants.filter((c) => c !== id) : claimants;
|
|
6
|
+
}
|
|
7
|
+
const ChartCardContext = createContext({
|
|
8
|
+
legendSlot: null,
|
|
9
|
+
inCard: false,
|
|
10
|
+
short: false,
|
|
11
|
+
legendClaimants: [],
|
|
12
|
+
dispatchLegendSlot: () => {
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
export {
|
|
16
|
+
ChartCardContext,
|
|
17
|
+
legendSlotReducer
|
|
18
|
+
};
|