ggaction 0.0.15 → 0.0.17
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/CHANGELOG.md +88 -0
- package/README.md +23 -2
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/knowledge/task-packet.schema.json +1 -1
- package/knowledge/task-resolver.js +1 -1
- package/package.json +40 -7
- package/src/BasicChartProgram.js +3 -1
- package/src/ChartProgram.js +2 -0
- package/src/accessibility.js +157 -0
- package/src/actions/boxPlots/components.js +6 -8
- package/src/actions/boxPlots/create.js +4 -5
- package/src/actions/boxPlots/edit.js +3 -4
- package/src/actions/boxPlots/materialize.js +1 -1
- package/src/actions/canvas/actions.js +3 -3
- package/src/actions/canvas/fitting.js +1 -1
- package/src/actions/categoryOrder/index.js +6 -8
- package/src/actions/charts/area.js +1 -1
- package/src/actions/charts/bar.js +1 -1
- package/src/actions/charts/beeswarm.js +1 -1
- package/src/actions/charts/density.js +1 -1
- package/src/actions/charts/ecdf.js +2 -2
- package/src/actions/charts/endpoints.js +4 -4
- package/src/actions/charts/heatmap.js +1 -1
- package/src/actions/charts/histogram.js +1 -1
- package/src/actions/charts/horizon.js +1 -1
- package/src/actions/charts/interval-regression.js +2 -2
- package/src/actions/charts/line.js +1 -1
- package/src/actions/charts/parallel.js +1 -1
- package/src/actions/charts/pie.js +1 -1
- package/src/actions/charts/polar.js +2 -2
- package/src/actions/charts/radar.js +1 -1
- package/src/actions/charts/radial.js +2 -2
- package/src/actions/charts/raincloud.js +2 -2
- package/src/actions/charts/rug-strip.js +2 -2
- package/src/actions/charts/scatter.js +1 -1
- package/src/actions/composition/actions.js +20 -24
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +1 -1
- package/src/actions/data/basicBin2d.js +4 -5
- package/src/actions/data/bin.js +3 -3
- package/src/actions/data/bin2d.js +6 -8
- package/src/actions/data/bin2dMaterialize.js +4 -5
- package/src/actions/data/box.js +4 -4
- package/src/actions/data/complete.js +2 -2
- package/src/actions/data/computed.js +2 -2
- package/src/actions/data/create.js +23 -17
- package/src/actions/data/density.js +4 -4
- package/src/actions/data/derived.js +25 -15
- package/src/actions/data/ecdf.js +2 -2
- package/src/actions/data/edit.js +54 -29
- package/src/actions/data/filter.js +29 -24
- package/src/actions/data/fold.js +2 -2
- package/src/actions/data/gradientProfile.js +2 -2
- package/src/actions/data/horizon.js +2 -2
- package/src/actions/data/impute.js +2 -2
- package/src/actions/data/index.js +58 -54
- package/src/actions/data/interval.js +4 -2
- package/src/actions/data/intervalEdit.js +26 -18
- package/src/actions/data/normalize.js +2 -2
- package/src/actions/data/regression.js +9 -7
- package/src/actions/data/revise.js +80 -0
- package/src/actions/data/revisionBindings.js +13 -33
- package/src/actions/data/shared.js +30 -2
- package/src/actions/data/sort.js +21 -0
- package/src/actions/data/stack.js +2 -2
- package/src/actions/data/summary.js +3 -3
- package/src/actions/data/timeUnit.js +2 -2
- package/src/actions/data/window.js +2 -2
- package/src/actions/encodings/angle.js +5 -2
- package/src/actions/encodings/appearance.js +10 -6
- package/src/actions/encodings/barWidth.js +1 -1
- package/src/actions/encodings/channels.js +2 -2
- package/src/actions/encodings/color/continuous.js +4 -1
- package/src/actions/encodings/color/index.js +5 -2
- package/src/actions/encodings/density.js +2 -2
- package/src/actions/encodings/histogram.js +1 -1
- package/src/actions/encodings/horizon.js +6 -8
- package/src/actions/encodings/offset.js +6 -3
- package/src/actions/encodings/parallel.js +4 -5
- package/src/actions/encodings/pathOrder.js +6 -11
- package/src/actions/encodings/position/index.js +4 -4
- package/src/actions/encodings/position/resolve.js +6 -1
- package/src/actions/encodings/ranged.js +11 -6
- package/src/actions/encodings/remove.js +4 -5
- package/src/actions/encodings/ruleAppearance.js +5 -2
- package/src/actions/encodings/seriesLayout.js +1 -1
- package/src/actions/encodings/stroke.js +5 -2
- package/src/actions/encodings/strokeDash.js +8 -3
- package/src/actions/encodings/text.js +7 -2
- package/src/actions/errorBands/create.js +11 -17
- package/src/actions/errorBands/edit.js +13 -131
- package/src/actions/errorBars/create.js +8 -13
- package/src/actions/errorBars/edit.js +10 -121
- package/src/actions/facets/actions.js +30 -16
- package/src/actions/facets/derive.js +8 -2
- package/src/actions/facets/guides.js +4 -5
- package/src/actions/facets/replay.js +4 -5
- package/src/actions/gradientPlots/components.js +5 -6
- package/src/actions/gradientPlots/create.js +4 -5
- package/src/actions/gradientPlots/edit.js +4 -5
- package/src/actions/gradientPlots/materialize.js +2 -2
- package/src/actions/gradientPlots/rebind.js +4 -5
- package/src/actions/guides/axes/axes.js +23 -4
- package/src/actions/guides/axes/axis.js +2 -2
- package/src/actions/guides/axes/edit.js +2 -2
- package/src/actions/guides/axes/labels.js +9 -9
- package/src/actions/guides/axes/lines.js +9 -7
- package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
- package/src/actions/guides/axes/parallel.js +5 -5
- package/src/actions/guides/axes/remove.js +4 -4
- package/src/actions/guides/axes/tickGroups.js +4 -4
- package/src/actions/guides/axes/ticks.js +13 -4
- package/src/actions/guides/axes/titles.js +10 -10
- package/src/actions/guides/grids/grid.js +18 -29
- package/src/actions/guides/guides.js +1 -1
- package/src/actions/guides/legends/blocks.js +1 -1
- package/src/actions/guides/legends/categorical/actions.js +4 -4
- package/src/actions/guides/legends/categorical/components.js +38 -33
- package/src/actions/guides/legends/categorical/layout.js +1 -1
- package/src/actions/guides/legends/categorical/symbols.js +27 -30
- package/src/actions/guides/legends/continuous/common.js +46 -8
- package/src/actions/guides/legends/continuous/gradient.js +89 -155
- package/src/actions/guides/legends/continuous/interval.js +13 -13
- package/src/actions/guides/legends/continuous/opacity.js +30 -79
- package/src/actions/guides/legends/continuous/stroke.js +22 -322
- package/src/actions/guides/legends/edit.js +1 -1
- package/src/actions/guides/legends/focused.js +5 -5
- package/src/actions/guides/legends/lane.js +6 -6
- package/src/actions/guides/legends/remove.js +4 -5
- package/src/actions/guides/legends/size.js +21 -82
- package/src/actions/guides/legends/strokeWidth.js +17 -77
- package/src/actions/guides/polar/axes/facade.js +4 -4
- package/src/actions/guides/polar/axes/labels.js +5 -5
- package/src/actions/guides/polar/axes/lines.js +9 -15
- package/src/actions/guides/polar/axes/ticks.js +9 -15
- package/src/actions/guides/polar/axes/titles.js +5 -5
- package/src/actions/guides/polar/grids.js +11 -13
- package/src/actions/index.js +2 -0
- package/src/actions/intervals/revision.js +126 -0
- package/src/actions/marks/arc/actions.js +3 -3
- package/src/actions/marks/area/actions.js +4 -4
- package/src/actions/marks/bar/create.js +9 -2
- package/src/actions/marks/bar/edit.js +13 -6
- package/src/actions/marks/bar/materialize.js +12 -38
- package/src/actions/marks/line/actions.js +3 -3
- package/src/actions/marks/point/create.js +9 -2
- package/src/actions/marks/point/edit.js +13 -6
- package/src/actions/marks/point/jitter.js +6 -8
- package/src/actions/marks/point/materialize.js +20 -26
- package/src/actions/marks/point/packing.js +6 -8
- package/src/actions/marks/rect/actions.js +26 -11
- package/src/actions/marks/references.js +8 -10
- package/src/actions/marks/remove.js +5 -49
- package/src/actions/marks/rule/actions.js +28 -12
- package/src/actions/marks/text/actions.js +30 -11
- package/src/actions/marks/text/layout.js +12 -20
- package/src/actions/marks/text/removal.js +1 -1
- package/src/actions/marks/text/selection.js +4 -5
- package/src/actions/marks/tick/actions.js +26 -11
- package/src/actions/primitives/createGraphics.js +5 -4
- package/src/actions/primitives/editGraphics.js +5 -4
- package/src/actions/primitives/graphicProperties.js +6 -0
- package/src/actions/primitives/semantic.js +10 -3
- package/src/actions/primitives/semanticAction.js +44 -7
- package/src/actions/primitives/semanticValidation/dataset.js +14 -4
- package/src/actions/primitives/semanticValidation/layer.js +22 -2
- package/src/actions/primitives/semanticValidation/scale.js +6 -0
- package/src/actions/regression/components.js +10 -14
- package/src/actions/regression/create.js +28 -8
- package/src/actions/regression/edit.js +50 -16
- package/src/actions/regression/follow.js +22 -0
- package/src/actions/resources/remove.js +12 -11
- package/src/actions/scales/channels.js +11 -11
- package/src/actions/scales/consumers/common.js +2 -1
- package/src/actions/scales/create.js +3 -2
- package/src/actions/scales/definitions.js +1 -1
- package/src/actions/scales/edit.js +2 -2
- package/src/actions/scales/materialize.js +1 -1
- package/src/actions/scales/offset.js +2 -2
- package/src/actions/scales/parallel.js +2 -2
- package/src/actions/scales/patch.js +1 -1
- package/src/actions/scales/preview.js +28 -1
- package/src/actions/scales/quantitativeColor.js +4 -5
- package/src/actions/selection/actions.js +25 -36
- package/src/actions/textMetrics/index.js +56 -0
- package/src/actions/theme/actions.js +2 -2
- package/src/actions/theme/reconcile.js +67 -121
- package/src/actions/titles/actions.js +8 -8
- package/src/actions/titles/resolve.js +3 -3
- package/src/actions/violinPlots/create.js +1 -1
- package/src/actions/violinPlots/edit.js +1 -1
- package/src/core/action.js +109 -36
- package/src/core/diagnostics.js +16 -0
- package/src/core/extensionRegistry.js +27 -0
- package/src/core/font.js +18 -0
- package/src/core/identifiers.js +5 -4
- package/src/core/immutable.js +10 -3
- package/src/core/optionRequirements.js +8 -0
- package/src/core/programState.js +6 -2
- package/src/core/resourceReferences.js +15 -6
- package/src/core/textMetricProfile.js +28 -0
- package/src/core/textMetrics.js +24 -3
- package/src/core/validation.js +22 -10
- package/src/diagnostics.js +1 -0
- package/src/grammar/bin.js +39 -10
- package/src/grammar/datasetSchema.js +386 -0
- package/src/grammar/density.js +53 -5
- package/src/grammar/filter.js +133 -39
- package/src/grammar/impute.js +3 -2
- package/src/grammar/interval.js +32 -1
- package/src/grammar/itemMissing.js +59 -0
- package/src/grammar/regression/derive.js +57 -16
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/models.js +51 -22
- package/src/grammar/regression/parameters.js +56 -4
- package/src/grammar/scales/definition.js +7 -0
- package/src/grammar/scales/types.js +8 -0
- package/src/grammar/schemas/graphicBounds.js +11 -11
- package/src/grammar/schemas/semanticPath.js +3 -2
- package/src/grammar/sort.js +88 -0
- package/src/grammar/summary.js +117 -19
- package/src/grammar/transformTopology.js +1 -0
- package/src/grammar/transforms.js +21 -11
- package/src/inspection.js +495 -0
- package/src/inspectionDescriptors.js +3 -0
- package/src/layout/labels.js +11 -10
- package/src/layout/legend.js +4 -4
- package/src/layout/legendItems.js +6 -6
- package/src/layout/text.js +10 -9
- package/src/layout/title.js +9 -9
- package/src/materialization/bars/resolve.js +4 -2
- package/src/materialization/facetGuides/placement.js +1 -1
- package/src/materialization/facetGuides/preparation.js +1 -1
- package/src/materialization/facetHeaders.js +11 -10
- package/src/materialization/guides/layout.js +3 -3
- package/src/materialization/revisionIdentity.js +19 -0
- package/src/materialization/scaleGuideDependencies.js +10 -0
- package/src/materialization/scales/resolve.js +67 -4
- package/src/materialization/selection/items/common.js +1 -1
- package/src/materialization/text.js +6 -4
- package/src/materialization/typography.js +31 -0
- package/src/mcp/cli.js +5 -3
- package/src/persistence/codec.js +65 -0
- package/src/persistence/validation.js +185 -0
- package/src/persistence.js +147 -0
- package/src/renderers/canvas/index.js +5 -4
- package/src/renderers/nativeBackend.js +10 -0
- package/src/renderers/options.js +13 -0
- package/src/renderers/pdf.js +25 -54
- package/src/renderers/png.js +22 -17
- package/src/renderers/svg.js +10 -14
- package/src/renderers/text.js +1 -11
- package/src/selectors/coordinates.js +3 -1
- package/src/selectors/datasets.js +8 -6
- package/src/selectors/layers.js +6 -4
- package/src/selectors/markOwners.js +46 -0
- package/src/selectors/scales.js +6 -4
- package/src/theme/defaults.js +2 -1
- package/src/version.js +2 -0
- package/types/accessibility.d.ts +37 -0
- package/types/basic.d.ts +4 -2
- package/types/diagnostics.d.ts +15 -0
- package/types/index.d.ts +5 -0
- package/types/inspection.d.ts +17 -0
- package/types/pdf.d.ts +9 -0
- package/types/persistence.d.ts +7 -0
- package/types/png.d.ts +9 -0
- package/types/program.d.ts +181 -28
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { rematerializeTypography } from "../../materialization/typography.js";
|
|
1
2
|
import { themeTokens } from "../../theme/defaults.js";
|
|
2
3
|
import {
|
|
3
4
|
normalizeThemeState,
|
|
@@ -5,6 +6,7 @@ import {
|
|
|
5
6
|
setThemeStateOverrides
|
|
6
7
|
} from "./state.js";
|
|
7
8
|
import { findLayer } from "../../selectors/layers.js";
|
|
9
|
+
import { reconcileFollowingRegressions } from "../regression/follow.js";
|
|
8
10
|
|
|
9
11
|
let rematerializeThemeHighlights = program => program;
|
|
10
12
|
|
|
@@ -46,10 +48,7 @@ function tokenFor(value, sourceTokens, targetTokens) {
|
|
|
46
48
|
if (matches.length === 0) return undefined;
|
|
47
49
|
const targets = new Set(matches.map(token => targetTokens[token]));
|
|
48
50
|
if (targets.size !== 1) return undefined;
|
|
49
|
-
|
|
50
|
-
if (targetTokens[token] === targets.values().next().value) return token;
|
|
51
|
-
}
|
|
52
|
-
return undefined;
|
|
51
|
+
return matches[0];
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
function roleValues(role, sourceTokens, legacy = []) {
|
|
@@ -411,6 +410,11 @@ function recolorConfig(
|
|
|
411
410
|
return { changed, value: changed ? next : value };
|
|
412
411
|
}
|
|
413
412
|
|
|
413
|
+
function addMarkPropertyOverrides(overrides, id, property) {
|
|
414
|
+
overrides.add(`c:marks.${id}.${property}`);
|
|
415
|
+
overrides.add(`g:${id}.${property}`);
|
|
416
|
+
}
|
|
417
|
+
|
|
414
418
|
function addMarkOverrides(overrides, program, op, args) {
|
|
415
419
|
const match = /^(?:create|edit)(Point|Line|Area|Arc|Bar|Rect|Rule|Tick|Text)Mark$/u
|
|
416
420
|
.exec(op);
|
|
@@ -425,42 +429,43 @@ function addMarkOverrides(overrides, program, op, args) {
|
|
|
425
429
|
if (typeof id !== "string") return;
|
|
426
430
|
for (const property of ["fill", "stroke", "fontFamily"]) {
|
|
427
431
|
if (!Object.hasOwn(args, property)) continue;
|
|
428
|
-
overrides
|
|
429
|
-
overrides.add(`g:${id}.${property}`);
|
|
432
|
+
addMarkPropertyOverrides(overrides, id, property);
|
|
430
433
|
}
|
|
431
434
|
}
|
|
432
435
|
|
|
433
436
|
function addFacadeMarkOverrides(overrides, op, args) {
|
|
434
437
|
const facades = {
|
|
435
|
-
createScatterPlot: ["
|
|
436
|
-
createLinePlot: ["
|
|
437
|
-
createPolarScatterPlot: ["
|
|
438
|
-
createPolarLinePlot: ["
|
|
439
|
-
createRadarPlot: ["
|
|
440
|
-
createRugPlot: ["
|
|
441
|
-
createStripPlot: ["
|
|
442
|
-
createBeeswarmPlot: ["
|
|
443
|
-
createBarPlot: ["
|
|
444
|
-
createAreaPlot: ["
|
|
445
|
-
createPiePlot: ["
|
|
446
|
-
createRosePlot: ["
|
|
447
|
-
createRadialBarPlot: ["
|
|
448
|
-
createDensityPlot: ["
|
|
449
|
-
createParallelCoordinates: ["
|
|
450
|
-
createHistogram: ["
|
|
451
|
-
createHeatmap: ["
|
|
452
|
-
createHorizonPlot: ["
|
|
453
|
-
editHorizon: ["
|
|
454
|
-
createViolinPlot: ["
|
|
438
|
+
createScatterPlot: ["point", true],
|
|
439
|
+
createLinePlot: ["line", false],
|
|
440
|
+
createPolarScatterPlot: ["point", true],
|
|
441
|
+
createPolarLinePlot: ["line", false],
|
|
442
|
+
createRadarPlot: ["line", false],
|
|
443
|
+
createRugPlot: ["tick", false],
|
|
444
|
+
createStripPlot: ["point", true],
|
|
445
|
+
createBeeswarmPlot: ["point", true],
|
|
446
|
+
createBarPlot: ["bar", true],
|
|
447
|
+
createAreaPlot: ["area", true],
|
|
448
|
+
createPiePlot: ["arc", true],
|
|
449
|
+
createRosePlot: ["arc", true],
|
|
450
|
+
createRadialBarPlot: ["arc", true],
|
|
451
|
+
createDensityPlot: ["area", true],
|
|
452
|
+
createParallelCoordinates: ["line", false],
|
|
453
|
+
createHistogram: ["bar", true],
|
|
454
|
+
createHeatmap: ["rect", false],
|
|
455
|
+
createHorizonPlot: ["area", false],
|
|
456
|
+
editHorizon: ["area", false],
|
|
457
|
+
createViolinPlot: ["area", true]
|
|
455
458
|
};
|
|
456
459
|
const facade = facades[op];
|
|
457
460
|
if (facade === undefined) return;
|
|
458
|
-
const [
|
|
461
|
+
const [option, includesFill] = facade;
|
|
462
|
+
const subject = op === "editHorizon" ? "HorizonPlot" : op.slice(6);
|
|
463
|
+
const defaultId = subject[0].toLowerCase() + subject.slice(1);
|
|
464
|
+
const properties = includesFill ? ["fill", "stroke"] : ["stroke"];
|
|
459
465
|
const id = args.id ?? defaultId;
|
|
460
466
|
for (const property of properties) {
|
|
461
467
|
if (!Object.hasOwn(args[option] ?? {}, property)) continue;
|
|
462
|
-
overrides
|
|
463
|
-
overrides.add(`g:${id}.${property}`);
|
|
468
|
+
addMarkPropertyOverrides(overrides, id, property);
|
|
464
469
|
}
|
|
465
470
|
}
|
|
466
471
|
|
|
@@ -492,8 +497,7 @@ function addTextFacadeOverrides(overrides, node) {
|
|
|
492
497
|
if (typeof id !== "string") return;
|
|
493
498
|
for (const property of ["fill", "fontFamily"]) {
|
|
494
499
|
if (!Object.hasOwn(node.args, property)) continue;
|
|
495
|
-
overrides
|
|
496
|
-
overrides.add(`g:${id}.${property}`);
|
|
500
|
+
addMarkPropertyOverrides(overrides, id, property);
|
|
497
501
|
}
|
|
498
502
|
}
|
|
499
503
|
|
|
@@ -509,8 +513,7 @@ function addErrorBarOverrides(overrides, program, node) {
|
|
|
509
513
|
if (id === undefined) return;
|
|
510
514
|
const config = program.markConfigs[id].errorBar;
|
|
511
515
|
for (const target of [id, config.lowerCapId, config.upperCapId]) {
|
|
512
|
-
overrides
|
|
513
|
-
overrides.add(`g:${target}.stroke`);
|
|
516
|
+
addMarkPropertyOverrides(overrides, target, "stroke");
|
|
514
517
|
}
|
|
515
518
|
}
|
|
516
519
|
|
|
@@ -536,8 +539,7 @@ function addErrorBandOverrides(overrides, program, node) {
|
|
|
536
539
|
const targets = errorBandTargets(program, node);
|
|
537
540
|
if (targets === undefined) return;
|
|
538
541
|
if (Object.hasOwn(node.args, "fill") && node.args.fill !== false) {
|
|
539
|
-
overrides
|
|
540
|
-
overrides.add(`g:${targets.id}.fill`);
|
|
542
|
+
addMarkPropertyOverrides(overrides, targets.id, "fill");
|
|
541
543
|
}
|
|
542
544
|
const boundary = node.op === "editErrorBandBoundary"
|
|
543
545
|
? node.args
|
|
@@ -548,8 +550,7 @@ function addErrorBandOverrides(overrides, program, node) {
|
|
|
548
550
|
? [targets.lower, targets.upper]
|
|
549
551
|
: [(node.args.boundary === "lower" ? targets.lower : targets.upper)];
|
|
550
552
|
for (const id of ids) {
|
|
551
|
-
overrides
|
|
552
|
-
overrides.add(`g:${id}.stroke`);
|
|
553
|
+
addMarkPropertyOverrides(overrides, id, "stroke");
|
|
553
554
|
}
|
|
554
555
|
}
|
|
555
556
|
|
|
@@ -589,8 +590,7 @@ function addReferenceOverrides(overrides, op, args) {
|
|
|
589
590
|
const id = args.id ?? defaultId;
|
|
590
591
|
for (const property of properties) {
|
|
591
592
|
if (!Object.hasOwn(args, property)) continue;
|
|
592
|
-
overrides
|
|
593
|
-
overrides.add(`g:${id}.${property}`);
|
|
593
|
+
addMarkPropertyOverrides(overrides, id, property);
|
|
594
594
|
}
|
|
595
595
|
}
|
|
596
596
|
|
|
@@ -611,12 +611,10 @@ function addRegressionOverrides(overrides, node) {
|
|
|
611
611
|
: child?.args.id ?? child?.args.target;
|
|
612
612
|
if (typeof id !== "string") return;
|
|
613
613
|
if (Object.hasOwn(style ?? {}, "color")) {
|
|
614
|
-
overrides
|
|
615
|
-
overrides.add(`g:${id}.fill`);
|
|
614
|
+
addMarkPropertyOverrides(overrides, id, "fill");
|
|
616
615
|
}
|
|
617
616
|
if (Object.hasOwn(style ?? {}, "stroke")) {
|
|
618
|
-
overrides
|
|
619
|
-
overrides.add(`g:${id}.stroke`);
|
|
617
|
+
addMarkPropertyOverrides(overrides, id, "stroke");
|
|
620
618
|
}
|
|
621
619
|
}
|
|
622
620
|
|
|
@@ -835,39 +833,18 @@ function addParallelOverrides(overrides, program, op, args) {
|
|
|
835
833
|
}
|
|
836
834
|
|
|
837
835
|
function addLegendOverrides(overrides, program, args) {
|
|
838
|
-
const
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
};
|
|
851
|
-
for (const kind of Object.keys(legend)) {
|
|
852
|
-
if (Object.hasOwn(args.labels ?? {}, "color")) {
|
|
853
|
-
overrides.add(`c:guides.legend.${kind}.labels.color`);
|
|
854
|
-
if (prefixes[kind]) overrides.add(`g:${prefixes[kind]}Labels.fill`);
|
|
855
|
-
}
|
|
856
|
-
if (Object.hasOwn(args.labels ?? {}, "fontFamily")) {
|
|
857
|
-
overrides.add(`c:guides.legend.${kind}.labels.fontFamily`);
|
|
858
|
-
if (prefixes[kind]) overrides.add(`g:${prefixes[kind]}Labels.fontFamily`);
|
|
859
|
-
}
|
|
860
|
-
if (Object.hasOwn(args.titleStyle ?? {}, "color")) {
|
|
861
|
-
overrides.add(`c:guides.legend.${kind}.titleStyle.color`);
|
|
862
|
-
if (prefixes[kind]) overrides.add(`g:${prefixes[kind]}Title.fill`);
|
|
863
|
-
}
|
|
864
|
-
if (Object.hasOwn(args.titleStyle ?? {}, "fontFamily")) {
|
|
865
|
-
overrides.add(`c:guides.legend.${kind}.titleStyle.fontFamily`);
|
|
866
|
-
if (prefixes[kind]) overrides.add(`g:${prefixes[kind]}Title.fontFamily`);
|
|
867
|
-
}
|
|
868
|
-
if (Object.hasOwn(args.border ?? {}, "color")) {
|
|
869
|
-
overrides.add(`c:guides.legend.${kind}.border.color`);
|
|
870
|
-
if (prefixes[kind]) overrides.add(`g:${prefixes[kind]}Background.stroke`);
|
|
836
|
+
for (const kind of Object.keys(program.guideConfigs.legend ?? {})) {
|
|
837
|
+
const prefix = legendPrefix(kind);
|
|
838
|
+
for (const [option, suffix, property, graphicProperty] of [
|
|
839
|
+
["labels", "Labels", "color", "fill"],
|
|
840
|
+
["labels", "Labels", "fontFamily", "fontFamily"],
|
|
841
|
+
["titleStyle", "Title", "color", "fill"],
|
|
842
|
+
["titleStyle", "Title", "fontFamily", "fontFamily"],
|
|
843
|
+
["border", "Background", "color", "stroke"]
|
|
844
|
+
]) {
|
|
845
|
+
if (!Object.hasOwn(args[option] ?? {}, property)) continue;
|
|
846
|
+
overrides.add(`c:guides.legend.${kind}.${option}.${property}`);
|
|
847
|
+
if (prefix) overrides.add(`g:${prefix}${suffix}.${graphicProperty}`);
|
|
871
848
|
}
|
|
872
849
|
}
|
|
873
850
|
}
|
|
@@ -1002,51 +979,19 @@ function collectOverrides(program) {
|
|
|
1002
979
|
return overrides;
|
|
1003
980
|
}
|
|
1004
981
|
|
|
1005
|
-
function callExisting(program, graphicId, operation) {
|
|
1006
|
-
return program.graphicSpec.objects[graphicId] !== undefined &&
|
|
1007
|
-
typeof program[operation] === "function"
|
|
1008
|
-
? program[operation]()
|
|
1009
|
-
: program;
|
|
1010
|
-
}
|
|
1011
|
-
|
|
1012
|
-
function rematerializeThemeTypography(program) {
|
|
1013
|
-
if (program.compositionSpec !== undefined) {
|
|
1014
|
-
return program.compositionSpec.type === "facet"
|
|
1015
|
-
? program.materializeComposition()
|
|
1016
|
-
: program;
|
|
1017
|
-
}
|
|
1018
|
-
|
|
1019
|
-
let next = program;
|
|
1020
|
-
for (const layer of next.semanticSpec.layers) {
|
|
1021
|
-
if (layer.mark?.type === "text" &&
|
|
1022
|
-
next.graphicSpec.objects[layer.id] !== undefined &&
|
|
1023
|
-
typeof next.rematerializeTextMark === "function") {
|
|
1024
|
-
next = next.rematerializeTextMark({ id: layer.id });
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
for (const [id, operation] of [
|
|
1028
|
-
["xAxisLabels", "editXAxisLabels"],
|
|
1029
|
-
["yAxisLabels", "editYAxisLabels"],
|
|
1030
|
-
["xAxisTitle", "editXAxisTitle"],
|
|
1031
|
-
["yAxisTitle", "editYAxisTitle"],
|
|
1032
|
-
["thetaAxisLabels", "editThetaAxisLabels"],
|
|
1033
|
-
["radialAxisLabels", "editRadialAxisLabels"],
|
|
1034
|
-
["thetaAxisTitle", "editThetaAxisTitle"],
|
|
1035
|
-
["radialAxisTitle", "editRadialAxisTitle"]
|
|
1036
|
-
]) {
|
|
1037
|
-
next = callExisting(next, id, operation);
|
|
1038
|
-
}
|
|
1039
|
-
if (Object.keys(next.guideConfigs.legend ?? {}).length > 0 &&
|
|
1040
|
-
typeof next.rematerializeLegend === "function") {
|
|
1041
|
-
next = next.rematerializeLegend();
|
|
1042
|
-
}
|
|
1043
|
-
next = callExisting(next, "chartTitle", "rematerializeTitle");
|
|
1044
|
-
return next;
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
982
|
export function reconcileProgramTheme(program, { source, metadata }) {
|
|
983
|
+
program = reconcileFollowingRegressions(program);
|
|
1048
984
|
const storedState = program.materializationConfigs.theme;
|
|
1049
985
|
if (storedState === undefined) return program;
|
|
986
|
+
// Data/context/trace-only transitions cannot change authored appearance.
|
|
987
|
+
// Preserve all visual identities instead of rescanning every existing mark.
|
|
988
|
+
if (program.graphicSpec === source.graphicSpec &&
|
|
989
|
+
program.materializationConfigs === source.materializationConfigs &&
|
|
990
|
+
program.children === source.children &&
|
|
991
|
+
program.compositionSpec === source.compositionSpec &&
|
|
992
|
+
["layers", "scales", "coordinates", "guides", "title"].every(
|
|
993
|
+
key => program.semanticSpec[key] === source.semanticSpec[key]
|
|
994
|
+
)) return program;
|
|
1050
995
|
const composition = program.compositionSpec !== undefined;
|
|
1051
996
|
const state = normalizeThemeState(storedState, { composition });
|
|
1052
997
|
const sourceState = normalizeThemeState(
|
|
@@ -1088,15 +1033,16 @@ export function reconcileProgramTheme(program, { source, metadata }) {
|
|
|
1088
1033
|
|
|
1089
1034
|
const facetsChanged = configs.value.facets !==
|
|
1090
1035
|
themed.materializationConfigs.facets;
|
|
1036
|
+
const typographyChanged = sourceTokens.fontFamily !== targetTokens.fontFamily;
|
|
1091
1037
|
if (facetsChanged && next.compositionSpec?.type === "facet") {
|
|
1092
1038
|
next = next.materializeComposition();
|
|
1093
|
-
} else if (
|
|
1094
|
-
next =
|
|
1039
|
+
} else if (typographyChanged) {
|
|
1040
|
+
next = rematerializeTypography(next);
|
|
1095
1041
|
}
|
|
1096
1042
|
|
|
1097
1043
|
const parallelChanged = configs.value.guides.axis?.parallel !==
|
|
1098
1044
|
themed.guideConfigs.axis?.parallel;
|
|
1099
|
-
if (parallelChanged && typeof next.rematerializeParallelAxes === "function") {
|
|
1045
|
+
if (parallelChanged && !typographyChanged && typeof next.rematerializeParallelAxes === "function") {
|
|
1100
1046
|
next = next.rematerializeParallelAxes();
|
|
1101
1047
|
}
|
|
1102
1048
|
|
|
@@ -115,12 +115,12 @@ function titleTextAction(kind, create) {
|
|
|
115
115
|
}));
|
|
116
116
|
}
|
|
117
117
|
|
|
118
|
-
export const editTitleText = titleTextAction("title", false);
|
|
119
|
-
export const createTitleText = titleTextAction("title", true);
|
|
120
|
-
export const editSubtitleText = titleTextAction("subtitle", false);
|
|
121
|
-
export const createSubtitleText = titleTextAction("subtitle", true);
|
|
118
|
+
export const editTitleText = /* @__PURE__ */ titleTextAction("title", false);
|
|
119
|
+
export const createTitleText = /* @__PURE__ */ titleTextAction("title", true);
|
|
120
|
+
export const editSubtitleText = /* @__PURE__ */ titleTextAction("subtitle", false);
|
|
121
|
+
export const createSubtitleText = /* @__PURE__ */ titleTextAction("subtitle", true);
|
|
122
122
|
|
|
123
|
-
export const rematerializeTitle = action(
|
|
123
|
+
export const rematerializeTitle = /* @__PURE__ */ action(
|
|
124
124
|
{ op: "rematerializeTitle", description: "Rematerialize chart title graphics." },
|
|
125
125
|
withGuideLayoutValidation(function (args = {}) {
|
|
126
126
|
noOptions(args, "rematerializeTitle");
|
|
@@ -142,7 +142,7 @@ export const rematerializeTitle = action(
|
|
|
142
142
|
})
|
|
143
143
|
);
|
|
144
144
|
|
|
145
|
-
export const createTitle = action(
|
|
145
|
+
export const createTitle = /* @__PURE__ */ action(
|
|
146
146
|
{
|
|
147
147
|
op: "createTitle",
|
|
148
148
|
description: "Create a chart title and optional subtitle.",
|
|
@@ -176,7 +176,7 @@ export const createTitle = action(
|
|
|
176
176
|
})
|
|
177
177
|
);
|
|
178
178
|
|
|
179
|
-
export const editTitle = action(
|
|
179
|
+
export const editTitle = /* @__PURE__ */ action(
|
|
180
180
|
{
|
|
181
181
|
op: "editTitle",
|
|
182
182
|
description: "Edit one stable chart title resource.",
|
|
@@ -214,7 +214,7 @@ export const editTitle = action(
|
|
|
214
214
|
})
|
|
215
215
|
);
|
|
216
216
|
|
|
217
|
-
export const removeTitle = action(
|
|
217
|
+
export const removeTitle = /* @__PURE__ */ action(
|
|
218
218
|
{
|
|
219
219
|
op: "removeTitle",
|
|
220
220
|
description: "Remove the complete chart title resource.",
|
|
@@ -212,7 +212,7 @@ export function resolveTitleLayout(program, config) {
|
|
|
212
212
|
program.semanticSpec.title.subtitle,
|
|
213
213
|
"Chart subtitle"
|
|
214
214
|
)
|
|
215
|
-
}, config);
|
|
215
|
+
}, config, program.materializationConfigs.textMetrics);
|
|
216
216
|
const horizontal = ["top", "bottom"].includes(config.position);
|
|
217
217
|
let component;
|
|
218
218
|
if (horizontal) {
|
|
@@ -249,10 +249,10 @@ export function resolveTitleLayout(program, config) {
|
|
|
249
249
|
? undefined
|
|
250
250
|
: component(block.subtitleLines, block.subtitleCenters);
|
|
251
251
|
const titleBounds = unionTitleBounds([
|
|
252
|
-
resolveTitleComponentBounds(title, config.titleStyle),
|
|
252
|
+
resolveTitleComponentBounds(title, config.titleStyle, program.materializationConfigs.textMetrics),
|
|
253
253
|
...(subtitle === undefined
|
|
254
254
|
? []
|
|
255
|
-
: [resolveTitleComponentBounds(subtitle, config.subtitleStyle)])
|
|
255
|
+
: [resolveTitleComponentBounds(subtitle, config.subtitleStyle, program.materializationConfigs.textMetrics)])
|
|
256
256
|
]);
|
|
257
257
|
validateLayout(
|
|
258
258
|
config.position,
|
|
@@ -132,7 +132,7 @@ function guideOptions(guides, x, y, category, color) {
|
|
|
132
132
|
};
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
-
export const createViolinPlot = action(
|
|
135
|
+
export const createViolinPlot = /* @__PURE__ */ action(
|
|
136
136
|
{
|
|
137
137
|
op: "createViolinPlot",
|
|
138
138
|
description: "Create a categorical kernel-density violin plot."
|
|
@@ -74,7 +74,7 @@ function assertSplitSelectionCompatibility(program, owner, changesSplit) {
|
|
|
74
74
|
}
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
export const editViolinPlot = action(
|
|
77
|
+
export const editViolinPlot = /* @__PURE__ */ action(
|
|
78
78
|
{
|
|
79
79
|
op: OPERATION,
|
|
80
80
|
description: "Revise one violin plot's data and statistical roles."
|
package/src/core/action.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { validateKeys } from "./validation.js";
|
|
2
|
+
import { annotateError } from "./diagnostics.js";
|
|
3
|
+
import { cloneAndFreeze, freezeOwned, isOwned, isPlainObject } from "./immutable.js";
|
|
2
4
|
|
|
3
5
|
const metadataByWrappedAction = new WeakMap();
|
|
4
6
|
const implementationByWrappedAction = new WeakMap();
|
|
@@ -35,6 +37,8 @@ function summarizeObject(value, ancestors = new WeakSet()) {
|
|
|
35
37
|
summary[`${key}Count`] = item.length;
|
|
36
38
|
} else if (isPlainObject(item)) {
|
|
37
39
|
summary[key] = summarizeObject(item, ancestors);
|
|
40
|
+
} else if (typeof item === "function") {
|
|
41
|
+
summary[`${key}Type`] = "function";
|
|
38
42
|
} else if (item !== null && typeof item === "object") {
|
|
39
43
|
summary[`${key}Type`] = item.constructor?.name ?? "object";
|
|
40
44
|
} else {
|
|
@@ -71,13 +75,59 @@ export function createActionNode({ id, op, description, args }) {
|
|
|
71
75
|
});
|
|
72
76
|
}
|
|
73
77
|
|
|
78
|
+
// Persistent child tails make appending the active (last) branch independent
|
|
79
|
+
// of sibling count. The public children property remains a stable frozen Array.
|
|
80
|
+
const childLists = new WeakMap();
|
|
81
|
+
|
|
82
|
+
function childList(node) {
|
|
83
|
+
let list = childLists.get(node);
|
|
84
|
+
if (list !== undefined) return list;
|
|
85
|
+
let tail;
|
|
86
|
+
for (const child of node.children) tail = { value: child, previous: tail };
|
|
87
|
+
list = { tail, length: node.children.length };
|
|
88
|
+
if (isOwned(node)) childLists.set(node, list);
|
|
89
|
+
return list;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function withChildList(node, list) {
|
|
93
|
+
let children;
|
|
94
|
+
const next = {};
|
|
95
|
+
for (const key of Object.keys(node)) {
|
|
96
|
+
if (key !== "children") Object.defineProperty(next, key, {
|
|
97
|
+
value: node[key], enumerable: true
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
Object.defineProperty(next, "children", {
|
|
101
|
+
enumerable: true,
|
|
102
|
+
get() {
|
|
103
|
+
if (children === undefined) {
|
|
104
|
+
const values = new Array(list.length);
|
|
105
|
+
let item = list.tail;
|
|
106
|
+
for (let index = list.length - 1; index >= 0; index -= 1) {
|
|
107
|
+
values[index] = item.value;
|
|
108
|
+
item = item.previous;
|
|
109
|
+
}
|
|
110
|
+
children = freezeOwned(values);
|
|
111
|
+
}
|
|
112
|
+
return children;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
childLists.set(next, list);
|
|
116
|
+
return freezeOwned(next);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function childAt(node, index) {
|
|
120
|
+
const list = childList(node);
|
|
121
|
+
return index === list.length - 1 ? list.tail.value : node.children[index];
|
|
122
|
+
}
|
|
123
|
+
|
|
74
124
|
function nodeAtPath(root, path) {
|
|
75
125
|
let node = root;
|
|
76
126
|
for (const index of path) {
|
|
77
|
-
if (!Number.isInteger(index) || index < 0 || index >= node.
|
|
127
|
+
if (!Number.isInteger(index) || index < 0 || index >= childList(node).length) {
|
|
78
128
|
throw new Error(`Unknown parent action path "${path.join(".")}".`);
|
|
79
129
|
}
|
|
80
|
-
node = node
|
|
130
|
+
node = childAt(node, index);
|
|
81
131
|
}
|
|
82
132
|
return node;
|
|
83
133
|
}
|
|
@@ -87,19 +137,28 @@ export function appendActionNodeAtPath(root, parentPath, actionNode) {
|
|
|
87
137
|
throw new TypeError("Parent action path must be an array.");
|
|
88
138
|
}
|
|
89
139
|
const parent = nodeAtPath(root, parentPath);
|
|
90
|
-
const path = [...parentPath, parent.
|
|
140
|
+
const path = [...parentPath, childList(parent).length];
|
|
91
141
|
|
|
92
142
|
function append(node, depth) {
|
|
143
|
+
const list = childList(node);
|
|
93
144
|
if (depth === parentPath.length) {
|
|
94
|
-
return
|
|
95
|
-
|
|
96
|
-
children: freezeOwned([...node.children, actionNode])
|
|
145
|
+
return withChildList(node, {
|
|
146
|
+
tail: { value: actionNode, previous: list.tail }, length: list.length + 1
|
|
97
147
|
});
|
|
98
148
|
}
|
|
99
149
|
const index = parentPath[depth];
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
150
|
+
const child = append(childAt(node, index), depth + 1);
|
|
151
|
+
if (index === list.length - 1) {
|
|
152
|
+
return withChildList(node, {
|
|
153
|
+
tail: { value: child, previous: list.tail.previous }, length: list.length
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
// Restored/extension traces may address an older sibling explicitly.
|
|
157
|
+
let tail;
|
|
158
|
+
for (let position = 0; position < list.length; position += 1) {
|
|
159
|
+
tail = { value: position === index ? child : node.children[position], previous: tail };
|
|
160
|
+
}
|
|
161
|
+
return withChildList(node, { tail, length: list.length });
|
|
103
162
|
}
|
|
104
163
|
|
|
105
164
|
return { root: append(root, 0), path };
|
|
@@ -133,43 +192,57 @@ export function action(metadata, implementation) {
|
|
|
133
192
|
const ownedMetadata = freezeOwned({
|
|
134
193
|
op: metadata.op,
|
|
135
194
|
description: metadata.description,
|
|
136
|
-
scope
|
|
195
|
+
scope,
|
|
196
|
+
...(Array.isArray(metadata.options) ? { options: [...metadata.options] } : {})
|
|
137
197
|
});
|
|
138
198
|
|
|
139
199
|
const wrappedAction = function wrappedAction(args = {}) {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
152
|
-
let result = implementation.call(entered, args);
|
|
153
|
-
|
|
154
|
-
if (!(result instanceof this.constructor)) {
|
|
155
|
-
throw new TypeError(`${ownedMetadata.op} must return a ChartProgram.`);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
if (this.actionStack.length === 0 && actionCompletionHook !== undefined) {
|
|
159
|
-
result = actionCompletionHook(result, {
|
|
160
|
-
source: this,
|
|
161
|
-
metadata: ownedMetadata,
|
|
200
|
+
try {
|
|
201
|
+
if (!isPlainObject(args)) {
|
|
202
|
+
throw new TypeError("Action arguments must be a plain object.");
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (scope === "unit") this._assertUnitProgram(ownedMetadata.op);
|
|
206
|
+
if (scope === "composition") this._assertCompositionProgram(ownedMetadata.op);
|
|
207
|
+
|
|
208
|
+
const summarizedArgs = summarizeArgs(args);
|
|
209
|
+
const entered = this._enterAction({
|
|
210
|
+
...ownedMetadata,
|
|
162
211
|
args: summarizedArgs
|
|
163
212
|
});
|
|
213
|
+
let result = implementation.call(entered, args);
|
|
214
|
+
|
|
164
215
|
if (!(result instanceof this.constructor)) {
|
|
165
|
-
throw new TypeError(
|
|
216
|
+
throw new TypeError(`${ownedMetadata.op} must return a ChartProgram.`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
if (this.actionStack.length === 0 && actionCompletionHook !== undefined) {
|
|
220
|
+
result = actionCompletionHook(result, {
|
|
221
|
+
source: this,
|
|
222
|
+
metadata: ownedMetadata,
|
|
223
|
+
args: summarizedArgs
|
|
224
|
+
});
|
|
225
|
+
if (!(result instanceof this.constructor)) {
|
|
226
|
+
throw new TypeError("Action completion hook must return a ChartProgram.");
|
|
227
|
+
}
|
|
166
228
|
}
|
|
229
|
+
|
|
230
|
+
return result._exitAction();
|
|
231
|
+
} catch (error) {
|
|
232
|
+
throw annotateError(error, { code: "action-failed", operation: ownedMetadata.op });
|
|
167
233
|
}
|
|
168
|
-
|
|
169
|
-
return result._exitAction();
|
|
170
234
|
};
|
|
171
235
|
|
|
172
236
|
metadataByWrappedAction.set(wrappedAction, ownedMetadata);
|
|
173
237
|
implementationByWrappedAction.set(wrappedAction, implementation);
|
|
174
238
|
return wrappedAction;
|
|
175
239
|
}
|
|
240
|
+
|
|
241
|
+
// Private built-in convenience: action() owns the object boundary and trace,
|
|
242
|
+
// while each definition supplies its closed option vocabulary exactly once.
|
|
243
|
+
export function closedAction(metadata, options, implementation) {
|
|
244
|
+
return action({ ...metadata, options }, function (args = {}) {
|
|
245
|
+
if (options !== undefined) validateKeys(args, options, metadata.op);
|
|
246
|
+
return implementation.call(this, args);
|
|
247
|
+
});
|
|
248
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const detailsByError = new WeakMap();
|
|
2
|
+
|
|
3
|
+
export function getErrorDetails(error) {
|
|
4
|
+
return error !== null && (typeof error === "object" || typeof error === "function")
|
|
5
|
+
? detailsByError.get(error) : undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Attach metadata without modifying the thrown value or its existing class.
|
|
9
|
+
export function annotateError(error, details) {
|
|
10
|
+
if (!(error instanceof Error)) return error;
|
|
11
|
+
const previous = getErrorDetails(error);
|
|
12
|
+
const merged = { ...details, ...previous };
|
|
13
|
+
if (merged.candidates !== undefined) merged.candidates = Object.freeze([...merged.candidates]);
|
|
14
|
+
detailsByError.set(error, Object.freeze(merged));
|
|
15
|
+
return error;
|
|
16
|
+
}
|
|
@@ -4,6 +4,32 @@ import { isPlainObject } from "./immutable.js";
|
|
|
4
4
|
const ACTION_NAME_PATTERN = /^[A-Za-z_$][A-Za-z0-9_$]*$/;
|
|
5
5
|
const DEFINITION_KEYS = new Set(["name", "actions"]);
|
|
6
6
|
const registeredExtensionNames = new Set();
|
|
7
|
+
const extensionByAction = new Map();
|
|
8
|
+
const builtinOpsByClass = new WeakMap();
|
|
9
|
+
|
|
10
|
+
export function recordBuiltinActions(ProgramClass, additional = []) {
|
|
11
|
+
builtinOpsByClass.set(ProgramClass, new Set([
|
|
12
|
+
...Object.getOwnPropertyNames(ProgramClass.prototype).flatMap(name => {
|
|
13
|
+
const metadata = getWrappedActionMetadata(ProgramClass.prototype[name]);
|
|
14
|
+
return metadata ? [metadata.op] : [];
|
|
15
|
+
}), ...additional
|
|
16
|
+
]));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isBuiltinProgramClass(ProgramClass) {
|
|
20
|
+
return builtinOpsByClass.has(ProgramClass);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function requiredTraceExtension(ProgramClass, op) {
|
|
24
|
+
if (op === "program" || builtinOpsByClass.get(ProgramClass)?.has(op)) return undefined;
|
|
25
|
+
const extension = extensionByAction.get(op);
|
|
26
|
+
if (extension !== undefined) return extension;
|
|
27
|
+
throw new TypeError(`Cannot persist unregistered action "${op}".`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function hasRegisteredExtension(name) {
|
|
31
|
+
return registeredExtensionNames.has(name);
|
|
32
|
+
}
|
|
7
33
|
|
|
8
34
|
function readDataProperty(object, key, owner) {
|
|
9
35
|
const descriptor = Object.getOwnPropertyDescriptor(object, key);
|
|
@@ -101,4 +127,5 @@ export function registerProgramExtension(ProgramClass, definition) {
|
|
|
101
127
|
|
|
102
128
|
Object.defineProperties(ProgramClass.prototype, descriptors);
|
|
103
129
|
registeredExtensionNames.add(name);
|
|
130
|
+
for (const actionName of actionNames) extensionByAction.set(actionName, name);
|
|
104
131
|
}
|
package/src/core/font.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export const DEFAULT_FONT_FAMILY = "sans-serif";
|
|
2
|
+
|
|
3
|
+
export function normalizeRendererFontWeight(fontWeight) {
|
|
4
|
+
if (typeof fontWeight !== "number") return fontWeight;
|
|
5
|
+
return Math.min(900, Math.max(100, Math.round(fontWeight / 100) * 100));
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function textMetricKey({ text, fontFamily, fontSize, fontWeight }) {
|
|
9
|
+
return JSON.stringify([text, fontFamily, fontSize, fontWeight]);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function textMetricFontWeight(value = "normal") {
|
|
13
|
+
if (typeof value === "number") return normalizeRendererFontWeight(value);
|
|
14
|
+
if (value === "normal") return 400;
|
|
15
|
+
if (value === "bold") return 700;
|
|
16
|
+
if (/^[1-9]00$/u.test(value)) return Number(value);
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|