basalt-ui 1.30.2 → 1.31.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 +31 -0
- package/MIGRATING.md +172 -12
- package/agent/rules/basalt-controls.md +19 -19
- package/agent/rules/basalt-mantine.md +1 -1
- package/configs/oxlint-plugin.js +254 -4
- package/configs/oxlint-plugin.test.ts +145 -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 +54 -41
- 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 +145 -131
- 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 +83 -68
- 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 +271 -125
- 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 +74 -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 +133 -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 +212 -71
- package/dist/charts/primitives/ChartTooltip.d.ts.map +1 -1
- package/dist/charts/primitives/ChartTooltip.js +4 -3
- package/dist/charts/primitives/Crosshair.js +2 -2
- package/dist/charts/primitives/HoverOverlay.d.ts +6 -1
- package/dist/charts/primitives/HoverOverlay.d.ts.map +1 -1
- package/dist/charts/primitives/HoverOverlay.js +37 -26
- 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 +29 -0
- package/dist/charts/primitives/chart-card-context.d.ts.map +1 -0
- package/dist/charts/primitives/chart-card-context.js +13 -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 +76 -29
- 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/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 +8 -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 +1 -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 +16 -4
- package/dist/dashboard/widget-grid.d.ts.map +1 -1
- 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.d.ts +23 -0
- package/dist/data/data-table.d.ts.map +1 -1
- package/dist/data/data-table.js +339 -141
- 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 +30 -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 +67 -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/provider/index.d.ts +20 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +22 -2
- 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/index.d.ts +12 -0
- package/dist/shell/index.d.ts.map +1 -1
- package/dist/shell/index.js +57 -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 +36 -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/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 +17 -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 +11 -1
- package/src/charts/kinds/Donut.tsx +153 -62
- package/src/charts/kinds/DualPanel.tsx +19 -4
- package/src/charts/kinds/Heatmap.tsx +61 -22
- package/src/charts/kinds/MirroredBars.tsx +15 -3
- 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 -68
- package/src/charts/primitives/ChartCard.tsx +141 -48
- package/src/charts/primitives/ChartFrame.tsx +243 -60
- package/src/charts/primitives/ChartLegend.tsx +257 -73
- package/src/charts/primitives/ChartTooltip.tsx +8 -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 +15 -4
- package/src/charts/primitives/chart-card-context.ts +37 -0
- package/src/charts/primitives/chart-frame-layout.ts +214 -177
- package/src/charts/primitives/chart-layout.ts +318 -0
- package/src/charts/primitives/chart-tier.tsx +66 -21
- 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 +8 -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 +1 -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 +16 -4
- 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.module.css +94 -0
- package/src/data/data-table.module.css.d.ts +11 -0
- package/src/data/data-table.tsx +503 -164
- package/src/data/virtual-list.tsx +31 -0
- package/src/forms/form-layout.module.css +30 -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 +183 -3
- package/src/guard/types.ts +3 -2
- package/src/index.ts +2 -0
- package/src/provider/index.tsx +53 -1
- 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/index.tsx +200 -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 +36 -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/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
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { useRef } from "react";
|
|
2
|
+
import { useIsomorphicLayoutEffect } from "./isomorphic-layout-effect.js";
|
|
3
|
+
function useMeasuredWidths(options) {
|
|
4
|
+
const { resolveRoot, signature, enabled = true, nonce = 0, extra, onMeasure } = options;
|
|
5
|
+
const boxes = useRef(/* @__PURE__ */ new Map());
|
|
6
|
+
const signatureRef = useRef(signature);
|
|
7
|
+
const remeasureRef = useRef(() => {
|
|
8
|
+
});
|
|
9
|
+
const resolveRef = useRef(resolveRoot);
|
|
10
|
+
resolveRef.current = resolveRoot;
|
|
11
|
+
const extraRef = useRef(extra);
|
|
12
|
+
extraRef.current = extra;
|
|
13
|
+
const onMeasureRef = useRef(onMeasure);
|
|
14
|
+
onMeasureRef.current = onMeasure;
|
|
15
|
+
useIsomorphicLayoutEffect(() => {
|
|
16
|
+
if (signatureRef.current !== signature) {
|
|
17
|
+
signatureRef.current = signature;
|
|
18
|
+
boxes.current.clear();
|
|
19
|
+
}
|
|
20
|
+
if (!enabled) {
|
|
21
|
+
remeasureRef.current = () => {
|
|
22
|
+
};
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const root = resolveRef.current();
|
|
26
|
+
if (root === null) {
|
|
27
|
+
remeasureRef.current = () => {
|
|
28
|
+
};
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const measure = () => {
|
|
32
|
+
onMeasureRef.current(root, boxes);
|
|
33
|
+
};
|
|
34
|
+
remeasureRef.current = measure;
|
|
35
|
+
if (typeof ResizeObserver === "undefined") {
|
|
36
|
+
measure();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const observer = new ResizeObserver(measure);
|
|
40
|
+
observer.observe(root);
|
|
41
|
+
for (const el of extraRef.current?.(root) ?? []) {
|
|
42
|
+
if (el !== null) observer.observe(el);
|
|
43
|
+
}
|
|
44
|
+
measure();
|
|
45
|
+
return () => observer.disconnect();
|
|
46
|
+
}, [enabled, signature, nonce]);
|
|
47
|
+
return { boxes, remeasure: () => remeasureRef.current() };
|
|
48
|
+
}
|
|
49
|
+
export {
|
|
50
|
+
useMeasuredWidths
|
|
51
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** A one-off, non-reactive read — for a dev-only check that runs once inside an effect/callback
|
|
2
|
+
* rather than subscribing for the component's lifetime. Prefer `useMediaQuery` for anything that
|
|
3
|
+
* should re-render on a match change. */
|
|
4
|
+
export declare function readMediaQuery(query: string, fallback: boolean): boolean;
|
|
5
|
+
export declare function useMediaQuery(query: string, serverFallback: boolean): boolean;
|
|
6
|
+
//# sourceMappingURL=use-media-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-media-query.d.ts","sourceRoot":"","sources":["../../src/common/use-media-query.ts"],"names":[],"mappings":"AAgCA;;yCAEyC;AACzC,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,GAAG,OAAO,CAExE;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO,CAgB7E"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { useCallback, useSyncExternalStore } from "react";
|
|
2
|
+
const cache = /* @__PURE__ */ new WeakMap();
|
|
3
|
+
function mediaQueryList(query) {
|
|
4
|
+
if (typeof window === "undefined" || typeof window.matchMedia !== "function") return null;
|
|
5
|
+
let byQuery = cache.get(window.matchMedia);
|
|
6
|
+
if (byQuery === void 0) {
|
|
7
|
+
byQuery = /* @__PURE__ */ new Map();
|
|
8
|
+
cache.set(window.matchMedia, byQuery);
|
|
9
|
+
}
|
|
10
|
+
const cached = byQuery.get(query);
|
|
11
|
+
if (cached !== void 0) return cached;
|
|
12
|
+
const list = window.matchMedia(query);
|
|
13
|
+
byQuery.set(query, list);
|
|
14
|
+
return list;
|
|
15
|
+
}
|
|
16
|
+
function readMediaQuery(query, fallback) {
|
|
17
|
+
return mediaQueryList(query)?.matches ?? fallback;
|
|
18
|
+
}
|
|
19
|
+
function useMediaQuery(query, serverFallback) {
|
|
20
|
+
const subscribe = useCallback(
|
|
21
|
+
(onStoreChange) => {
|
|
22
|
+
const list = mediaQueryList(query);
|
|
23
|
+
if (list === null) return () => {
|
|
24
|
+
};
|
|
25
|
+
list.addEventListener("change", onStoreChange);
|
|
26
|
+
return () => list.removeEventListener("change", onStoreChange);
|
|
27
|
+
},
|
|
28
|
+
[query]
|
|
29
|
+
);
|
|
30
|
+
const getSnapshot = useCallback(
|
|
31
|
+
() => mediaQueryList(query)?.matches ?? serverFallback,
|
|
32
|
+
[query, serverFallback]
|
|
33
|
+
);
|
|
34
|
+
const getServerSnapshot = useCallback(() => serverFallback, [serverFallback]);
|
|
35
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
36
|
+
}
|
|
37
|
+
export {
|
|
38
|
+
readMediaQuery,
|
|
39
|
+
useMediaQuery
|
|
40
|
+
};
|
|
@@ -20,6 +20,15 @@ type CheckResult = string | null | undefined | Array<string | null | undefined>;
|
|
|
20
20
|
* )
|
|
21
21
|
*/
|
|
22
22
|
export declare function useValidateProps(component: string, check: () => CheckResult, deps: unknown[]): void;
|
|
23
|
+
/**
|
|
24
|
+
* The same once-per-`(component, message)` dev diagnostic {@link useValidateProps} logs, for a
|
|
25
|
+
* caller that already owns the effect a check would otherwise race — a decision made synchronously
|
|
26
|
+
* inside a `useLayoutEffect` (e.g. `ChartFrame`'s header-slot claim, P2-9) has no business waiting a
|
|
27
|
+
* further render for a REACTIVE check on state that effect itself just set: that state update lags
|
|
28
|
+
* one commit behind the decision, and a passive-effect check racing it warns about instances that
|
|
29
|
+
* are about to win in the very next render.
|
|
30
|
+
*/
|
|
31
|
+
export declare function reportOnce(component: string, message: string): void;
|
|
23
32
|
/** Test seam. The once-per-message Set is module state, so a suite has to be able to clear it. */
|
|
24
33
|
export declare function resetValidatedProps(): void;
|
|
25
34
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/common/validate.ts"],"names":[],"mappings":"AAYA,iGAAiG;AACjG,KAAK,WAAW,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAU/E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,WAAW,EACxB,IAAI,EAAE,OAAO,EAAE,GACd,IAAI,
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/common/validate.ts"],"names":[],"mappings":"AAYA,iGAAiG;AACjG,KAAK,WAAW,GAAG,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;AAU/E;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,WAAW,EACxB,IAAI,EAAE,OAAO,EAAE,GACd,IAAI,CAYN;AAED;;;;;;;GAOG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAMnE;AAED,kGAAkG;AAClG,wBAAgB,mBAAmB,IAAI,IAAI,CAE1C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,MAAM,EAClD,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,CAAC,EACR,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,EAC7C,KAAK,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,GACxD,IAAI,CASN"}
|
package/dist/common/validate.js
CHANGED
|
@@ -9,13 +9,17 @@ function useValidateProps(component, check, deps) {
|
|
|
9
9
|
const messages = Array.isArray(result) ? result : [result];
|
|
10
10
|
for (const raw of messages) {
|
|
11
11
|
if (raw === null || raw === void 0) continue;
|
|
12
|
-
|
|
13
|
-
if (reported.has(key)) continue;
|
|
14
|
-
reported.add(key);
|
|
15
|
-
console.error(raw);
|
|
12
|
+
reportOnce(component, raw);
|
|
16
13
|
}
|
|
17
14
|
}, deps);
|
|
18
15
|
}
|
|
16
|
+
function reportOnce(component, message) {
|
|
17
|
+
if (!isDev()) return;
|
|
18
|
+
const key = `${component} ${message}`;
|
|
19
|
+
if (reported.has(key)) return;
|
|
20
|
+
reported.add(key);
|
|
21
|
+
console.error(message);
|
|
22
|
+
}
|
|
19
23
|
function resetValidatedProps() {
|
|
20
24
|
reported.clear();
|
|
21
25
|
}
|
|
@@ -31,6 +35,7 @@ function assertRequiredProps(component, props, keys, hints) {
|
|
|
31
35
|
}
|
|
32
36
|
export {
|
|
33
37
|
assertRequiredProps,
|
|
38
|
+
reportOnce,
|
|
34
39
|
resetValidatedProps,
|
|
35
40
|
useValidateProps
|
|
36
41
|
};
|
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
* `ReadingProgress`) — it does not reimplement them.
|
|
6
6
|
*
|
|
7
7
|
* The header/content/footer all align to the SAME grid column, so the article body reads as one
|
|
8
|
-
* consistent width whether or not the TOC rail is visible
|
|
9
|
-
*
|
|
8
|
+
* consistent width whether or not the TOC rail is visible. Below the 1200px breakpoint the rail
|
|
9
|
+
* is replaced, not dropped: a sticky "On this page" trigger opens the same `TableOfContents` in a
|
|
10
|
+
* `Popover` (docs/CONTENT-SPEC.md §7's originally-documented behavior, `useSizeClass() !==
|
|
11
|
+
* 'expanded'` — the same numeric threshold, resolved in JS instead of `@media`).
|
|
10
12
|
*
|
|
11
13
|
* @example
|
|
12
14
|
* import { ArticleLayout } from 'basalt-ui/content'
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"article-layout.d.ts","sourceRoot":"","sources":["../../src/content/article-layout.tsx"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"article-layout.d.ts","sourceRoot":"","sources":["../../src/content/article-layout.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AAMrD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AAK3C,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,4FAA4F;IAC5F,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAA;IACtB,2CAA2C;IAC3C,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAC9B,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,EAAE,SAAS,CAAA;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,iBAAiB,CAAA;IACjC,wFAAwF;IACxF,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAA;IACtB,0FAA0F;IAC1F,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAA;IAClC,QAAQ,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAA;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,gBAAgB,CAAA;IAChC,wFAAwF;IACxF,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,EAAE,IAAI,EAAE,SAAS,KAAK,SAAS,CAAA;IAC9E,wDAAwD;IACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,YAAY,CAAA;IAC/B;0EACsE;IACtE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAA;IACxB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAA;CAC/B,CAAA;AAiCD,wBAAgB,aAAa,CAAC,EAC5B,QAAQ,EACR,IAAI,EACJ,GAAU,EACV,eAAuB,EACvB,IAAI,EACJ,IAAI,EACJ,UAA8B,EAC9B,OAAmB,EACnB,MAAgB,EAChB,SAAS,EACT,KAAK,GACN,EAAE,kBAAkB,+BAyGpB"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useRef } from "react";
|
|
3
|
-
import { ScrollArea } from "@mantine/core";
|
|
2
|
+
import { useRef, useState } from "react";
|
|
3
|
+
import { Button, Popover, ScrollArea } from "@mantine/core";
|
|
4
|
+
import { useSizeClass } from "../shell/use-size-class.js";
|
|
4
5
|
import classes from "./article-layout.module.css";
|
|
5
6
|
import { formatArticleDate } from "./article-model.js";
|
|
6
7
|
import { Prose } from "./prose.js";
|
|
@@ -44,6 +45,13 @@ function ArticleLayout({
|
|
|
44
45
|
const articleRef = useRef(null);
|
|
45
46
|
const rootClass = [classes.root, !toc && classes.noToc, className].filter(Boolean).join(" ");
|
|
46
47
|
const hasMetaRow = meta?.date !== void 0 || meta?.readingTime !== void 0;
|
|
48
|
+
const showTocRail = useSizeClass() === "expanded";
|
|
49
|
+
const [tocOpen, setTocOpen] = useState(false);
|
|
50
|
+
const prevShowTocRailRef = useRef(showTocRail);
|
|
51
|
+
if (prevShowTocRailRef.current !== showTocRail) {
|
|
52
|
+
prevShowTocRailRef.current = showTocRail;
|
|
53
|
+
if (tocOpen) setTocOpen(false);
|
|
54
|
+
}
|
|
47
55
|
return /* @__PURE__ */ jsxs("div", { className: rootClass, ...style !== void 0 && { style }, children: [
|
|
48
56
|
readingProgress && /* @__PURE__ */ jsx(ReadingProgress, { target: articleRef }),
|
|
49
57
|
meta !== void 0 && /* @__PURE__ */ jsxs("header", { className: classes.header, children: [
|
|
@@ -59,7 +67,39 @@ function ArticleLayout({
|
|
|
59
67
|
] })
|
|
60
68
|
] }),
|
|
61
69
|
/* @__PURE__ */ jsx("div", { className: classes.content, ref: articleRef, children: /* @__PURE__ */ jsx(Prose, { density, children }) }),
|
|
62
|
-
toc && /* @__PURE__ */ jsx("div", { className: classes.tocRail, children: /* @__PURE__ */ jsx(ScrollArea.Autosize, { mah: "calc(100vh - 108px)", type: "hover", children: /* @__PURE__ */ jsx(TableOfContents, { containerRef: articleRef }) }) }),
|
|
70
|
+
toc && showTocRail && /* @__PURE__ */ jsx("div", { className: classes.tocRail, children: /* @__PURE__ */ jsx(ScrollArea.Autosize, { mah: "calc(100vh - 108px)", type: "hover", children: /* @__PURE__ */ jsx(TableOfContents, { containerRef: articleRef }) }) }),
|
|
71
|
+
toc && !showTocRail && // `.tocTrigger`'s `grid-row: 2` (article-layout.module.css) is EXPLICIT, matching
|
|
72
|
+
// `.content`'s own row — not left to CSS Grid's auto-placement, which used to land this
|
|
73
|
+
// in its own row below the content instead of at its top (both are `grid-column: 1`, and
|
|
74
|
+
// the auto-placement cursor moves past row 2 once `.content` claims it).
|
|
75
|
+
/* @__PURE__ */ jsxs(
|
|
76
|
+
Popover,
|
|
77
|
+
{
|
|
78
|
+
opened: tocOpen,
|
|
79
|
+
onChange: setTocOpen,
|
|
80
|
+
onDismiss: () => setTocOpen(false),
|
|
81
|
+
position: "bottom-end",
|
|
82
|
+
withinPortal: true,
|
|
83
|
+
shadow: "md",
|
|
84
|
+
radius: "sm",
|
|
85
|
+
trapFocus: true,
|
|
86
|
+
children: [
|
|
87
|
+
/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(
|
|
88
|
+
Button,
|
|
89
|
+
{
|
|
90
|
+
variant: "subtle",
|
|
91
|
+
color: "gray",
|
|
92
|
+
size: "compact-xs",
|
|
93
|
+
className: classes.tocTrigger,
|
|
94
|
+
classNames: { label: classes.tocTriggerLabel },
|
|
95
|
+
onClick: () => setTocOpen((current) => !current),
|
|
96
|
+
children: "On this page"
|
|
97
|
+
}
|
|
98
|
+
) }),
|
|
99
|
+
/* @__PURE__ */ jsx(Popover.Dropdown, { className: classes.tocDropdown, children: /* @__PURE__ */ jsx(ScrollArea.Autosize, { mah: "calc(100vh - 108px)", type: "hover", children: /* @__PURE__ */ jsx(TableOfContents, { containerRef: articleRef, onNavigate: () => setTocOpen(false) }) }) })
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
),
|
|
63
103
|
(prev !== void 0 || next !== void 0) && /* @__PURE__ */ jsxs("footer", { className: classes.footer, children: [
|
|
64
104
|
prev !== void 0 ? /* @__PURE__ */ jsx(NavCell, { target: prev, side: "prev", renderLink }) : /* @__PURE__ */ jsx("span", {}),
|
|
65
105
|
next !== void 0 ? /* @__PURE__ */ jsx(NavCell, { target: next, side: "next", renderLink }) : /* @__PURE__ */ jsx("span", {})
|
|
@@ -17,12 +17,19 @@
|
|
|
17
17
|
grid-template-columns: minmax(0, var(--vx-prose-measure));
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
/* The literal below MUST equal `BREAKPOINTS.article` (src/tokens/index.ts) — a `@media`
|
|
20
|
+
/* The literal below MUST equal `BREAKPOINTS.article - 0.1` (src/tokens/index.ts) — a `@media`
|
|
21
21
|
* condition is resolved before custom properties exist, so `max-width: var(--x)` is invalid CSS
|
|
22
|
-
* and a stylesheet with a responsive rule has no choice but to write the number. The
|
|
23
|
-
*
|
|
22
|
+
* and a stylesheet with a responsive rule has no choice but to write the number. The 0.1px offset
|
|
23
|
+
* is `tokens/size-classes.ts`' own `sizeClassMaxEm` convention (Mantine's own): the JS side
|
|
24
|
+
* (`article-layout.tsx`'s `useSizeClass() === 'expanded'`) reads a plain `min-width: 1200px`,
|
|
25
|
+
* inclusive AT 1200 — writing this query as a bare `max-width: 1200px` would ALSO be inclusive at
|
|
26
|
+
* exactly 1200px, so at that one width both conditions would fire at once: JS renders the rail,
|
|
27
|
+
* and this rule then hides it with `display: none`, leaving neither the rail nor the trigger
|
|
28
|
+
* visible. `1199.9px` makes the two conditions strict complements with no such gap. The token is
|
|
29
|
+
* the readable half; `article-layout.breakpoint.test.ts` asserts the two agree, the same
|
|
24
30
|
* "literal must match the token" idiom as `styles.floor.test.ts`. Change both or neither. */
|
|
25
|
-
|
|
31
|
+
/* theme-allow raw-media-query — deliberate literal pinned to BREAKPOINTS.article, outside shell/** */
|
|
32
|
+
@media (max-width: 1199.9px) {
|
|
26
33
|
.root {
|
|
27
34
|
grid-template-columns: minmax(0, var(--vx-prose-measure));
|
|
28
35
|
}
|
|
@@ -34,6 +41,7 @@
|
|
|
34
41
|
|
|
35
42
|
.header {
|
|
36
43
|
grid-column: 1;
|
|
44
|
+
grid-row: 1;
|
|
37
45
|
display: flex;
|
|
38
46
|
flex-direction: column;
|
|
39
47
|
gap: var(--vx-space-article-header-gap);
|
|
@@ -71,11 +79,13 @@
|
|
|
71
79
|
|
|
72
80
|
.content {
|
|
73
81
|
grid-column: 1;
|
|
82
|
+
grid-row: 2;
|
|
74
83
|
min-width: 0;
|
|
75
84
|
}
|
|
76
85
|
|
|
77
86
|
.tocRail {
|
|
78
87
|
grid-column: 2;
|
|
88
|
+
grid-row: 2;
|
|
79
89
|
position: sticky;
|
|
80
90
|
/* The rail sticks inside whatever scrolls it — `AppShell.Main` in a shell, the document without
|
|
81
91
|
* one — and NOTHING overhangs that box: the app header and `PageBar` row 2's band are both shell
|
|
@@ -87,8 +97,39 @@
|
|
|
87
97
|
align-self: start;
|
|
88
98
|
}
|
|
89
99
|
|
|
100
|
+
/* The rail's below-breakpoint replacement (docs/CONTENT-SPEC.md §7): a small sticky trigger that
|
|
101
|
+
* opens the SAME `TableOfContents` in a `Popover` instead of the rail vanishing. Rendered by JS
|
|
102
|
+
* (`useSizeClass() !== 'expanded'`), never both at once with `.tocRail` — no media query needed
|
|
103
|
+
* here, only the sticky/alignment behaviour for whenever it IS mounted. `grid-row: 2` is EXPLICIT,
|
|
104
|
+
* not left to auto-placement: `.content` also being `grid-column: 1` moves the auto-placement
|
|
105
|
+
* cursor's row on past row 2 by the time this item (also column 1) is placed, landing it in its
|
|
106
|
+
* own row BELOW the content instead of at its top — the whole point of this trigger. */
|
|
107
|
+
.tocTrigger {
|
|
108
|
+
grid-column: 1;
|
|
109
|
+
grid-row: 2;
|
|
110
|
+
justify-self: end;
|
|
111
|
+
align-self: start;
|
|
112
|
+
position: sticky;
|
|
113
|
+
top: var(--vx-space-sticky-header-clearance);
|
|
114
|
+
z-index: 1;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.tocTriggerLabel {
|
|
118
|
+
font-family: var(--basalt-font-mono);
|
|
119
|
+
font-size: var(--vx-text-micro);
|
|
120
|
+
letter-spacing: 0.06em;
|
|
121
|
+
text-transform: uppercase;
|
|
122
|
+
color: var(--vx-faint);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
.tocDropdown {
|
|
126
|
+
min-width: 220px;
|
|
127
|
+
max-width: min(320px, calc(100vw - 32px));
|
|
128
|
+
}
|
|
129
|
+
|
|
90
130
|
.footer {
|
|
91
131
|
grid-column: 1;
|
|
132
|
+
grid-row: 3;
|
|
92
133
|
display: grid;
|
|
93
134
|
grid-template-columns: 1fr 1fr;
|
|
94
135
|
gap: var(--vx-space-article-footer-gap);
|
|
@@ -11,6 +11,9 @@ declare const classes: {
|
|
|
11
11
|
readonly metaRow: string
|
|
12
12
|
readonly content: string
|
|
13
13
|
readonly tocRail: string
|
|
14
|
+
readonly tocTrigger: string
|
|
15
|
+
readonly tocTriggerLabel: string
|
|
16
|
+
readonly tocDropdown: string
|
|
14
17
|
readonly footer: string
|
|
15
18
|
readonly navCell: string
|
|
16
19
|
readonly navCellNext: string
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../../src/content/code-block.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"code-block.d.ts","sourceRoot":"","sources":["../../src/content/code-block.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAO1C,MAAM,MAAM,cAAc,GAAG;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAA;IACvB,yDAAyD;IACzD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAA;CAC/B,CAAA;AAED,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAQ,EACR,KAAK,EACL,QAAe,EACf,SAAS,EACT,KAAK,GACN,EAAE,cAAc,+BAuFhB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect, useState } from "react";
|
|
2
|
+
import { useEffect, useRef, useState } from "react";
|
|
3
|
+
import { useIsomorphicLayoutEffect } from "../common/isomorphic-layout-effect.js";
|
|
3
4
|
import classes from "./code-block.module.css";
|
|
4
5
|
import { CopyAction } from "./copy-action.js";
|
|
5
6
|
import { highlightCode } from "./highlighter.js";
|
|
@@ -12,6 +13,10 @@ function CodeBlock({
|
|
|
12
13
|
style
|
|
13
14
|
}) {
|
|
14
15
|
const [html, setHtml] = useState(null);
|
|
16
|
+
const bodyRef = useRef(null);
|
|
17
|
+
const setBodyRef = (node) => {
|
|
18
|
+
bodyRef.current = node;
|
|
19
|
+
};
|
|
15
20
|
useEffect(() => {
|
|
16
21
|
if (language === void 0) return;
|
|
17
22
|
let cancelled = false;
|
|
@@ -23,6 +28,23 @@ function CodeBlock({
|
|
|
23
28
|
cancelled = true;
|
|
24
29
|
};
|
|
25
30
|
}, [code, language]);
|
|
31
|
+
const [showOverflowFade, setShowOverflowFade] = useState(false);
|
|
32
|
+
useIsomorphicLayoutEffect(() => {
|
|
33
|
+
const body = bodyRef.current;
|
|
34
|
+
if (!body) return;
|
|
35
|
+
const update = () => {
|
|
36
|
+
const atEnd = body.scrollLeft + body.clientWidth >= body.scrollWidth - 1;
|
|
37
|
+
setShowOverflowFade(body.scrollWidth > body.clientWidth && !atEnd);
|
|
38
|
+
};
|
|
39
|
+
update();
|
|
40
|
+
body.addEventListener("scroll", update, { passive: true });
|
|
41
|
+
const observer = new ResizeObserver(update);
|
|
42
|
+
observer.observe(body);
|
|
43
|
+
return () => {
|
|
44
|
+
body.removeEventListener("scroll", update);
|
|
45
|
+
observer.disconnect();
|
|
46
|
+
};
|
|
47
|
+
}, [html, code]);
|
|
26
48
|
const containerClass = [classes.container, className].filter(Boolean).join(" ");
|
|
27
49
|
return /* @__PURE__ */ jsxs("div", { className: containerClass, ...style !== void 0 && { style }, children: [
|
|
28
50
|
title !== void 0 && /* @__PURE__ */ jsxs("div", { className: classes.header, children: [
|
|
@@ -32,7 +54,23 @@ function CodeBlock({
|
|
|
32
54
|
showCopy && /* @__PURE__ */ jsx(CopyAction, { value: code, ariaLabel: "Copy code" })
|
|
33
55
|
] })
|
|
34
56
|
] }),
|
|
35
|
-
html !== null ? /* @__PURE__ */ jsx(
|
|
57
|
+
html !== null ? /* @__PURE__ */ jsx(
|
|
58
|
+
"div",
|
|
59
|
+
{
|
|
60
|
+
ref: setBodyRef,
|
|
61
|
+
className: classes.body,
|
|
62
|
+
...showOverflowFade && { "data-code-overflow": true },
|
|
63
|
+
dangerouslySetInnerHTML: { __html: html }
|
|
64
|
+
}
|
|
65
|
+
) : /* @__PURE__ */ jsx(
|
|
66
|
+
"pre",
|
|
67
|
+
{
|
|
68
|
+
ref: setBodyRef,
|
|
69
|
+
className: classes.body,
|
|
70
|
+
...showOverflowFade && { "data-code-overflow": true },
|
|
71
|
+
children: /* @__PURE__ */ jsx("code", { children: code })
|
|
72
|
+
}
|
|
73
|
+
),
|
|
36
74
|
title === void 0 && showCopy && /* @__PURE__ */ jsx("div", { className: classes.floatingCopy, children: /* @__PURE__ */ jsx(CopyAction, { value: code, ariaLabel: "Copy code" }) })
|
|
37
75
|
] });
|
|
38
76
|
}
|
|
@@ -56,6 +56,27 @@
|
|
|
56
56
|
overflow-x: auto;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
/* Trailing-edge overflow fade (docs/MATURATION-LEDGER.md) — `code-block.tsx` toggles this
|
|
60
|
+
* attribute from a scroll/resize measurement (`scrollWidth > clientWidth`, not yet at the end), so
|
|
61
|
+
* it never decorates a block that already fits and never lingers once scrolled to the end. The mask
|
|
62
|
+
* fades to TRANSPARENT, not to a solid color — what shows through is `.container`'s own translucent
|
|
63
|
+
* background, already identical to what borders the block everywhere else, so the fade reads as a
|
|
64
|
+
* soft edge rather than a hard cut. Reuses the content inset token rather than a new literal; LTR
|
|
65
|
+
* only, matching the rest of this file (no `dir` handling exists here to fade the other edge from).
|
|
66
|
+
*/
|
|
67
|
+
.body[data-code-overflow] {
|
|
68
|
+
mask-image: linear-gradient(
|
|
69
|
+
to right,
|
|
70
|
+
black calc(100% - var(--vx-space-code-block-content-inset-x) * 2),
|
|
71
|
+
transparent 100%
|
|
72
|
+
);
|
|
73
|
+
-webkit-mask-image: linear-gradient(
|
|
74
|
+
to right,
|
|
75
|
+
black calc(100% - var(--vx-space-code-block-content-inset-x) * 2),
|
|
76
|
+
transparent 100%
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
59
80
|
.body :global(pre.shiki) {
|
|
60
81
|
margin: 0;
|
|
61
82
|
padding: 0;
|
|
@@ -77,11 +98,20 @@ html[data-mantine-color-scheme='light'] .body :global(.shiki span) {
|
|
|
77
98
|
position: absolute;
|
|
78
99
|
top: var(--vx-space-code-block-floating-copy-offset);
|
|
79
100
|
right: var(--vx-space-code-block-floating-copy-offset);
|
|
80
|
-
opacity: 0;
|
|
81
101
|
transition: opacity 120ms ease;
|
|
82
102
|
}
|
|
83
103
|
|
|
84
|
-
|
|
104
|
+
/* Hidden-until-hover only where hover exists (pointer tier, docs/DESIGN-CORE.md § Layout). */
|
|
105
|
+
@media (hover: hover) and (pointer: fine) {
|
|
106
|
+
.floatingCopy {
|
|
107
|
+
opacity: 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.container:hover .floatingCopy {
|
|
111
|
+
opacity: 1;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
85
115
|
.container:focus-within .floatingCopy {
|
|
86
116
|
opacity: 1;
|
|
87
117
|
}
|
|
@@ -149,17 +149,22 @@
|
|
|
149
149
|
display: inline-flex;
|
|
150
150
|
vertical-align: middle;
|
|
151
151
|
margin-left: var(--vx-space-prose-heading-anchor-gap);
|
|
152
|
-
opacity: 0;
|
|
153
152
|
transition: opacity 120ms ease;
|
|
154
153
|
}
|
|
155
154
|
|
|
156
|
-
|
|
157
|
-
.
|
|
158
|
-
|
|
159
|
-
.root
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
155
|
+
/* Hidden-until-hover only where hover exists (pointer tier, docs/DESIGN-CORE.md § Layout,
|
|
156
|
+
elevation, shapes); touch shows it. Focus always reveals (the rule below outranks the hidden one). */
|
|
157
|
+
@media (hover: hover) and (pointer: fine) {
|
|
158
|
+
.root :is(h1, h2, h3, h4, h5, h6) .headingAnchor {
|
|
159
|
+
opacity: 0;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.root :is(h1, h2, h3, h4, h5, h6):hover .headingAnchor {
|
|
163
|
+
opacity: 1;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.root :is(h1, h2, h3, h4, h5, h6) .headingAnchor:focus-within {
|
|
163
168
|
opacity: 1;
|
|
164
169
|
}
|
|
165
170
|
|
|
@@ -71,8 +71,6 @@ export type GlobalAction = {
|
|
|
71
71
|
/** @default 'bar' for the first two, `'more'` for the rest */
|
|
72
72
|
mobile?: 'bar' | 'more' | 'hidden';
|
|
73
73
|
};
|
|
74
|
-
/** Secondaries rendered inline on desktop; the rest fold into `More` (`docs/CONTROLS-SPEC.md` §2.1). */
|
|
75
|
-
export declare const DESKTOP_SECONDARY_MAX = 3;
|
|
76
74
|
/** `GlobalAction`s without an explicit `mobile` that still land on the mobile bar. */
|
|
77
75
|
export declare const MOBILE_GLOBAL_BAR_MAX = 2;
|
|
78
76
|
/**
|
|
@@ -100,6 +98,13 @@ export declare function barActionMobile(action: BarAction, isPrimary: boolean):
|
|
|
100
98
|
export declare function globalActionMobile(action: GlobalAction, index: number): 'bar' | 'more' | 'hidden';
|
|
101
99
|
/** A `GlobalAction` reaching a `BarAction` slot — the kebab renders one row shape, not two. */
|
|
102
100
|
export declare function globalActionAsBarAction(action: GlobalAction): BarActionCustom;
|
|
101
|
+
/**
|
|
102
|
+
* The DOM contract between `PageBar` row 1 and {@link useMeasuredFold} — module-internal, not part
|
|
103
|
+
* of any barrel. `PAGE_BAR_END_ATTR` marks the elastic row the fold measures; `BAR_KEY_ATTR` tags
|
|
104
|
+
* each rendered action with its `key` so a measured box maps back to its action.
|
|
105
|
+
*/
|
|
106
|
+
export declare const PAGE_BAR_END_ATTR = "data-basalt-page-bar-end";
|
|
107
|
+
export declare const BAR_KEY_ATTR = "data-bar-key";
|
|
103
108
|
export type OverflowMenuProps = BasaltProps & {
|
|
104
109
|
actions: readonly BarAction[];
|
|
105
110
|
/**
|
|
@@ -149,12 +154,30 @@ type BarActionRowProps = ActionGroupProps & {
|
|
|
149
154
|
*/
|
|
150
155
|
syncNode?: ReactNode;
|
|
151
156
|
};
|
|
157
|
+
type FoldStep = 'icon' | 'overflow';
|
|
158
|
+
/**
|
|
159
|
+
* The measured fold as a pure decision. `room` is the row's available width, `fixed` everything in it
|
|
160
|
+
* that never folds (primary, sync, joined runs, custom nodes), each foldable `item` its labelled and
|
|
161
|
+
* icon-only width (`icon` absent when it ships no icon). Folds from the LAST item back: first to
|
|
162
|
+
* icon-only where an icon exists, then into `More`. Items that stay whole are absent from the result.
|
|
163
|
+
*/
|
|
164
|
+
export declare function planBarFold(input: {
|
|
165
|
+
room: number;
|
|
166
|
+
fixed: number;
|
|
167
|
+
gap: number;
|
|
168
|
+
hasMenus: boolean;
|
|
169
|
+
items: readonly {
|
|
170
|
+
key: string;
|
|
171
|
+
full: number;
|
|
172
|
+
icon: number | undefined;
|
|
173
|
+
}[];
|
|
174
|
+
}): Record<string, FoldStep>;
|
|
152
175
|
export declare function BarActionRow({ primary, secondary, host, viewport, mobileOnly, syncNode, className, style, }: BarActionRowProps): ReactNode;
|
|
153
176
|
/**
|
|
154
177
|
* A home's `actions` slot, projected for both viewports.
|
|
155
178
|
*
|
|
156
|
-
* Desktop: `primary` as a `filled` button ·
|
|
157
|
-
*
|
|
179
|
+
* Desktop: `primary` as a `filled` button · secondaries as `default` buttons, folded by the row's
|
|
180
|
+
* measured width (icon-only, then into `More`) · every `kind: 'menu'` in that same `More` menu.
|
|
158
181
|
* Mobile: `primary` as an icon button when it ships an icon and a compact labelled button when it
|
|
159
182
|
* does not · one kebab holding every `mobile: 'more'` action · `mobile: 'hidden'` drops the action
|
|
160
183
|
* entirely.
|
|
@@ -192,8 +215,8 @@ export type SlotActions = BarAction[] | ReactNode;
|
|
|
192
215
|
export declare function isBarActionList(actions: SlotActions): actions is BarAction[];
|
|
193
216
|
/**
|
|
194
217
|
* Renders a {@link SlotActions} slot: the typed form goes through the SAME projection `PageBar` and
|
|
195
|
-
* `ActionGroup` use — inline
|
|
196
|
-
*
|
|
218
|
+
* `ActionGroup` use — inline, `kind: 'menu'` folded into `More`, and a mobile kebab below `sm` — and
|
|
219
|
+
* the node form is returned untouched.
|
|
197
220
|
*
|
|
198
221
|
* Every entry lands in `secondary`: a `BarAction[]` carries no primary marker, and law C6's "exactly
|
|
199
222
|
* one primary" is the page bar's rule, enforced by `ActionGroupProps.primary` being singular. A home
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/controls/actions.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"actions.d.ts","sourceRoot":"","sources":["../../src/controls/actions.tsx"],"names":[],"mappings":"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"}
|