@blueprint-chart/lib 0.1.15 → 0.1.18
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/dist/charts/axis/axis-service.d.ts +5 -0
- package/dist/charts/clip-path-helper.d.ts +7 -0
- package/dist/charts/contrast.d.ts +4 -1
- package/dist/charts/plugins/proximity.d.ts +8 -0
- package/dist/charts/scale-helpers.d.ts +2 -1
- package/dist/charts/types/pie/pie.d.ts +8 -0
- package/dist/charts/types.d.ts +0 -1
- package/dist/dsl/types.d.ts +3 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3576 -3155
- package/dist/lib/lib.iife.js +4 -3
- package/dist/recommendations/recommend.d.ts +9 -0
- package/dist/render/ast-to-definition.d.ts +2 -0
- package/dist/render/cross-type-fade.d.ts +9 -0
- package/dist/render/resolve-scene.d.ts +2 -0
- package/dist/render/types.d.ts +7 -0
- package/dist/runtime/chart-css.d.ts +1 -1
- package/dist/runtime/runtime.d.ts +1 -0
- package/dist/runtime/scenes.d.ts +1 -1
- package/dist/transitions/feature-join.d.ts +13 -0
- package/dist/transitions/index.d.ts +7 -0
- package/dist/transitions/role-matcher.d.ts +42 -0
- package/dist/transitions/scene-transition.d.ts +78 -0
- package/dist/transitions/snapshot.d.ts +16 -0
- package/dist/transitions/types.d.ts +44 -0
- package/package.json +1 -1
- package/src/charts/chart.scss +26 -1
- package/dist/dsl/lexer.d.ts +0 -8
package/dist/lib/lib.iife.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var BlueprintChart=(function(l){"use strict";const
|
|
1
|
+
var BlueprintChart=(function(l){"use strict";const v=`
|
|
2
2
|
/* Blueprint Chart — Runtime Embed Styles
|
|
3
3
|
CSS custom properties with baked-in defaults for standalone iframe usage. */
|
|
4
4
|
|
|
@@ -89,6 +89,7 @@ var BlueprintChart=(function(l){"use strict";const p=`
|
|
|
89
89
|
font-weight: 600;
|
|
90
90
|
display: inline-flex;
|
|
91
91
|
align-items: center;
|
|
92
|
+
text-decoration: none;
|
|
92
93
|
}
|
|
93
94
|
|
|
94
95
|
.bc-frame-source-link {
|
|
@@ -182,5 +183,5 @@ body {
|
|
|
182
183
|
margin: 0;
|
|
183
184
|
overflow: hidden;
|
|
184
185
|
}
|
|
185
|
-
|
|
186
|
-
`)}function
|
|
186
|
+
`,p=new Map;let f=null;function x(){f||(f=t=>{for(const[e,r]of p)if(t.source===e.contentWindow){r(t);return}},window.addEventListener("message",f))}function b(){x(),document.querySelectorAll('script[type="application/blueprint-chart"]').forEach(y)}function y(t){var c,n;const e=(c=t.textContent)==null?void 0:c.trim();if(!e)return;const r=document.createElement("iframe");r.className="blueprint-chart-iframe",r.style.cssText="border: none; width: 100%; display: block;",r.setAttribute("sandbox","allow-scripts"),r.setAttribute("title","Blueprint Chart"),(n=t.parentNode)==null||n.insertBefore(r,t),r.srcdoc=z(e);const o=a=>{var i;((i=a.data)==null?void 0:i.type)==="blueprint-chart-resize"&&(r.style.height=`${a.data.height}px`)};p.set(r,o)}function z(t){const e=C(t);return["<!DOCTYPE html>","<html><head>",`<style>${v}</style>`,"</head><body>",`<div id="chart" class="blueprint-chart-container blueprint-chart-placeholder">${e}</div>`,"<script>","function notifySize() {"," var h = document.documentElement.scrollHeight;",' parent.postMessage({ type: "blueprint-chart-resize", height: h }, "*");',"}","notifySize();","new ResizeObserver(notifySize).observe(document.body);","<\/script>","</body></html>"].join(`
|
|
187
|
+
`)}function C(t){return t.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function u(t,e,r){let o=0,c=!1;const n=document.createElement("nav");n.className="blueprint-chart-scenes";const a=document.createElement("button");a.className="blueprint-chart-scenes-prev",a.textContent="Previous";const i=document.createElement("button");i.className="blueprint-chart-scenes-next",i.textContent="Next";const s=document.createElement("span");s.className="blueprint-chart-scenes-counter",n.appendChild(a),n.appendChild(s),n.appendChild(i),e.length>0&&t.appendChild(n);function g(){if(e.length===0){s.textContent="";return}s.textContent=`${o+1} / ${e.length}`}function d(h){if(c||e.length===0||!Number.isFinite(h))return;const m=(Math.floor(h)%e.length+e.length)%e.length;o=m,g(),r(e[m],m)}return a.addEventListener("click",()=>d(o-1)),i.addEventListener("click",()=>d(o+1)),g(),{get currentScene(){return o},get totalScenes(){return e.length},next(){d(o+1)},previous(){d(o-1)},goTo:d,destroy(){c||(c=!0,n.remove())}}}const k=u;return document.readyState==="loading"?document.addEventListener("DOMContentLoaded",b):b(),l.createSceneController=u,l.createStepController=k,l.initBlueprint=b,Object.defineProperty(l,Symbol.toStringTag,{value:"Module"}),l})({});
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ColumnType = 'string' | 'number' | 'date';
|
|
2
|
+
export type RecommendationFitness = 'best' | 'good' | 'alternative';
|
|
3
|
+
export interface ChartRecommendation {
|
|
4
|
+
chartType: string;
|
|
5
|
+
label: string;
|
|
6
|
+
fitness: RecommendationFitness;
|
|
7
|
+
reason: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function recommendCharts(columnTypes: ColumnType[], rowCount: number): ChartRecommendation[];
|
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import { ChartNode } from '../dsl/types';
|
|
2
2
|
import { ChartDefinition } from './types';
|
|
3
|
+
/** @internal — exposed for tests that need to reset the warn-once cache. */
|
|
4
|
+
export declare function __resetTransformWarnings(): void;
|
|
3
5
|
export declare function astToDefinition(ast: ChartNode): ChartDefinition;
|
|
@@ -1,3 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cancel and remove any in-flight fade-out overlays inside `container`.
|
|
3
|
+
*
|
|
4
|
+
* Safe to call at any time — when no overlay is present this is a no-op.
|
|
5
|
+
* Use as an explicit cleanup hook (e.g. when tearing down a chart or before
|
|
6
|
+
* starting a brand-new fade) to prevent stacked overlays and zombie WAAPI
|
|
7
|
+
* animations from accumulating on rapid re-triggers.
|
|
8
|
+
*/
|
|
9
|
+
export declare function cancelInflightFade(container: HTMLElement): void;
|
|
1
10
|
export declare function snapshotIfTypeChanged(container: HTMLElement, newChartType: string, transition: boolean): HTMLElement | null;
|
|
2
11
|
export declare function commitCrossTypeFade(container: HTMLElement, newChartType: string, overlay: HTMLElement | null): void;
|
|
3
12
|
export declare function clearCrossTypeMarker(container: HTMLElement): void;
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
import { ChartDefinition, ResolvedChartState } from './types';
|
|
2
|
+
/** @internal — exposed for tests that need to reset the warn-once cache. */
|
|
3
|
+
export declare function __resetTransformWarnings(): void;
|
|
2
4
|
export declare function resolveScene(def: ChartDefinition, sceneIndex: number | undefined): ResolvedChartState;
|
package/dist/render/types.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { SortDirection, SortMode } from '../enums';
|
|
2
2
|
import { ChartData, ChartTypeOptions, ColorizeConfig, HighlightConfig, AreaFillConfig, AnnotationConfig, SeriesOverride, FrameOptions } from '../charts/types';
|
|
3
3
|
import { PropertyNode, SceneNode } from '../dsl/types';
|
|
4
|
+
import { TransitionMode } from '../transitions/types';
|
|
4
5
|
export interface ChartDefinition {
|
|
5
6
|
chartType: string;
|
|
6
7
|
data: ChartData;
|
|
@@ -20,6 +21,12 @@ export interface ChartDefinition {
|
|
|
20
21
|
export interface RenderOptions {
|
|
21
22
|
sceneIndex?: number;
|
|
22
23
|
transition?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Transition mode. Defaults to `'transform'` when omitted. Only the
|
|
26
|
+
* `transform` mode runs in v1; other values warn-once at the orchestrator
|
|
27
|
+
* and fall back to snap. See `transitions/index.ts`.
|
|
28
|
+
*/
|
|
29
|
+
transitionMode?: TransitionMode;
|
|
23
30
|
thumbnail?: boolean;
|
|
24
31
|
stripColors?: boolean;
|
|
25
32
|
ignoreLayout?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const CHART_CSS = "\n/* Blueprint Chart \u2014 Runtime Embed Styles\n CSS custom properties with baked-in defaults for standalone iframe usage. */\n\n.bc-frame {\n --bc-frame-font-family: system-ui, -apple-system, sans-serif;\n --bc-frame-padding: 0;\n --bc-text-color: #333;\n font-family: var(--bc-frame-font-family);\n}\n\n.bc-frame-header {\n padding: var(--bc-frame-padding) var(--bc-frame-padding) 0;\n background: var(--bc-frame-header-bg, transparent);\n border-bottom: var(--bc-frame-header-border-bottom, none);\n margin-bottom: var(--bc-frame-header-margin-bottom, 0);\n}\n\n.bc-frame-body {\n padding: 0 var(--bc-frame-padding);\n}\n\n.bc-frame-title {\n --bc-frame-title-color: var(--bc-text-color, #333);\n --bc-frame-title-font-size: 1.25rem;\n color: var(--bc-frame-title-color);\n font-size: var(--bc-frame-title-font-size);\n font-weight: bold;\n margin: 0;\n}\n\n.bc-frame-description {\n --bc-frame-description-color: var(--bc-text-color, #555);\n --bc-frame-description-font-size: 0.875rem;\n color: var(--bc-frame-description-color);\n font-size: var(--bc-frame-description-font-size);\n margin: 0.25rem 0 0;\n}\n\n.bc-frame-footer {\n margin-top: 0.5rem;\n gap: 0.25rem 1rem;\n padding: var(--bc-frame-footer-padding-top, 0) var(--bc-frame-padding) var(--bc-frame-padding);\n background: var(--bc-frame-footer-bg, transparent);\n border-top: var(--bc-frame-footer-border-top, none);\n}\n\n.bc-frame-footer-left {\n display: flex;\n align-items: baseline;\n flex-wrap: wrap;\n gap: 0.25rem 0.75rem;\n}\n\n.bc-frame-footer-left > :not(:first-child)::before {\n content: \"\\00B7\";\n margin-right: 0.5rem;\n color: var(--bc-text-color, #888);\n}\n\n.bc-frame-footer-right {\n display: flex;\n align-items: center;\n}\n\n.bc-frame-note {\n --bc-frame-note-color: var(--bc-text-color, #888);\n --bc-frame-note-font-size: 0.75rem;\n font-style: italic;\n color: var(--bc-frame-note-color);\n font-size: var(--bc-frame-note-font-size);\n margin: 0;\n padding: 0 var(--bc-frame-padding);\n}\n\n.bc-frame-byline,\n.bc-frame-source {\n --bc-frame-meta-color: var(--bc-text-color, #888);\n --bc-frame-meta-font-size: 0.75rem;\n color: var(--bc-frame-meta-color);\n font-size: var(--bc-frame-meta-font-size);\n}\n\n.bc-frame-credit {\n --bc-frame-credit-color: var(--bc-text-color, #666);\n --bc-frame-credit-font-size: 0.75rem;\n color: var(--bc-frame-credit-color);\n font-size: var(--bc-frame-credit-font-size);\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n}\n\n.bc-frame-source-link {\n color: inherit;\n text-decoration: underline;\n}\n\n.bc-axis .domain {\n stroke: var(--bc-axis-color, #333);\n}\n\n.bc-axis .tick text {\n fill: var(--bc-axis-color, #333);\n font-size: 10px;\n}\n\n.bc-axis .tick line {\n stroke: var(--bc-axis-color, #333);\n}\n\n.bc-grid-line {\n stroke: var(--bc-grid-color, #e0e0e0);\n stroke-width: 1;\n}\n\n.bc-zero-baseline {\n stroke: #666;\n stroke-width: 1;\n}\n\n.bc-bar {\n /* fill is set via D3 .attr() from data-bound colors \u2014 do not override */\n}\n\n.bc-line {\n fill: none;\n stroke-width: 2;\n}\n\n.bc-value-label {\n font-size: 11px;\n /* fill is set via D3 .attr() \u2014 do not override */\n}\n\n.bc-direct-label {\n font-size: 12px;\n font-weight: 600;\n}\n\n.bc-tooltip {\n position: absolute;\n pointer-events: none;\n background: var(--bc-tooltip-bg, #fff);\n color: var(--bc-tooltip-color, #212529);\n border: 1px solid var(--bc-tooltip-border-color, #dee2e6);\n border-radius: 4px;\n padding: 6px 10px;\n font-size: 13px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n z-index: 9999;\n display: none;\n}\n\n.bc-crosshair {\n stroke: #999;\n stroke-width: 1;\n pointer-events: none;\n}\n\n.bc-arc-label-line {\n fill: none;\n stroke: #999;\n stroke-width: 1;\n}\n\n.bc-theme-blueprint-framed {\n --bc-frame-header-border-bottom: 1px solid #e0e0e0;\n --bc-frame-header-margin-bottom: 0.5rem;\n --bc-frame-footer-bg: #f8f8f8;\n --bc-frame-footer-border-top: 1px solid #e0e0e0;\n --bc-frame-footer-padding-top: 0.625rem;\n}\n\n.blueprint-chart-error {\n color: red;\n padding: 1em;\n border: 1px solid red;\n}\n\nbody {\n margin: 0;\n overflow: hidden;\n}\n";
|
|
1
|
+
export declare const CHART_CSS = "\n/* Blueprint Chart \u2014 Runtime Embed Styles\n CSS custom properties with baked-in defaults for standalone iframe usage. */\n\n.bc-frame {\n --bc-frame-font-family: system-ui, -apple-system, sans-serif;\n --bc-frame-padding: 0;\n --bc-text-color: #333;\n font-family: var(--bc-frame-font-family);\n}\n\n.bc-frame-header {\n padding: var(--bc-frame-padding) var(--bc-frame-padding) 0;\n background: var(--bc-frame-header-bg, transparent);\n border-bottom: var(--bc-frame-header-border-bottom, none);\n margin-bottom: var(--bc-frame-header-margin-bottom, 0);\n}\n\n.bc-frame-body {\n padding: 0 var(--bc-frame-padding);\n}\n\n.bc-frame-title {\n --bc-frame-title-color: var(--bc-text-color, #333);\n --bc-frame-title-font-size: 1.25rem;\n color: var(--bc-frame-title-color);\n font-size: var(--bc-frame-title-font-size);\n font-weight: bold;\n margin: 0;\n}\n\n.bc-frame-description {\n --bc-frame-description-color: var(--bc-text-color, #555);\n --bc-frame-description-font-size: 0.875rem;\n color: var(--bc-frame-description-color);\n font-size: var(--bc-frame-description-font-size);\n margin: 0.25rem 0 0;\n}\n\n.bc-frame-footer {\n margin-top: 0.5rem;\n gap: 0.25rem 1rem;\n padding: var(--bc-frame-footer-padding-top, 0) var(--bc-frame-padding) var(--bc-frame-padding);\n background: var(--bc-frame-footer-bg, transparent);\n border-top: var(--bc-frame-footer-border-top, none);\n}\n\n.bc-frame-footer-left {\n display: flex;\n align-items: baseline;\n flex-wrap: wrap;\n gap: 0.25rem 0.75rem;\n}\n\n.bc-frame-footer-left > :not(:first-child)::before {\n content: \"\\00B7\";\n margin-right: 0.5rem;\n color: var(--bc-text-color, #888);\n}\n\n.bc-frame-footer-right {\n display: flex;\n align-items: center;\n}\n\n.bc-frame-note {\n --bc-frame-note-color: var(--bc-text-color, #888);\n --bc-frame-note-font-size: 0.75rem;\n font-style: italic;\n color: var(--bc-frame-note-color);\n font-size: var(--bc-frame-note-font-size);\n margin: 0;\n padding: 0 var(--bc-frame-padding);\n}\n\n.bc-frame-byline,\n.bc-frame-source {\n --bc-frame-meta-color: var(--bc-text-color, #888);\n --bc-frame-meta-font-size: 0.75rem;\n color: var(--bc-frame-meta-color);\n font-size: var(--bc-frame-meta-font-size);\n}\n\n.bc-frame-credit {\n --bc-frame-credit-color: var(--bc-text-color, #666);\n --bc-frame-credit-font-size: 0.75rem;\n color: var(--bc-frame-credit-color);\n font-size: var(--bc-frame-credit-font-size);\n font-weight: 600;\n display: inline-flex;\n align-items: center;\n text-decoration: none;\n}\n\n.bc-frame-source-link {\n color: inherit;\n text-decoration: underline;\n}\n\n.bc-axis .domain {\n stroke: var(--bc-axis-color, #333);\n}\n\n.bc-axis .tick text {\n fill: var(--bc-axis-color, #333);\n font-size: 10px;\n}\n\n.bc-axis .tick line {\n stroke: var(--bc-axis-color, #333);\n}\n\n.bc-grid-line {\n stroke: var(--bc-grid-color, #e0e0e0);\n stroke-width: 1;\n}\n\n.bc-zero-baseline {\n stroke: #666;\n stroke-width: 1;\n}\n\n.bc-bar {\n /* fill is set via D3 .attr() from data-bound colors \u2014 do not override */\n}\n\n.bc-line {\n fill: none;\n stroke-width: 2;\n}\n\n.bc-value-label {\n font-size: 11px;\n /* fill is set via D3 .attr() \u2014 do not override */\n}\n\n.bc-direct-label {\n font-size: 12px;\n font-weight: 600;\n}\n\n.bc-tooltip {\n position: absolute;\n pointer-events: none;\n background: var(--bc-tooltip-bg, #fff);\n color: var(--bc-tooltip-color, #212529);\n border: 1px solid var(--bc-tooltip-border-color, #dee2e6);\n border-radius: 4px;\n padding: 6px 10px;\n font-size: 13px;\n box-shadow: 0 2px 8px rgba(0,0,0,0.12);\n z-index: 9999;\n display: none;\n}\n\n.bc-crosshair {\n stroke: #999;\n stroke-width: 1;\n pointer-events: none;\n}\n\n.bc-arc-label-line {\n fill: none;\n stroke: #999;\n stroke-width: 1;\n}\n\n.bc-theme-blueprint-framed {\n --bc-frame-header-border-bottom: 1px solid #e0e0e0;\n --bc-frame-header-margin-bottom: 0.5rem;\n --bc-frame-footer-bg: #f8f8f8;\n --bc-frame-footer-border-top: 1px solid #e0e0e0;\n --bc-frame-footer-padding-top: 0.625rem;\n}\n\n.blueprint-chart-error {\n color: red;\n padding: 1em;\n border: 1px solid red;\n}\n\nbody {\n margin: 0;\n overflow: hidden;\n}\n";
|
package/dist/runtime/scenes.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export interface SceneController {
|
|
|
12
12
|
goTo(index: number): void;
|
|
13
13
|
destroy(): void;
|
|
14
14
|
}
|
|
15
|
-
/** @deprecated Use
|
|
15
|
+
/** @deprecated Use StepController instead */
|
|
16
16
|
export type StepController = SceneController;
|
|
17
17
|
export declare function createSceneController(container: HTMLElement, scenes: SceneDefinition[], onSceneChange: (scene: SceneDefinition, index: number) => void): SceneController;
|
|
18
18
|
/** @deprecated Use createSceneController instead */
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SceneTransition } from './scene-transition';
|
|
2
|
+
import { FeatureJoinConfig } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Idempotent keyed data-join for a single visual feature.
|
|
5
|
+
*
|
|
6
|
+
* Behaviour by orchestrator state:
|
|
7
|
+
* - `idle` / `animating` — plain d3 data-join; attrs applied directly.
|
|
8
|
+
* A featureJoin during `animating` cannot piggyback on the in-flight
|
|
9
|
+
* transition (it has no place to register), so we snap. Mid-tween
|
|
10
|
+
* featureJoin calls should be rare in normal flow; tests cover them.
|
|
11
|
+
* - `committing` — buffer enter / update / exit for the next commit.
|
|
12
|
+
*/
|
|
13
|
+
export declare function featureJoin<D>(orchestrator: SceneTransition, cfg: FeatureJoinConfig<D>): void;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SceneTransition, getSceneTransition } from './scene-transition';
|
|
2
|
+
export { BC_TRANSITION_NAME } from './types';
|
|
3
|
+
export type { CommitOptions } from './scene-transition';
|
|
4
|
+
export { featureJoin } from './feature-join';
|
|
5
|
+
export { roleScan, tagsCompatible, shouldEscalateToFade, ROLE_MATCH_THRESHOLD } from './role-matcher';
|
|
6
|
+
export { snapshotLiveAttrs } from './snapshot';
|
|
7
|
+
export type { TransitionMode, SceneTransitionState, FeatureRole, FeatureJoinConfig, AttrMap, AttrValue, } from './types';
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { FeatureRole } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Minimum fraction of new features that must match a prior role-tagged
|
|
4
|
+
* element for per-feature morph to be preferred over whole-chart crossfade.
|
|
5
|
+
*
|
|
6
|
+
* Below this threshold, the visual gap between "old chart" and "new chart"
|
|
7
|
+
* is large enough that morphing a small overlap feels jarring; a clean
|
|
8
|
+
* crossfade reads better. Stage 7 ships this constant as scaffolding; the
|
|
9
|
+
* orchestrator-level wiring lives downstream.
|
|
10
|
+
*/
|
|
11
|
+
export declare const ROLE_MATCH_THRESHOLD = 0.5;
|
|
12
|
+
/**
|
|
13
|
+
* Return all live elements in `container` tagged with the given role,
|
|
14
|
+
* keyed by their `data-bc-key` attribute. Used by featureJoin to find
|
|
15
|
+
* cross-feature predecessors when the new commit's selector differs
|
|
16
|
+
* from the prior's.
|
|
17
|
+
*
|
|
18
|
+
* Elements missing a `data-bc-key` are skipped (they couldn't be matched
|
|
19
|
+
* against the new data anyway).
|
|
20
|
+
*/
|
|
21
|
+
export declare function roleScan(container: HTMLElement, role: FeatureRole): Map<string, Element>;
|
|
22
|
+
/**
|
|
23
|
+
* Tag-name compatibility check for cross-type morph.
|
|
24
|
+
*
|
|
25
|
+
* Two elements can morph attribute-to-attribute only when they share a tag
|
|
26
|
+
* (rect → rect, path → path). When the new feature uses a different SVG
|
|
27
|
+
* element than the prior (rect ↔ circle, rect ↔ path), the orchestrator
|
|
28
|
+
* falls back to per-feature crossfade rather than attempting an invalid
|
|
29
|
+
* attribute tween.
|
|
30
|
+
*/
|
|
31
|
+
export declare function tagsCompatible(prior: Element, next: Element): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Decide whether the orchestrator should escalate a commit from per-feature
|
|
34
|
+
* morph to whole-chart crossfade based on how many of the new features have
|
|
35
|
+
* a same-role predecessor.
|
|
36
|
+
*
|
|
37
|
+
* Returns `true` when there is something to match against (`total > 0`) but
|
|
38
|
+
* the match ratio falls below {@link ROLE_MATCH_THRESHOLD}. When `total` is
|
|
39
|
+
* 0 there is nothing to match — return `false` so the caller treats this as
|
|
40
|
+
* a normal first-render rather than a crossfade.
|
|
41
|
+
*/
|
|
42
|
+
export declare function shouldEscalateToFade(matchedCount: number, totalCount: number): boolean;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { SceneTransitionState, TransitionMode } from './types';
|
|
2
|
+
/** Get or create the SceneTransition bound to this container. */
|
|
3
|
+
export declare function getSceneTransition(container: HTMLElement): SceneTransition;
|
|
4
|
+
export interface CommitOptions {
|
|
5
|
+
/** Tween duration in ms. `0` snaps without animating (reduced-motion path). */
|
|
6
|
+
duration?: number;
|
|
7
|
+
/** Transition mode. Defaults to `'transform'`. Other values warn-once and snap. */
|
|
8
|
+
mode?: TransitionMode;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Per-container orchestrator that owns the scene transition lifecycle.
|
|
12
|
+
*
|
|
13
|
+
* Lifecycle:
|
|
14
|
+
* idle ──beginCommit()──▶ committing ──commit()──▶ animating ──end──▶ idle
|
|
15
|
+
*
|
|
16
|
+
* Re-entry into `beginCommit()` while in `committing` or `animating`
|
|
17
|
+
* interrupts the prior transition (invariant I1) before proceeding.
|
|
18
|
+
*
|
|
19
|
+
* NOTE: this task implements only the lifecycle / interrupt / registry.
|
|
20
|
+
* `featureJoin` and feature buffering arrive in the next task.
|
|
21
|
+
*/
|
|
22
|
+
export declare class SceneTransition {
|
|
23
|
+
readonly container: HTMLElement;
|
|
24
|
+
private _state;
|
|
25
|
+
private _transition;
|
|
26
|
+
private _buffer;
|
|
27
|
+
/**
|
|
28
|
+
* Internal: register a flush callback to be run on the next commit.
|
|
29
|
+
* Used by `featureJoin` to defer DOM mutations until the orchestrator
|
|
30
|
+
* is animating. Callbacks run in registration order.
|
|
31
|
+
*/
|
|
32
|
+
register(flush: () => void): void;
|
|
33
|
+
constructor(container: HTMLElement);
|
|
34
|
+
get state(): SceneTransitionState;
|
|
35
|
+
/** Internal: the active d3 transition handle, or null when not animating. */
|
|
36
|
+
get activeTransition(): any;
|
|
37
|
+
/**
|
|
38
|
+
* Enter the committing phase. If a prior transition is in flight, it
|
|
39
|
+
* is interrupted first (invariant I1).
|
|
40
|
+
*/
|
|
41
|
+
beginCommit(): void;
|
|
42
|
+
/**
|
|
43
|
+
* Commit any buffered work and start animating.
|
|
44
|
+
*
|
|
45
|
+
* If `duration` is 0 (e.g. prefers-reduced-motion), the orchestrator
|
|
46
|
+
* goes straight to idle without creating a d3 transition. Tests that
|
|
47
|
+
* pass `duration: 0` rely on this snap path.
|
|
48
|
+
*/
|
|
49
|
+
commit(opts?: CommitOptions): void;
|
|
50
|
+
/**
|
|
51
|
+
* Clamp a requested duration to 0 when the user prefers reduced motion.
|
|
52
|
+
* The lifecycle still runs (snap path), so the same code paths exercise
|
|
53
|
+
* both animated and reduced-motion behaviour — no aesthetic-only branch.
|
|
54
|
+
*/
|
|
55
|
+
private effectiveDuration;
|
|
56
|
+
/**
|
|
57
|
+
* Cancel any in-flight tween. Always safe; idempotent on `idle`.
|
|
58
|
+
*
|
|
59
|
+
* NOTE: this interrupts BC_TRANSITION_NAME tweens on the container and
|
|
60
|
+
* its attached descendants. A descendant that was detached from the
|
|
61
|
+
* container (e.g. an exit node that already self-removed) cannot be
|
|
62
|
+
* reached and its tween may continue ticking until natural completion.
|
|
63
|
+
* Task 5 (featureJoin exit pathway) must therefore wait for the
|
|
64
|
+
* transition's `end` event before calling `.remove()`, not before.
|
|
65
|
+
*/
|
|
66
|
+
interrupt(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Convenience: run a synchronous callback inside `committing` and then
|
|
69
|
+
* commit. Catches exceptions from the callback so the lifecycle never
|
|
70
|
+
* gets stuck.
|
|
71
|
+
*/
|
|
72
|
+
run(work: () => void, opts?: CommitOptions): void;
|
|
73
|
+
/**
|
|
74
|
+
* Tear down: interrupt and drop the WeakMap entry so a fresh lookup
|
|
75
|
+
* returns a new instance. Idempotent.
|
|
76
|
+
*/
|
|
77
|
+
destroy(): void;
|
|
78
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { AttrMap } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* Read the listed attributes off `el` as currently set in the DOM.
|
|
4
|
+
*
|
|
5
|
+
* Before reading, the orchestrator-named d3 transition on the element
|
|
6
|
+
* is interrupted (invariant I4). After interrupt, the attribute values
|
|
7
|
+
* reflect "where the pixels are right now" — exactly what we need as
|
|
8
|
+
* the starting point of a cancel-and-retween.
|
|
9
|
+
*
|
|
10
|
+
* The interrupt targets only the `BC_TRANSITION_NAME` transition so
|
|
11
|
+
* unrelated transitions on the element are unaffected.
|
|
12
|
+
*
|
|
13
|
+
* Attributes that are not present on the element are omitted from the
|
|
14
|
+
* result rather than represented as `null`.
|
|
15
|
+
*/
|
|
16
|
+
export declare function snapshotLiveAttrs(el: Element, names: readonly string[]): AttrMap;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Selection } from 'd3';
|
|
2
|
+
/**
|
|
3
|
+
* Name used for every d3 transition created by the orchestrator.
|
|
4
|
+
* Snapshot + interrupt operations target this name so they don't
|
|
5
|
+
* collide with any unrelated transitions a renderer might have.
|
|
6
|
+
*/
|
|
7
|
+
export declare const BC_TRANSITION_NAME = "bc-scene";
|
|
8
|
+
/** Transition mode chosen by the caller. Only `'transform'` runs in v1. */
|
|
9
|
+
export type TransitionMode = 'transform' | 'fade' | 'slide-x' | 'slide-y';
|
|
10
|
+
/** Lifecycle state of a SceneTransition instance. */
|
|
11
|
+
export type SceneTransitionState = 'idle' | 'committing' | 'animating';
|
|
12
|
+
/**
|
|
13
|
+
* Abstract feature role used for cross-type morph matching.
|
|
14
|
+
*
|
|
15
|
+
* Roles are container-independent: a tick on a vertical axis in one scene
|
|
16
|
+
* and a tick on a horizontal axis in the next can match on
|
|
17
|
+
* `'axis-tick.value'`. The role-matcher (future plan) acts on this tag;
|
|
18
|
+
* v1 stores it without acting on it for cross-type.
|
|
19
|
+
*/
|
|
20
|
+
export type FeatureRole = 'mark-per-category' | 'mark-per-cell' | 'series-path' | 'axis-tick.value' | 'axis-tick.category' | 'value-label' | 'annotation.point' | 'annotation.range' | 'annotation.free';
|
|
21
|
+
/** Subset of SVG / HTML attribute values we tween. */
|
|
22
|
+
export type AttrValue = string | number;
|
|
23
|
+
/** Map of attribute name → value. */
|
|
24
|
+
export type AttrMap = Record<string, AttrValue>;
|
|
25
|
+
/**
|
|
26
|
+
* Description of a keyed visual feature for the orchestrator.
|
|
27
|
+
*
|
|
28
|
+
* The orchestrator reads `data`, matches existing DOM by `key`, and on
|
|
29
|
+
* commit either snaps every element to `attrs(d)` (idle path) or tweens
|
|
30
|
+
* each entry through enter/update/exit pathways (animating path).
|
|
31
|
+
*/
|
|
32
|
+
export interface FeatureJoinConfig<D> {
|
|
33
|
+
role: FeatureRole;
|
|
34
|
+
parent: SVGElement;
|
|
35
|
+
selector: string;
|
|
36
|
+
data: D[];
|
|
37
|
+
key: (d: D) => string;
|
|
38
|
+
insert: (enterSel: Selection<any, D, any, any>) => Selection<any, D, any, any>;
|
|
39
|
+
attrs: (d: D) => AttrMap;
|
|
40
|
+
/** Attrs to apply to a brand-new element at the start of its enter tween. Defaults to `attrs(d)` (snap-in). */
|
|
41
|
+
enterFrom?: (d: D) => AttrMap;
|
|
42
|
+
/** Attrs to tween an exiting element toward before removal. Default: `{ opacity: 0 }`. */
|
|
43
|
+
exitTo?: (d: D) => AttrMap;
|
|
44
|
+
}
|
package/package.json
CHANGED
package/src/charts/chart.scss
CHANGED
|
@@ -35,6 +35,30 @@
|
|
|
35
35
|
background: var(--bc-frame-bg);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
// During a cross-type scene transition, `snapshotForFadeOut()` in motion.ts
|
|
39
|
+
// renames `.bc-frame` -> `.bc-frame--fade-snapshot` on the overlay clone so
|
|
40
|
+
// selectors targeting `.bc-frame` don't double-match the live + fading
|
|
41
|
+
// charts. Without this alias, the snapshot loses the frame's background and
|
|
42
|
+
// font, so the fade-out has nothing visible to fade — producing a flash.
|
|
43
|
+
// `@extend` makes the snapshot inherit every rule rooted on `.bc-frame`,
|
|
44
|
+
// including any descendant selectors added in the future.
|
|
45
|
+
.bc-frame--fade-snapshot {
|
|
46
|
+
@extend .bc-frame;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// The fade overlay is a position:absolute; inset:0; display:flex column
|
|
50
|
+
// container created by snapshotForFadeOut() during cross-type scene
|
|
51
|
+
// transitions. Its cloned chart needs to fill it so the fade-out is
|
|
52
|
+
// visible at the same dimensions as the original chart.
|
|
53
|
+
[data-bc-fade-overlay] {
|
|
54
|
+
> .bc-frame,
|
|
55
|
+
> .bc-frame--fade-snapshot {
|
|
56
|
+
flex: 1;
|
|
57
|
+
min-height: 0;
|
|
58
|
+
width: 100%;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
38
62
|
// Constrained-height mode: when the frame's container has a definite height
|
|
39
63
|
// (fixed or aspect-ratio).
|
|
40
64
|
//
|
|
@@ -86,7 +110,7 @@
|
|
|
86
110
|
// -- Header elements --------------------------------------------------------
|
|
87
111
|
|
|
88
112
|
.bc-frame-header {
|
|
89
|
-
padding: var(--bc-frame-padding) var(--bc-frame-padding) var(--bc-frame-header-padding-bottom,
|
|
113
|
+
padding: var(--bc-frame-padding) var(--bc-frame-padding) var(--bc-frame-header-padding-bottom, 0.5rem);
|
|
90
114
|
background: var(--bc-frame-header-bg, transparent);
|
|
91
115
|
border-bottom: var(--bc-frame-header-border-bottom, none);
|
|
92
116
|
margin-bottom: var(--bc-frame-header-margin-bottom, 0);
|
|
@@ -197,6 +221,7 @@
|
|
|
197
221
|
font-weight: var(--bc-frame-credit-font-weight);
|
|
198
222
|
display: inline-flex;
|
|
199
223
|
align-items: center;
|
|
224
|
+
text-decoration: none;
|
|
200
225
|
}
|
|
201
226
|
|
|
202
227
|
// ---------------------------------------------------------------------------
|
package/dist/dsl/lexer.d.ts
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export interface Token {
|
|
2
|
-
type: TokenType;
|
|
3
|
-
value: string;
|
|
4
|
-
line: number;
|
|
5
|
-
column: number;
|
|
6
|
-
}
|
|
7
|
-
export type TokenType = 'keyword' | 'string' | 'number' | 'percent' | 'lbrace' | 'rbrace' | 'equals' | 'tab' | 'identifier' | 'eof';
|
|
8
|
-
export declare function tokenize(input: string): Token[];
|