ggaction 0.0.13 → 0.0.16
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 +146 -0
- package/README.md +41 -12
- 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 +39 -7
- package/src/BasicChartProgram.js +3 -1
- package/src/ChartProgram.js +2 -0
- package/src/accessibility.js +157 -0
- package/src/actions/basic.js +2 -2
- package/src/actions/boxPlots/components.js +20 -12
- package/src/actions/boxPlots/create.js +4 -5
- package/src/actions/boxPlots/edit.js +34 -9
- package/src/actions/boxPlots/materialize.js +12 -4
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/canvas/actions.js +3 -3
- package/src/actions/canvas/fitting.js +1 -1
- package/src/actions/categoryOrder/index.js +21 -12
- package/src/actions/charts/area.js +6 -2
- package/src/actions/charts/bar.js +3 -2
- package/src/actions/charts/beeswarm.js +1 -1
- package/src/actions/charts/density.js +7 -3
- package/src/actions/charts/ecdf.js +6 -3
- package/src/actions/charts/endpoints.js +29 -7
- package/src/actions/charts/heatmap.js +3 -2
- package/src/actions/charts/histogram.js +5 -4
- package/src/actions/charts/horizon.js +4 -2
- package/src/actions/charts/interval-regression.js +7 -4
- package/src/actions/charts/line.js +4 -2
- package/src/actions/charts/parallel.js +9 -3
- package/src/actions/charts/pie.js +11 -3
- package/src/actions/charts/polar.js +17 -6
- package/src/actions/charts/radar.js +9 -3
- package/src/actions/charts/radial.js +12 -4
- package/src/actions/charts/raincloud.js +2 -2
- package/src/actions/charts/rug-strip.js +8 -4
- package/src/actions/charts/scatter.js +4 -2
- package/src/actions/composition/actions.js +29 -24
- package/src/actions/coordinates/actions.js +2 -2
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/basicBin2d.js +4 -5
- package/src/actions/data/bin.js +3 -3
- package/src/actions/data/bin2d.js +63 -193
- package/src/actions/data/bin2dMaterialize.js +4 -5
- package/src/actions/data/box.js +4 -4
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +4 -4
- package/src/actions/data/create.js +7 -14
- package/src/actions/data/density.js +15 -23
- package/src/actions/data/derived.js +57 -31
- package/src/actions/data/ecdf.js +2 -2
- package/src/actions/data/edit.js +551 -0
- package/src/actions/data/filter.js +28 -22
- 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 +26 -0
- package/src/actions/data/index.js +62 -47
- package/src/actions/data/interval.js +2 -2
- package/src/actions/data/intervalEdit.js +26 -18
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +21 -27
- package/src/actions/data/revise.js +48 -0
- package/src/actions/data/revisionBindings.js +125 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/stack.js +2 -2
- package/src/actions/data/summary.js +3 -3
- package/src/actions/data/timeUnit.js +6 -3
- package/src/actions/data/window.js +3 -3
- package/src/actions/encodings/angle.js +1 -1
- package/src/actions/encodings/appearance.js +4 -4
- package/src/actions/encodings/barWidth.js +1 -1
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/index.js +3 -2
- package/src/actions/encodings/density.js +7 -4
- package/src/actions/encodings/histogram.js +4 -3
- package/src/actions/encodings/horizon.js +6 -8
- package/src/actions/encodings/index.js +4 -0
- package/src/actions/encodings/offset.js +22 -15
- package/src/actions/encodings/parallel.js +4 -5
- package/src/actions/encodings/pathOrder.js +6 -11
- package/src/actions/encodings/position/apply.js +53 -7
- package/src/actions/encodings/position/index.js +14 -6
- package/src/actions/encodings/position/policies/bar.js +9 -0
- package/src/actions/encodings/position/resolve.js +24 -7
- package/src/actions/encodings/ranged.js +5 -5
- package/src/actions/encodings/remove.js +13 -9
- package/src/actions/encodings/ruleAppearance.js +2 -24
- package/src/actions/encodings/seriesLayout.js +2 -1
- package/src/actions/encodings/shared.js +82 -14
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/encodings/strokeDash.js +2 -2
- package/src/actions/encodings/text.js +1 -1
- package/src/actions/errorBands/create.js +34 -20
- package/src/actions/errorBands/edit.js +34 -137
- package/src/actions/errorBars/create.js +43 -20
- package/src/actions/errorBars/edit.js +29 -125
- package/src/actions/facets/actions.js +267 -73
- package/src/actions/facets/derive.js +99 -28
- package/src/actions/facets/guides.js +4 -5
- package/src/actions/facets/replay.js +4 -5
- package/src/actions/gradientPlots/components.js +15 -8
- package/src/actions/gradientPlots/create.js +4 -5
- package/src/actions/gradientPlots/edit.js +18 -9
- package/src/actions/gradientPlots/materialize.js +5 -3
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/gradientPlots/rebind.js +4 -5
- package/src/actions/guides/applicability.js +8 -2
- 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 +67 -21
- package/src/actions/guides/axes/lines.js +15 -9
- package/src/actions/guides/axes/parallel/lifecycle.js +13 -13
- package/src/actions/guides/axes/parallel/resolve.js +6 -2
- 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 +6 -5
- package/src/actions/guides/axes/ticks.js +19 -6
- package/src/actions/guides/axes/titles.js +21 -13
- package/src/actions/guides/grids/grid.js +18 -29
- package/src/actions/guides/grids/resolve.js +7 -2
- package/src/actions/guides/guides.js +20 -4
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +138 -52
- package/src/actions/guides/legends/categorical/components.js +55 -45
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +98 -16
- package/src/actions/guides/legends/categorical/options.js +2 -2
- package/src/actions/guides/legends/categorical/recipes.js +111 -20
- package/src/actions/guides/legends/categorical/resolve.js +12 -8
- package/src/actions/guides/legends/categorical/symbols.js +104 -52
- package/src/actions/guides/legends/continuous/common.js +76 -20
- package/src/actions/guides/legends/continuous/gradient.js +95 -158
- package/src/actions/guides/legends/continuous/index.js +2 -0
- package/src/actions/guides/legends/continuous/interval.js +21 -16
- package/src/actions/guides/legends/continuous/opacity.js +37 -83
- package/src/actions/guides/legends/continuous/stroke.js +225 -0
- package/src/actions/guides/legends/creation.js +14 -1
- package/src/actions/guides/legends/edit.js +159 -60
- package/src/actions/guides/legends/focused.js +5 -5
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +59 -24
- package/src/actions/guides/legends/lifecycle.js +19 -8
- package/src/actions/guides/legends/remove.js +17 -8
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +100 -108
- package/src/actions/guides/legends/strokeWidth.js +38 -92
- package/src/actions/guides/legends/target.js +112 -1
- package/src/actions/guides/legends/transition.js +165 -16
- package/src/actions/guides/polar/axes/facade.js +8 -8
- package/src/actions/guides/polar/axes/labels.js +29 -10
- package/src/actions/guides/polar/axes/lines.js +19 -19
- package/src/actions/guides/polar/axes/shared.js +16 -0
- package/src/actions/guides/polar/axes/ticks.js +10 -16
- package/src/actions/guides/polar/axes/titles.js +6 -6
- package/src/actions/guides/polar/grids.js +12 -14
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/index.js +16 -3
- package/src/actions/intervals/revision.js +126 -0
- package/src/actions/marks/arc/actions.js +80 -22
- package/src/actions/marks/area/actions.js +38 -13
- package/src/actions/marks/area/materialize.js +17 -1
- package/src/actions/marks/bar/create.js +12 -3
- package/src/actions/marks/bar/edit.js +21 -4
- package/src/actions/marks/bar/materialize.js +34 -40
- package/src/actions/marks/index.js +10 -1
- package/src/actions/marks/line/actions.js +40 -17
- package/src/actions/marks/line/materialize.js +29 -10
- package/src/actions/marks/point/create.js +9 -3
- package/src/actions/marks/point/edit.js +19 -7
- package/src/actions/marks/point/jitter.js +6 -8
- package/src/actions/marks/point/materialize.js +48 -22
- package/src/actions/marks/point/packing.js +6 -8
- package/src/actions/marks/rect/actions.js +36 -15
- package/src/actions/marks/references.js +602 -33
- package/src/actions/marks/remove.js +67 -41
- package/src/actions/marks/rule/actions.js +51 -14
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +79 -14
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +157 -17
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +72 -0
- package/src/actions/marks/tick/actions.js +25 -8
- package/src/actions/primitives/createGraphics.js +5 -4
- package/src/actions/primitives/editGraphics.js +31 -4
- package/src/actions/primitives/graphicProperties.js +6 -0
- package/src/actions/primitives/semantic.js +11 -3
- package/src/actions/primitives/semanticAction.js +90 -14
- package/src/actions/primitives/semanticValidation/dataset.js +2 -4
- package/src/actions/primitives/semanticValidation/guide.js +1 -1
- package/src/actions/primitives/semanticValidation/index.js +9 -1
- package/src/actions/primitives/semanticValidation/layer.js +5 -0
- package/src/actions/primitives/semanticValidation/scale.js +28 -7
- package/src/actions/regression/components.js +36 -25
- package/src/actions/regression/create.js +13 -6
- package/src/actions/regression/edit.js +24 -11
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +173 -0
- package/src/actions/scales/channels.js +212 -0
- package/src/actions/scales/consumers/common.js +1 -1
- package/src/actions/scales/consumers/families.js +3 -2
- package/src/actions/scales/consumers/index.js +19 -2
- package/src/actions/scales/consumers/seriesLayout.js +28 -14
- package/src/actions/scales/create.js +55 -23
- package/src/actions/scales/definitions.js +94 -40
- package/src/actions/scales/edit.js +67 -12
- package/src/actions/scales/editPolicy.js +81 -11
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +5 -4
- package/src/actions/scales/offset.js +48 -0
- package/src/actions/scales/parallel.js +71 -0
- package/src/actions/scales/preview.js +111 -10
- package/src/actions/scales/quantitativeColor.js +4 -5
- package/src/actions/selection/actions.js +179 -66
- package/src/actions/selection/index.js +3 -0
- package/src/actions/textMetrics/index.js +56 -0
- package/src/actions/theme/actions.js +70 -15
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +9 -2
- package/src/actions/theme/reconcile.js +313 -121
- package/src/actions/theme/state.js +160 -0
- package/src/actions/titles/actions.js +8 -8
- package/src/actions/titles/resolve.js +3 -3
- package/src/actions/violinPlots/create.js +6 -3
- package/src/actions/violinPlots/edit.js +2 -1
- package/src/core/action.js +117 -35
- package/src/core/compositionState.js +6 -1
- 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 +21 -1
- package/src/core/resourceReferences.js +341 -0
- package/src/core/textMetricProfile.js +28 -0
- package/src/core/textMetrics.js +24 -3
- package/src/core/validation.js +22 -10
- package/src/core/vocabulary.js +16 -3
- package/src/diagnostics.js +1 -0
- package/src/grammar/bars/aggregate.js +4 -1
- package/src/grammar/bars/geometry.js +44 -0
- package/src/grammar/bin.js +54 -9
- package/src/grammar/complete.js +279 -0
- package/src/grammar/computed.js +265 -64
- package/src/grammar/coordinates.js +37 -0
- package/src/grammar/density.js +239 -37
- package/src/grammar/displayLabels.js +57 -0
- package/src/grammar/facets/dependencies.js +133 -1
- package/src/grammar/facets/guides.js +3 -0
- package/src/grammar/facets/index.js +7 -47
- package/src/grammar/facets/scales.js +15 -18
- package/src/grammar/impute.js +341 -0
- package/src/grammar/markLabelSelection.js +57 -0
- package/src/grammar/markLabels.js +18 -1
- package/src/grammar/normalize.js +366 -0
- package/src/grammar/pathSeries.js +26 -8
- package/src/grammar/pointShapes.js +13 -4
- package/src/grammar/polar.js +90 -8
- package/src/grammar/regression/index.js +1 -0
- package/src/grammar/regression/parameters.js +23 -0
- package/src/grammar/roundedRect.js +180 -0
- package/src/grammar/rules.js +1 -0
- package/src/grammar/scales/colorConsumers.js +20 -1
- package/src/grammar/scales/continuous.js +2 -2
- package/src/grammar/scales/definition.js +27 -4
- package/src/grammar/scales/index.js +1 -0
- package/src/grammar/scales/ordinal.js +12 -3
- package/src/grammar/scales/policies.js +2 -2
- package/src/grammar/scales/size.js +456 -0
- package/src/grammar/scales/types.js +8 -0
- package/src/grammar/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +190 -41
- package/src/grammar/schemas/semanticPath.js +7 -2
- package/src/grammar/statisticalReference.js +103 -0
- package/src/grammar/strokeStyle.js +77 -0
- package/src/grammar/summary.js +78 -16
- package/src/grammar/timeUnit.js +216 -5
- package/src/grammar/transformTopology.js +4 -0
- package/src/grammar/transforms.js +394 -28
- package/src/grammar/weightedStatistics.js +374 -0
- package/src/grammar/window.js +221 -16
- package/src/layout/aspect.js +80 -0
- package/src/layout/facets.js +59 -5
- package/src/layout/labels.js +351 -7
- 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/aggregate.js +25 -2
- package/src/materialization/bars/histogram.js +84 -24
- package/src/materialization/bars/ranged.js +19 -3
- package/src/materialization/bars/resolve.js +7 -4
- package/src/materialization/composition.js +3 -1
- package/src/materialization/coordinateBounds.js +204 -0
- package/src/materialization/dependencies.js +36 -0
- package/src/materialization/facetGuides/legacyCategorical.js +3 -0
- package/src/materialization/facetGuides/placement.js +9 -3
- package/src/materialization/facetGuides/preparation.js +13 -8
- package/src/materialization/facetHeaders.js +347 -0
- package/src/materialization/facets.js +15 -65
- package/src/materialization/guides/layout.js +3 -3
- package/src/materialization/guides/resources.js +26 -0
- package/src/materialization/legends.js +1 -1
- package/src/materialization/marks/index.js +11 -5
- package/src/materialization/marks/policies.js +2 -1
- package/src/materialization/rect.js +25 -12
- package/src/materialization/rectConfig.js +5 -1
- package/src/materialization/scaleGuideDependencies.js +10 -0
- package/src/materialization/scales/map.js +5 -3
- package/src/materialization/scales/policies/binnedPosition.js +2 -2
- package/src/materialization/scales/policies/offset.js +50 -8
- package/src/materialization/scales/policies/series.js +4 -1
- package/src/materialization/scales/resolve.js +22 -6
- package/src/materialization/selection/items/arc.js +28 -4
- package/src/materialization/selection/items/bar.js +30 -3
- package/src/materialization/selection/items/common.js +20 -5
- package/src/materialization/selection/items/rect.js +28 -4
- package/src/materialization/selection/path.js +1 -1
- package/src/materialization/selection/point.js +3 -1
- package/src/materialization/text.js +265 -14
- 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 +74 -0
- package/src/renderers/canvas/circle.js +2 -3
- package/src/renderers/canvas/index.js +5 -4
- package/src/renderers/canvas/line.js +2 -3
- package/src/renderers/canvas/native.js +4 -4
- package/src/renderers/canvas/path.js +2 -3
- package/src/renderers/canvas/rect.js +2 -3
- package/src/renderers/canvas/stroke.js +11 -0
- 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 +29 -14
- package/src/renderers/text.js +1 -11
- package/src/selectors/coordinates.js +3 -1
- package/src/selectors/datasets.js +38 -5
- package/src/selectors/layers.js +10 -4
- package/src/selectors/markOwners.js +46 -0
- package/src/selectors/scales.js +6 -4
- package/src/theme/defaults.js +103 -1
- package/src/version.js +2 -0
- package/types/accessibility.d.ts +37 -0
- package/types/basic.d.ts +10 -2
- package/types/diagnostics.d.ts +15 -0
- package/types/index.d.ts +90 -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 +944 -118
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { action } from "../../core/action.js";
|
|
1
|
+
import { action, closedAction } from "../../core/action.js";
|
|
2
2
|
import { validateUserId } from "../../core/identifiers.js";
|
|
3
3
|
import { isPlainObject } from "../../core/immutable.js";
|
|
4
4
|
import { validateKeys } from "../../core/validation.js";
|
|
5
|
-
import {
|
|
5
|
+
import { collectResourceReferences } from "../../core/resourceReferences.js";
|
|
6
|
+
import { findLayer, resolveEligibleLayer } from "../../selectors/layers.js";
|
|
7
|
+
import { isSourceOwnedText } from "../../grammar/text.js";
|
|
6
8
|
import { transformPointHighlightChild } from "../../materialization/selection/point.js";
|
|
7
9
|
import {
|
|
8
10
|
transformPathHighlightProperties,
|
|
@@ -22,6 +24,10 @@ import {
|
|
|
22
24
|
normalizeDimOthers,
|
|
23
25
|
validateUnitInterval
|
|
24
26
|
} from "../../materialization/selection/styles.js";
|
|
27
|
+
import {
|
|
28
|
+
normalizeThemeState,
|
|
29
|
+
resolveEffectiveThemeTokens
|
|
30
|
+
} from "../theme/state.js";
|
|
25
31
|
|
|
26
32
|
const SELECTOR_KEYS = Object.freeze([
|
|
27
33
|
"grain", "field", "channel", "property", "op", "value", "values", "min", "max",
|
|
@@ -58,32 +64,38 @@ function resolveTarget(program, target, label = "mark selection") {
|
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
function hasLegendSelection(program, target, selection) {
|
|
61
|
-
const legend = program.guideConfigs.legend?.series ??
|
|
62
|
-
program.guideConfigs.legend?.color;
|
|
63
67
|
const selector = program.materializationConfigs.selections?.[selection]?.selector;
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
const layer = findLayer(program, target);
|
|
69
|
+
const field = selector?.field ?? layer?.encoding?.[selector?.channel]?.field;
|
|
70
|
+
if (field === undefined) return false;
|
|
71
|
+
return ["series", "color", "stroke"].some(kind => {
|
|
72
|
+
const legend = program.guideConfigs.legend?.[kind];
|
|
73
|
+
return legend?.target === target && legend.field === field &&
|
|
74
|
+
(selector?.channel === undefined || legend.channels.includes(selector.channel));
|
|
75
|
+
});
|
|
67
76
|
}
|
|
68
77
|
|
|
69
|
-
function
|
|
70
|
-
return ["series", "color"].
|
|
78
|
+
function categoricalLegendKinds(program, target) {
|
|
79
|
+
return ["series", "color", "stroke"].filter(
|
|
71
80
|
kind => program.guideConfigs.legend?.[kind]?.target === target
|
|
72
81
|
);
|
|
73
82
|
}
|
|
74
83
|
|
|
75
84
|
function resetCategoricalLegendSymbols(program, target) {
|
|
76
|
-
const
|
|
77
|
-
if (
|
|
85
|
+
const kinds = categoricalLegendKinds(program, target);
|
|
86
|
+
if (kinds.length === 0) return program;
|
|
78
87
|
let next = program;
|
|
79
|
-
for (const
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
88
|
+
for (const kind of kinds) {
|
|
89
|
+
for (const id of legendGraphicIds(kind).filter(id => id.includes("Symbol"))) {
|
|
90
|
+
const graphic = next.graphicSpec.objects[id];
|
|
91
|
+
if (graphic === undefined) continue;
|
|
92
|
+
next = graphic.type === "collection"
|
|
93
|
+
? next.editGraphics({ target: id, property: "items", value: [] })
|
|
94
|
+
: next.editGraphics({ target: id, property: "length", value: 0 });
|
|
95
|
+
}
|
|
96
|
+
next = next.rematerializeLegendSymbols({ kind });
|
|
85
97
|
}
|
|
86
|
-
return next
|
|
98
|
+
return next;
|
|
87
99
|
}
|
|
88
100
|
|
|
89
101
|
function targetHighlightEntries(program, target) {
|
|
@@ -91,7 +103,32 @@ function targetHighlightEntries(program, target) {
|
|
|
91
103
|
.filter(([, config]) => config.target === target);
|
|
92
104
|
}
|
|
93
105
|
|
|
94
|
-
function
|
|
106
|
+
function namedLabelDependents(program, selection) {
|
|
107
|
+
const referenced = new Set(collectResourceReferences(program, {
|
|
108
|
+
kind: "selection",
|
|
109
|
+
id: selection
|
|
110
|
+
}).filter(reference =>
|
|
111
|
+
reference.ownerKind === "markConfig" &&
|
|
112
|
+
reference.path.join(".") === "labelAuthoring.selection.id"
|
|
113
|
+
).map(reference => reference.ownerId));
|
|
114
|
+
return Object.entries(program.markConfigs)
|
|
115
|
+
.filter(([id, config]) => {
|
|
116
|
+
const layer = findLayer(program, id);
|
|
117
|
+
return isSourceOwnedText(layer) &&
|
|
118
|
+
config?.labelAuthoring?.selection?.kind === "named" &&
|
|
119
|
+
referenced.has(id);
|
|
120
|
+
})
|
|
121
|
+
.map(([id]) => id)
|
|
122
|
+
.sort();
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function rematerializeLabels(program, ids) {
|
|
126
|
+
let next = program;
|
|
127
|
+
for (const id of ids) next = next.rematerializeTextMark({ id });
|
|
128
|
+
return next;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function rebuildTargetHighlights(program, target, { labels = [] } = {}) {
|
|
95
132
|
const layer = resolveTarget(program, target, "highlight mark");
|
|
96
133
|
const highlights = targetHighlightEntries(program, target);
|
|
97
134
|
let baseline = program;
|
|
@@ -105,12 +142,26 @@ function rebuildTargetHighlights(program, target) {
|
|
|
105
142
|
baseline = baseline[requireSelectionPolicy(
|
|
106
143
|
layer.mark.type
|
|
107
144
|
).rematerializeOp]({ id: target });
|
|
145
|
+
baseline = rematerializeLabels(baseline, labels);
|
|
108
146
|
baseline = resetCategoricalLegendSymbols(baseline, target);
|
|
109
147
|
return highlights.length === 0
|
|
110
148
|
? baseline
|
|
111
149
|
: baseline.rematerializeMarkHighlights({ target, highlights });
|
|
112
150
|
}
|
|
113
151
|
|
|
152
|
+
export function rematerializeLabelsBeforeHighlights(
|
|
153
|
+
program,
|
|
154
|
+
target,
|
|
155
|
+
labels,
|
|
156
|
+
{ skipWithoutHighlights = false } = {}
|
|
157
|
+
) {
|
|
158
|
+
return targetHighlightEntries(program, target).length === 0
|
|
159
|
+
? skipWithoutHighlights
|
|
160
|
+
? program
|
|
161
|
+
: rematerializeLabels(program, labels)
|
|
162
|
+
: rebuildTargetHighlights(program, target, { labels });
|
|
163
|
+
}
|
|
164
|
+
|
|
114
165
|
function selectedKeys(args, resolved) {
|
|
115
166
|
if (args.keys === undefined) return resolved.keys;
|
|
116
167
|
if (!Array.isArray(args.keys) || !args.keys.every(key =>
|
|
@@ -155,9 +206,10 @@ function editSelectedItems(
|
|
|
155
206
|
}
|
|
156
207
|
|
|
157
208
|
function applyHighlight(program, config, keys) {
|
|
209
|
+
const style = resolveHighlightStyle(program, config);
|
|
158
210
|
let next = program[requireSelectionPolicy(config.markType).applyHighlightOp]({
|
|
159
211
|
selection: config.selection,
|
|
160
|
-
style
|
|
212
|
+
style,
|
|
161
213
|
keys
|
|
162
214
|
});
|
|
163
215
|
if (config.dimOthers !== false) {
|
|
@@ -172,10 +224,63 @@ function applyHighlight(program, config, keys) {
|
|
|
172
224
|
: next;
|
|
173
225
|
}
|
|
174
226
|
|
|
175
|
-
|
|
176
|
-
|
|
227
|
+
function highlightPaintProperty(markType) {
|
|
228
|
+
return ["line", "rule", "tick"].includes(markType) ? "stroke" : "fill";
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
function requestedPaintSource(args, markType, style) {
|
|
232
|
+
const property = highlightPaintProperty(markType);
|
|
233
|
+
const explicit = args.color !== undefined || args[property] !== undefined;
|
|
234
|
+
if (explicit) return "explicit";
|
|
235
|
+
return Object.hasOwn(style, property) ? "theme" : "preserve";
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function tracePaintSource(program, id, config) {
|
|
239
|
+
let source;
|
|
240
|
+
for (const node of program.trace.children) {
|
|
241
|
+
if (node.op !== "highlightMarks") continue;
|
|
242
|
+
const requestedId = node.args.selection ?? node.args.id ??
|
|
243
|
+
`${node.args.target ?? config.target}Selection`;
|
|
244
|
+
if (requestedId !== id) continue;
|
|
245
|
+
const property = highlightPaintProperty(config.markType);
|
|
246
|
+
const explicit = node.args.color !== undefined ||
|
|
247
|
+
node.args[property] !== undefined;
|
|
248
|
+
source = explicit
|
|
249
|
+
? "explicit"
|
|
250
|
+
: Object.hasOwn(config.style, property) ? "theme" : "preserve";
|
|
251
|
+
}
|
|
252
|
+
return source ?? "explicit";
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function normalizeStoredHighlightConfig(program, id, config) {
|
|
256
|
+
return config.paintSource === undefined
|
|
257
|
+
? { ...config, paintSource: tracePaintSource(program, id, config) }
|
|
258
|
+
: config;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function resolveHighlightStyle(program, config) {
|
|
262
|
+
if (config.paintSource !== "theme") return config.style;
|
|
263
|
+
const property = highlightPaintProperty(config.markType);
|
|
264
|
+
return {
|
|
265
|
+
...config.style,
|
|
266
|
+
[property]: resolveEffectiveThemeTokens(normalizeThemeState(
|
|
267
|
+
program.materializationConfigs.theme
|
|
268
|
+
)).highlight
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function rematerializeThemeHighlights(program) {
|
|
273
|
+
const targets = [...new Set(Object.values(
|
|
274
|
+
program.materializationConfigs.highlights ?? {}
|
|
275
|
+
).map(config => config.target))];
|
|
276
|
+
let next = program;
|
|
277
|
+
for (const target of targets) next = rebuildTargetHighlights(next, target);
|
|
278
|
+
return next;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export const selectMarks = /* @__PURE__ */ closedAction(
|
|
282
|
+
{ op: "selectMarks", description: "Create one reusable selection over final mark items." }, SELECT_OPTIONS,
|
|
177
283
|
function (args = {}) {
|
|
178
|
-
validateKeys(args, SELECT_OPTIONS, "selectMarks");
|
|
179
284
|
const layer = resolveTarget(this, args.target);
|
|
180
285
|
const resolved = resolveMarkSelection(this, layer.id, selectorFrom(args));
|
|
181
286
|
const id = resolveSelectionCreationId(this, args.id, layer.id);
|
|
@@ -185,20 +290,19 @@ export const selectMarks = action(
|
|
|
185
290
|
}
|
|
186
291
|
);
|
|
187
292
|
|
|
188
|
-
export const editMarkSelection =
|
|
293
|
+
export const editMarkSelection = /* @__PURE__ */ closedAction(
|
|
189
294
|
{
|
|
190
295
|
op: "editMarkSelection",
|
|
191
296
|
description: "Replace one stored mark selector while preserving its identity and target."
|
|
192
|
-
},
|
|
297
|
+
}, EDIT_SELECTION_OPTIONS,
|
|
193
298
|
function (args = {}) {
|
|
194
|
-
validateKeys(args, EDIT_SELECTION_OPTIONS, "editMarkSelection");
|
|
195
299
|
const current = resolveStoredSelection(this, args.selection);
|
|
196
300
|
const replacement = resolveMarkSelection(
|
|
197
301
|
this,
|
|
198
302
|
current.definition.target,
|
|
199
303
|
selectorFrom(args)
|
|
200
304
|
);
|
|
201
|
-
|
|
305
|
+
let next = this
|
|
202
306
|
._withSelectionConfig(current.id, {
|
|
203
307
|
target: current.definition.target,
|
|
204
308
|
selector: replacement.selector
|
|
@@ -207,19 +311,24 @@ export const editMarkSelection = action(
|
|
|
207
311
|
const hasDependentHighlight = Object.values(
|
|
208
312
|
next.materializationConfigs.highlights ?? {}
|
|
209
313
|
).some(config => config.selection === current.id);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
314
|
+
const labels = namedLabelDependents(this, current.id);
|
|
315
|
+
if (hasDependentHighlight) {
|
|
316
|
+
return rematerializeLabelsBeforeHighlights(
|
|
317
|
+
next,
|
|
318
|
+
current.definition.target,
|
|
319
|
+
labels
|
|
320
|
+
);
|
|
321
|
+
}
|
|
322
|
+
return rematerializeLabels(next, labels);
|
|
213
323
|
}
|
|
214
324
|
);
|
|
215
325
|
|
|
216
|
-
export const removeMarkHighlight =
|
|
326
|
+
export const removeMarkHighlight = /* @__PURE__ */ closedAction(
|
|
217
327
|
{
|
|
218
328
|
op: "removeMarkHighlight",
|
|
219
329
|
description: "Remove one stored highlight assignment and restore the clean mark baseline."
|
|
220
|
-
},
|
|
330
|
+
}, REMOVE_SELECTION_OPTIONS,
|
|
221
331
|
function (args = {}) {
|
|
222
|
-
validateKeys(args, REMOVE_SELECTION_OPTIONS, "removeMarkHighlight");
|
|
223
332
|
const current = resolveStoredSelection(this, args.selection);
|
|
224
333
|
const dependent = Object.entries(
|
|
225
334
|
this.materializationConfigs.highlights ?? {}
|
|
@@ -237,14 +346,19 @@ export const removeMarkHighlight = action(
|
|
|
237
346
|
}
|
|
238
347
|
);
|
|
239
348
|
|
|
240
|
-
export const removeMarkSelection =
|
|
349
|
+
export const removeMarkSelection = /* @__PURE__ */ closedAction(
|
|
241
350
|
{
|
|
242
351
|
op: "removeMarkSelection",
|
|
243
352
|
description: "Remove one stored selection after removing its dependent highlight."
|
|
244
|
-
},
|
|
353
|
+
}, REMOVE_SELECTION_OPTIONS,
|
|
245
354
|
function (args = {}) {
|
|
246
|
-
validateKeys(args, REMOVE_SELECTION_OPTIONS, "removeMarkSelection");
|
|
247
355
|
const current = resolveStoredSelection(this, args.selection);
|
|
356
|
+
const labelDependents = namedLabelDependents(this, current.id);
|
|
357
|
+
if (labelDependents.length > 0) {
|
|
358
|
+
throw new Error(
|
|
359
|
+
`Selection "${current.id}" is referenced by attached labels: ${labelDependents.join(", ")}.`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
248
362
|
const hasDependentHighlight = Object.values(
|
|
249
363
|
this.materializationConfigs.highlights ?? {}
|
|
250
364
|
).some(config => config.selection === current.id);
|
|
@@ -258,10 +372,9 @@ export const removeMarkSelection = action(
|
|
|
258
372
|
}
|
|
259
373
|
);
|
|
260
374
|
|
|
261
|
-
export const applyPointHighlight =
|
|
262
|
-
{ op: "applyPointHighlight", description: "Apply selected point appearance and geometry." },
|
|
375
|
+
export const applyPointHighlight = /* @__PURE__ */ closedAction(
|
|
376
|
+
{ op: "applyPointHighlight", description: "Apply selected point appearance and geometry." }, INTERNAL_SELECTION_OPTIONS,
|
|
263
377
|
function (args = {}) {
|
|
264
|
-
validateKeys(args, INTERNAL_SELECTION_OPTIONS, "applyPointHighlight");
|
|
265
378
|
const resolved = resolveStoredSelection(this, args.selection);
|
|
266
379
|
const keys = selectedKeys(args, resolved);
|
|
267
380
|
if (resolved.items[0]?.markType !== "point" && resolved.items.length > 0) {
|
|
@@ -287,6 +400,15 @@ function transformRectangularProperties(properties, style, offset = false) {
|
|
|
287
400
|
};
|
|
288
401
|
}
|
|
289
402
|
|
|
403
|
+
function transformRectangularHighlightChild(item, style, offset) {
|
|
404
|
+
return {
|
|
405
|
+
...item,
|
|
406
|
+
properties: item.type === "path"
|
|
407
|
+
? transformPathHighlightProperties(item.properties, style)
|
|
408
|
+
: transformRectangularProperties(item.properties, style, offset)
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
|
|
290
412
|
function applyRectangularHighlight(
|
|
291
413
|
program,
|
|
292
414
|
args,
|
|
@@ -301,22 +423,18 @@ function applyRectangularHighlight(
|
|
|
301
423
|
throw new Error(`${operation} requires a ${markType} selection.`);
|
|
302
424
|
}
|
|
303
425
|
if (keys.length === 0) return program;
|
|
304
|
-
return editSelectedItems(program, resolved, keys, item =>
|
|
305
|
-
|
|
306
|
-
properties: transformRectangularProperties(
|
|
307
|
-
item.properties, args.style, offset
|
|
308
|
-
)
|
|
309
|
-
}));
|
|
426
|
+
return editSelectedItems(program, resolved, keys, item =>
|
|
427
|
+
transformRectangularHighlightChild(item, args.style, offset));
|
|
310
428
|
}
|
|
311
429
|
|
|
312
|
-
export const applyBarHighlight = action(
|
|
430
|
+
export const applyBarHighlight = /* @__PURE__ */ action(
|
|
313
431
|
{ op: "applyBarHighlight", description: "Apply selected bar appearance." },
|
|
314
432
|
function (args = {}) {
|
|
315
433
|
return applyRectangularHighlight(this, args, "applyBarHighlight", "bar");
|
|
316
434
|
}
|
|
317
435
|
);
|
|
318
436
|
|
|
319
|
-
export const applyRectHighlight = action(
|
|
437
|
+
export const applyRectHighlight = /* @__PURE__ */ action(
|
|
320
438
|
{ op: "applyRectHighlight", description: "Apply selected rect appearance." },
|
|
321
439
|
function (args = {}) {
|
|
322
440
|
return applyRectangularHighlight(
|
|
@@ -329,10 +447,9 @@ export const applyRectHighlight = action(
|
|
|
329
447
|
}
|
|
330
448
|
);
|
|
331
449
|
|
|
332
|
-
export const applyPathHighlight =
|
|
333
|
-
{ op: "applyPathHighlight", description: "Apply selected line or area path appearance and offset." },
|
|
450
|
+
export const applyPathHighlight = /* @__PURE__ */ closedAction(
|
|
451
|
+
{ op: "applyPathHighlight", description: "Apply selected line or area path appearance and offset." }, INTERNAL_SELECTION_OPTIONS,
|
|
334
452
|
function (args = {}) {
|
|
335
|
-
validateKeys(args, INTERNAL_SELECTION_OPTIONS, "applyPathHighlight");
|
|
336
453
|
const resolved = resolveStoredSelection(this, args.selection);
|
|
337
454
|
const keys = selectedKeys(args, resolved);
|
|
338
455
|
const markType = resolved.items[0]?.markType;
|
|
@@ -350,10 +467,9 @@ export const applyPathHighlight = action(
|
|
|
350
467
|
}
|
|
351
468
|
);
|
|
352
469
|
|
|
353
|
-
export const applyRuleHighlight =
|
|
354
|
-
{ op: "applyRuleHighlight", description: "Apply selected rule appearance and offset." },
|
|
470
|
+
export const applyRuleHighlight = /* @__PURE__ */ closedAction(
|
|
471
|
+
{ op: "applyRuleHighlight", description: "Apply selected rule appearance and offset." }, INTERNAL_SELECTION_OPTIONS,
|
|
355
472
|
function (args = {}) {
|
|
356
|
-
validateKeys(args, INTERNAL_SELECTION_OPTIONS, "applyRuleHighlight");
|
|
357
473
|
const resolved = resolveStoredSelection(this, args.selection);
|
|
358
474
|
const keys = selectedKeys(args, resolved);
|
|
359
475
|
if (
|
|
@@ -370,10 +486,9 @@ export const applyRuleHighlight = action(
|
|
|
370
486
|
}
|
|
371
487
|
);
|
|
372
488
|
|
|
373
|
-
export const dimUnselectedMarkItems =
|
|
374
|
-
{ op: "dimUnselectedMarkItems", description: "Dim the complement of one mark selection." },
|
|
489
|
+
export const dimUnselectedMarkItems = /* @__PURE__ */ closedAction(
|
|
490
|
+
{ op: "dimUnselectedMarkItems", description: "Dim the complement of one mark selection." }, INTERNAL_DIM_OPTIONS,
|
|
375
491
|
function (args = {}) {
|
|
376
|
-
validateKeys(args, INTERNAL_DIM_OPTIONS, "dimUnselectedMarkItems");
|
|
377
492
|
const opacity = validateUnitInterval(args.opacity, "Dim opacity");
|
|
378
493
|
const resolved = resolveStoredSelection(this, args.selection);
|
|
379
494
|
const keys = selectedKeys(args, resolved);
|
|
@@ -384,10 +499,9 @@ export const dimUnselectedMarkItems = action(
|
|
|
384
499
|
}
|
|
385
500
|
);
|
|
386
501
|
|
|
387
|
-
export const placeSelectedMarkItemsLast =
|
|
388
|
-
{ op: "placeSelectedMarkItemsLast", description: "Place selected collection items after their complement." },
|
|
502
|
+
export const placeSelectedMarkItemsLast = /* @__PURE__ */ closedAction(
|
|
503
|
+
{ op: "placeSelectedMarkItemsLast", description: "Place selected collection items after their complement." }, INTERNAL_ORDER_OPTIONS,
|
|
389
504
|
function (args = {}) {
|
|
390
|
-
validateKeys(args, INTERNAL_ORDER_OPTIONS, "placeSelectedMarkItemsLast");
|
|
391
505
|
const resolved = resolveStoredSelection(this, args.selection);
|
|
392
506
|
const keys = selectedKeys(args, resolved);
|
|
393
507
|
if (keys.length === 0 || keys.length === resolved.items.length) {
|
|
@@ -405,17 +519,16 @@ export const placeSelectedMarkItemsLast = action(
|
|
|
405
519
|
}
|
|
406
520
|
);
|
|
407
521
|
|
|
408
|
-
export const rematerializeMarkHighlights =
|
|
409
|
-
{ op: "rematerializeMarkHighlights", description: "Reapply stored highlight assignments to one rematerialized mark." },
|
|
522
|
+
export const rematerializeMarkHighlights = /* @__PURE__ */ closedAction(
|
|
523
|
+
{ op: "rematerializeMarkHighlights", description: "Reapply stored highlight assignments to one rematerialized mark." }, REMATERIALIZE_OPTIONS,
|
|
410
524
|
function (args = {}) {
|
|
411
|
-
validateKeys(args, REMATERIALIZE_OPTIONS, "rematerializeMarkHighlights");
|
|
412
525
|
validateUserId(args.target, "Highlight target id");
|
|
413
526
|
if (!Array.isArray(args.highlights)) {
|
|
414
527
|
throw new TypeError("rematerializeMarkHighlights requires highlight entries.");
|
|
415
528
|
}
|
|
416
529
|
const prepared = args.highlights.map(([id, config]) => ({
|
|
417
530
|
id,
|
|
418
|
-
config,
|
|
531
|
+
config: normalizeStoredHighlightConfig(this, id, config),
|
|
419
532
|
keys: resolveStoredSelection(this, config.selection).keys
|
|
420
533
|
}));
|
|
421
534
|
let next = this;
|
|
@@ -430,10 +543,9 @@ export const rematerializeMarkHighlights = action(
|
|
|
430
543
|
}
|
|
431
544
|
);
|
|
432
545
|
|
|
433
|
-
export const highlightMarks =
|
|
434
|
-
{ op: "highlightMarks", description: "Select and emphasize final visual mark items." },
|
|
546
|
+
export const highlightMarks = /* @__PURE__ */ closedAction(
|
|
547
|
+
{ op: "highlightMarks", description: "Select and emphasize final visual mark items." }, HIGHLIGHT_OPTIONS,
|
|
435
548
|
function (args = {}) {
|
|
436
|
-
validateKeys(args, HIGHLIGHT_OPTIONS, "highlightMarks");
|
|
437
549
|
if (args.select !== undefined && args.selection !== undefined) {
|
|
438
550
|
throw new Error("highlightMarks accepts select or selection, not both.");
|
|
439
551
|
}
|
|
@@ -492,6 +604,7 @@ export const highlightMarks = action(
|
|
|
492
604
|
selection,
|
|
493
605
|
markType: layer.mark.type,
|
|
494
606
|
style,
|
|
607
|
+
paintSource: requestedPaintSource(args, layer.mark.type, style),
|
|
495
608
|
dimOthers,
|
|
496
609
|
bringToFront
|
|
497
610
|
};
|
|
@@ -9,12 +9,15 @@ import {
|
|
|
9
9
|
highlightMarks,
|
|
10
10
|
placeSelectedMarkItemsLast,
|
|
11
11
|
rematerializeMarkHighlights,
|
|
12
|
+
rematerializeThemeHighlights,
|
|
12
13
|
removeMarkHighlight,
|
|
13
14
|
removeMarkSelection,
|
|
14
15
|
selectMarks
|
|
15
16
|
} from "./actions.js";
|
|
17
|
+
import { registerThemeHighlightReconciler } from "../theme/reconcile.js";
|
|
16
18
|
|
|
17
19
|
export function registerSelectionActions(ProgramClass) {
|
|
20
|
+
registerThemeHighlightReconciler(rematerializeThemeHighlights);
|
|
18
21
|
ProgramClass.prototype.selectMarks = selectMarks;
|
|
19
22
|
ProgramClass.prototype.editMarkSelection = editMarkSelection;
|
|
20
23
|
ProgramClass.prototype.removeMarkHighlight = removeMarkHighlight;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { action, closedAction } from "../../core/action.js";
|
|
2
|
+
import { noOptions } from "../../core/validation.js";
|
|
3
|
+
import { normalizeTextMetricProfile } from "../../core/textMetricProfile.js";
|
|
4
|
+
import { rematerializeTypography } from "../../materialization/typography.js";
|
|
5
|
+
|
|
6
|
+
function metricsProgram(parent, child) {
|
|
7
|
+
return typeof child.applyTextMetrics === "function" ? child : new parent.constructor({
|
|
8
|
+
...child, actionSequence: child._actionSequence
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function inheritTextMetrics(parent, child) {
|
|
13
|
+
const profile = parent.materializationConfigs.textMetrics;
|
|
14
|
+
return profile === undefined ? child : metricsProgram(parent, child).applyTextMetrics({ profile });
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function applyProfile(program, profile) {
|
|
18
|
+
let next = profile === undefined
|
|
19
|
+
? program._withoutMaterializationConfig(["textMetrics"])
|
|
20
|
+
: program._withMaterializationConfig(["textMetrics"], profile);
|
|
21
|
+
if (next.compositionSpec !== undefined) {
|
|
22
|
+
const children = Object.fromEntries(next.compositionSpec.children.map(id => {
|
|
23
|
+
const child = next.children[id];
|
|
24
|
+
return [id, profile === undefined
|
|
25
|
+
? child.materializationConfigs.textMetrics === undefined ? child : metricsProgram(next, child).removeTextMetrics()
|
|
26
|
+
: inheritTextMetrics(next, child)];
|
|
27
|
+
}));
|
|
28
|
+
next = next._withCompositionState({ children, compositionSpec: next.compositionSpec });
|
|
29
|
+
for (const id of next.compositionSpec.children) next = next.useProgram({ id });
|
|
30
|
+
return next.materializeComposition();
|
|
31
|
+
}
|
|
32
|
+
return rematerializeTypography(next);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export const applyTextMetrics = /* @__PURE__ */ closedAction(
|
|
36
|
+
{ op: "applyTextMetrics", description: "Apply measured text widths to chart layout.", scope: "any" }, ["profile"],
|
|
37
|
+
function (args = {}) {
|
|
38
|
+
const profile = normalizeTextMetricProfile(args.profile);
|
|
39
|
+
applyProfile(this, profile);
|
|
40
|
+
return applyProfile(this, profile);
|
|
41
|
+
}
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
export const removeTextMetrics = /* @__PURE__ */ action(
|
|
45
|
+
{ op: "removeTextMetrics", description: "Restore estimated text layout.", scope: "any" },
|
|
46
|
+
function (args = {}) {
|
|
47
|
+
noOptions(args, "removeTextMetrics");
|
|
48
|
+
if (this.materializationConfigs.textMetrics === undefined) throw new Error("removeTextMetrics requires an active profile.");
|
|
49
|
+
applyProfile(this, undefined);
|
|
50
|
+
return applyProfile(this, undefined);
|
|
51
|
+
}
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
export function registerTextMetricActions(ProgramClass) {
|
|
55
|
+
Object.assign(ProgramClass.prototype, { applyTextMetrics, removeTextMetrics });
|
|
56
|
+
}
|
|
@@ -1,43 +1,98 @@
|
|
|
1
1
|
import { action } from "../../core/action.js";
|
|
2
2
|
import { noOptions, validateOptionObject } from "../../core/validation.js";
|
|
3
|
-
import {
|
|
3
|
+
import { normalizeThemeDefinition } from "../../theme/defaults.js";
|
|
4
|
+
import {
|
|
5
|
+
LOCAL_THEME_OWNER,
|
|
6
|
+
createThemeFrame,
|
|
7
|
+
moveLocalThemeScope,
|
|
8
|
+
normalizeThemeState,
|
|
9
|
+
removeThemeFrameOwner,
|
|
10
|
+
upsertThemeFrame
|
|
11
|
+
} from "./state.js";
|
|
4
12
|
|
|
5
|
-
|
|
13
|
+
let compositionThemeHandlers;
|
|
14
|
+
|
|
15
|
+
export function registerCompositionThemeHandlers(handlers) {
|
|
16
|
+
if (handlers === undefined ||
|
|
17
|
+
typeof handlers.apply !== "function" ||
|
|
18
|
+
typeof handlers.remove !== "function") {
|
|
19
|
+
throw new TypeError("Composition theme handlers must provide apply and remove functions.");
|
|
20
|
+
}
|
|
21
|
+
compositionThemeHandlers = handlers;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function requireCompositionThemeHandlers() {
|
|
25
|
+
if (compositionThemeHandlers === undefined) {
|
|
26
|
+
throw new Error("Composition theme actions are unavailable from this entry point.");
|
|
27
|
+
}
|
|
28
|
+
return compositionThemeHandlers;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export const applyTheme = /* @__PURE__ */ action(
|
|
6
32
|
{
|
|
7
33
|
op: "applyTheme",
|
|
8
|
-
description: "Apply persistent visual defaults to the chart program."
|
|
34
|
+
description: "Apply persistent visual defaults to the chart program.",
|
|
35
|
+
scope: "any"
|
|
9
36
|
},
|
|
10
37
|
function (args = {}) {
|
|
11
|
-
validateOptionObject(args, ["theme"], "applyTheme", {
|
|
38
|
+
validateOptionObject(args, ["theme", "scope"], "applyTheme", {
|
|
12
39
|
allowEmpty: false,
|
|
13
40
|
emptyMessage: "applyTheme requires theme.",
|
|
14
41
|
emptyError: Error
|
|
15
42
|
});
|
|
16
|
-
if (!
|
|
17
|
-
throw new Error(
|
|
43
|
+
if (!Object.hasOwn(args, "theme")) {
|
|
44
|
+
throw new Error("applyTheme requires theme.");
|
|
18
45
|
}
|
|
19
|
-
const
|
|
46
|
+
const definition = normalizeThemeDefinition(args.theme);
|
|
47
|
+
if (args.scope !== undefined &&
|
|
48
|
+
!["self", "descendants"].includes(args.scope)) {
|
|
49
|
+
throw new Error(`Unsupported theme scope "${args.scope}".`);
|
|
50
|
+
}
|
|
51
|
+
if (this.compositionSpec !== undefined) {
|
|
52
|
+
return requireCompositionThemeHandlers().apply(
|
|
53
|
+
this,
|
|
54
|
+
{ base: definition.name, tokens: definition.tokens },
|
|
55
|
+
args.scope ?? "descendants"
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
const scope = "self";
|
|
59
|
+
const previous = normalizeThemeState(this.materializationConfigs.theme);
|
|
60
|
+
const frame = createThemeFrame({
|
|
61
|
+
owner: LOCAL_THEME_OWNER,
|
|
62
|
+
scope,
|
|
63
|
+
definition: { base: definition.name, tokens: definition.tokens }
|
|
64
|
+
});
|
|
20
65
|
return this._withMaterializationConfig(["theme"], {
|
|
21
|
-
|
|
22
|
-
|
|
66
|
+
...previous,
|
|
67
|
+
frames: upsertThemeFrame(previous.frames, frame),
|
|
68
|
+
localOrder: moveLocalThemeScope(previous.localOrder, scope)
|
|
23
69
|
});
|
|
24
70
|
}
|
|
25
71
|
);
|
|
26
72
|
|
|
27
|
-
export const removeTheme = action(
|
|
73
|
+
export const removeTheme = /* @__PURE__ */ action(
|
|
28
74
|
{
|
|
29
75
|
op: "removeTheme",
|
|
30
|
-
description: "Remove program theme defaults while preserving local styles."
|
|
76
|
+
description: "Remove program theme defaults while preserving local styles.",
|
|
77
|
+
scope: "any"
|
|
31
78
|
},
|
|
32
79
|
function (args = {}) {
|
|
33
80
|
noOptions(args, "removeTheme");
|
|
34
|
-
if (this.
|
|
81
|
+
if (this.compositionSpec !== undefined) {
|
|
82
|
+
return requireCompositionThemeHandlers().remove(this);
|
|
83
|
+
}
|
|
84
|
+
const previous = normalizeThemeState(this.materializationConfigs.theme);
|
|
85
|
+
const removed = removeThemeFrameOwner(
|
|
86
|
+
previous.frames,
|
|
87
|
+
LOCAL_THEME_OWNER
|
|
88
|
+
);
|
|
89
|
+
if (!removed.removed) {
|
|
35
90
|
throw new Error("removeTheme requires an active program theme.");
|
|
36
91
|
}
|
|
37
92
|
return this._withMaterializationConfig(["theme"], {
|
|
38
|
-
...
|
|
39
|
-
|
|
40
|
-
|
|
93
|
+
...previous,
|
|
94
|
+
frames: removed.frames,
|
|
95
|
+
localOrder: previous.localOrder.filter(scope => scope !== "self")
|
|
41
96
|
});
|
|
42
97
|
}
|
|
43
98
|
);
|