ggaction 0.0.13 → 0.0.15
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 +78 -0
- package/README.md +20 -11
- package/knowledge/action-cards.json +1 -1
- package/knowledge/intent-taxonomy.json +1 -1
- package/knowledge/mcp-resources.json +1 -1
- package/package.json +8 -3
- package/src/actions/basic.js +2 -2
- package/src/actions/boxPlots/components.js +14 -4
- package/src/actions/boxPlots/edit.js +31 -5
- package/src/actions/boxPlots/materialize.js +11 -3
- package/src/actions/boxPlots/options.js +48 -16
- package/src/actions/categoryOrder/index.js +15 -4
- package/src/actions/charts/area.js +5 -1
- package/src/actions/charts/bar.js +2 -1
- package/src/actions/charts/density.js +6 -2
- package/src/actions/charts/ecdf.js +4 -1
- package/src/actions/charts/endpoints.js +25 -3
- package/src/actions/charts/heatmap.js +2 -1
- package/src/actions/charts/histogram.js +4 -3
- package/src/actions/charts/horizon.js +3 -1
- package/src/actions/charts/interval-regression.js +5 -2
- package/src/actions/charts/line.js +3 -1
- package/src/actions/charts/parallel.js +8 -2
- package/src/actions/charts/pie.js +10 -2
- package/src/actions/charts/polar.js +15 -4
- package/src/actions/charts/radar.js +8 -2
- package/src/actions/charts/radial.js +10 -2
- package/src/actions/charts/rug-strip.js +6 -2
- package/src/actions/charts/scatter.js +3 -1
- package/src/actions/composition/actions.js +13 -4
- package/src/actions/coordinates/actions.js +1 -1
- package/src/actions/coordinates/edit.js +76 -0
- package/src/actions/data/bin.js +1 -1
- package/src/actions/data/bin2d.js +57 -185
- package/src/actions/data/complete.js +26 -0
- package/src/actions/data/computed.js +2 -2
- package/src/actions/data/create.js +2 -2
- package/src/actions/data/density.js +12 -20
- package/src/actions/data/derived.js +47 -17
- package/src/actions/data/edit.js +539 -0
- package/src/actions/data/filter.js +14 -2
- package/src/actions/data/impute.js +26 -0
- package/src/actions/data/index.js +14 -0
- package/src/actions/data/normalize.js +27 -0
- package/src/actions/data/regression.js +16 -21
- package/src/actions/data/revisionBindings.js +145 -0
- package/src/actions/data/shared.js +20 -4
- package/src/actions/data/summary.js +1 -1
- package/src/actions/data/timeUnit.js +4 -1
- package/src/actions/data/window.js +1 -1
- package/src/actions/encodings/channels.js +415 -0
- package/src/actions/encodings/color/index.js +2 -1
- package/src/actions/encodings/density.js +5 -2
- package/src/actions/encodings/histogram.js +3 -2
- package/src/actions/encodings/index.js +4 -0
- package/src/actions/encodings/offset.js +20 -13
- package/src/actions/encodings/position/apply.js +53 -7
- package/src/actions/encodings/position/index.js +10 -2
- package/src/actions/encodings/position/policies/bar.js +9 -0
- package/src/actions/encodings/position/resolve.js +24 -7
- package/src/actions/encodings/remove.js +9 -4
- package/src/actions/encodings/ruleAppearance.js +1 -23
- package/src/actions/encodings/seriesLayout.js +1 -0
- package/src/actions/encodings/shared.js +82 -14
- package/src/actions/encodings/stroke.js +226 -0
- package/src/actions/errorBands/create.js +23 -3
- package/src/actions/errorBands/edit.js +21 -6
- package/src/actions/errorBars/create.js +35 -7
- package/src/actions/errorBars/edit.js +19 -4
- package/src/actions/facets/actions.js +237 -57
- package/src/actions/facets/derive.js +91 -26
- package/src/actions/gradientPlots/components.js +10 -2
- package/src/actions/gradientPlots/edit.js +14 -4
- package/src/actions/gradientPlots/materialize.js +3 -1
- package/src/actions/gradientPlots/options.js +10 -2
- package/src/actions/guides/applicability.js +8 -2
- package/src/actions/guides/axes/labels.js +58 -12
- package/src/actions/guides/axes/lines.js +6 -2
- package/src/actions/guides/axes/parallel/resolve.js +6 -2
- package/src/actions/guides/axes/tickGroups.js +2 -1
- package/src/actions/guides/axes/ticks.js +6 -2
- package/src/actions/guides/axes/titles.js +11 -3
- package/src/actions/guides/grids/resolve.js +7 -2
- package/src/actions/guides/guides.js +19 -3
- package/src/actions/guides/legends/blocks.js +426 -0
- package/src/actions/guides/legends/categorical/actions.js +134 -48
- package/src/actions/guides/legends/categorical/components.js +17 -12
- package/src/actions/guides/legends/categorical/index.js +37 -33
- package/src/actions/guides/legends/categorical/layout.js +97 -15
- 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 +85 -30
- package/src/actions/guides/legends/continuous/common.js +30 -12
- package/src/actions/guides/legends/continuous/gradient.js +10 -7
- package/src/actions/guides/legends/continuous/index.js +2 -0
- package/src/actions/guides/legends/continuous/interval.js +8 -3
- package/src/actions/guides/legends/continuous/opacity.js +8 -5
- package/src/actions/guides/legends/continuous/stroke.js +525 -0
- package/src/actions/guides/legends/creation.js +14 -1
- package/src/actions/guides/legends/edit.js +158 -59
- package/src/actions/guides/legends/index.js +2 -0
- package/src/actions/guides/legends/lane.js +54 -19
- package/src/actions/guides/legends/lifecycle.js +19 -8
- package/src/actions/guides/legends/remove.js +13 -3
- package/src/actions/guides/legends/sampling.js +140 -0
- package/src/actions/guides/legends/size.js +93 -40
- package/src/actions/guides/legends/strokeWidth.js +34 -28
- 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 +4 -4
- package/src/actions/guides/polar/axes/labels.js +24 -5
- package/src/actions/guides/polar/axes/lines.js +10 -4
- package/src/actions/guides/polar/axes/shared.js +16 -0
- package/src/actions/guides/polar/axes/ticks.js +1 -1
- package/src/actions/guides/polar/axes/titles.js +1 -1
- package/src/actions/guides/polar/grids.js +1 -1
- package/src/actions/guides/polar/resolve.js +12 -8
- package/src/actions/index.js +14 -3
- package/src/actions/marks/arc/actions.js +77 -19
- package/src/actions/marks/area/actions.js +34 -9
- package/src/actions/marks/area/materialize.js +17 -1
- package/src/actions/marks/bar/create.js +11 -2
- package/src/actions/marks/bar/edit.js +20 -3
- package/src/actions/marks/bar/materialize.js +22 -2
- package/src/actions/marks/index.js +10 -1
- package/src/actions/marks/line/actions.js +37 -14
- package/src/actions/marks/line/materialize.js +29 -10
- package/src/actions/marks/point/create.js +8 -2
- package/src/actions/marks/point/edit.js +18 -6
- package/src/actions/marks/point/materialize.js +49 -15
- package/src/actions/marks/rect/actions.js +33 -12
- package/src/actions/marks/references.js +601 -30
- package/src/actions/marks/remove.js +71 -1
- package/src/actions/marks/rule/actions.js +47 -10
- package/src/actions/marks/shared.js +1 -1
- package/src/actions/marks/text/actions.js +74 -9
- package/src/actions/marks/text/index.js +4 -0
- package/src/actions/marks/text/layout.js +154 -6
- package/src/actions/marks/text/removal.js +173 -0
- package/src/actions/marks/text/selection.js +73 -0
- package/src/actions/marks/tick/actions.js +22 -5
- package/src/actions/primitives/editGraphics.js +26 -0
- package/src/actions/primitives/semantic.js +2 -1
- package/src/actions/primitives/semanticAction.js +83 -10
- 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 +26 -11
- package/src/actions/regression/create.js +10 -2
- package/src/actions/regression/edit.js +21 -7
- package/src/actions/resources/index.js +7 -0
- package/src/actions/resources/remove.js +172 -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 +54 -22
- package/src/actions/scales/definitions.js +94 -40
- package/src/actions/scales/edit.js +66 -11
- package/src/actions/scales/editPolicy.js +81 -11
- package/src/actions/scales/index.js +6 -0
- package/src/actions/scales/materialize.js +4 -3
- 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/selection/actions.js +154 -30
- package/src/actions/selection/index.js +3 -0
- package/src/actions/theme/actions.js +68 -13
- package/src/actions/theme/composition.js +238 -0
- package/src/actions/theme/index.js +9 -2
- package/src/actions/theme/reconcile.js +315 -67
- package/src/actions/theme/state.js +160 -0
- package/src/actions/violinPlots/create.js +5 -2
- package/src/actions/violinPlots/edit.js +1 -0
- package/src/core/action.js +10 -0
- package/src/core/compositionState.js +6 -1
- package/src/core/programState.js +20 -0
- package/src/core/resourceReferences.js +332 -0
- package/src/core/vocabulary.js +16 -3
- 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 +340 -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/schemas/concreteGraphic.js +14 -2
- package/src/grammar/schemas/graphic.js +15 -0
- package/src/grammar/schemas/graphicBounds.js +179 -30
- 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 +343 -0
- 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 +8 -2
- package/src/materialization/facetGuides/preparation.js +12 -7
- package/src/materialization/facetHeaders.js +346 -0
- package/src/materialization/facets.js +15 -65
- 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/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 +19 -4
- 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/renderers/canvas/circle.js +2 -3
- 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/svg.js +19 -0
- package/src/selectors/datasets.js +32 -1
- package/src/selectors/layers.js +4 -0
- package/src/theme/defaults.js +101 -0
- package/types/basic.d.ts +6 -0
- package/types/index.d.ts +85 -0
- package/types/program.d.ts +910 -117
|
@@ -2,7 +2,9 @@ import { action } 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,6 +224,60 @@ function applyHighlight(program, config, keys) {
|
|
|
172
224
|
: next;
|
|
173
225
|
}
|
|
174
226
|
|
|
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
|
+
|
|
175
281
|
export const selectMarks = action(
|
|
176
282
|
{ op: "selectMarks", description: "Create one reusable selection over final mark items." },
|
|
177
283
|
function (args = {}) {
|
|
@@ -198,7 +304,7 @@ export const editMarkSelection = action(
|
|
|
198
304
|
current.definition.target,
|
|
199
305
|
selectorFrom(args)
|
|
200
306
|
);
|
|
201
|
-
|
|
307
|
+
let next = this
|
|
202
308
|
._withSelectionConfig(current.id, {
|
|
203
309
|
target: current.definition.target,
|
|
204
310
|
selector: replacement.selector
|
|
@@ -207,9 +313,15 @@ export const editMarkSelection = action(
|
|
|
207
313
|
const hasDependentHighlight = Object.values(
|
|
208
314
|
next.materializationConfigs.highlights ?? {}
|
|
209
315
|
).some(config => config.selection === current.id);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
316
|
+
const labels = namedLabelDependents(this, current.id);
|
|
317
|
+
if (hasDependentHighlight) {
|
|
318
|
+
return rematerializeLabelsBeforeHighlights(
|
|
319
|
+
next,
|
|
320
|
+
current.definition.target,
|
|
321
|
+
labels
|
|
322
|
+
);
|
|
323
|
+
}
|
|
324
|
+
return rematerializeLabels(next, labels);
|
|
213
325
|
}
|
|
214
326
|
);
|
|
215
327
|
|
|
@@ -245,6 +357,12 @@ export const removeMarkSelection = action(
|
|
|
245
357
|
function (args = {}) {
|
|
246
358
|
validateKeys(args, REMOVE_SELECTION_OPTIONS, "removeMarkSelection");
|
|
247
359
|
const current = resolveStoredSelection(this, args.selection);
|
|
360
|
+
const labelDependents = namedLabelDependents(this, current.id);
|
|
361
|
+
if (labelDependents.length > 0) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`Selection "${current.id}" is referenced by attached labels: ${labelDependents.join(", ")}.`
|
|
364
|
+
);
|
|
365
|
+
}
|
|
248
366
|
const hasDependentHighlight = Object.values(
|
|
249
367
|
this.materializationConfigs.highlights ?? {}
|
|
250
368
|
).some(config => config.selection === current.id);
|
|
@@ -287,6 +405,15 @@ function transformRectangularProperties(properties, style, offset = false) {
|
|
|
287
405
|
};
|
|
288
406
|
}
|
|
289
407
|
|
|
408
|
+
function transformRectangularHighlightChild(item, style, offset) {
|
|
409
|
+
return {
|
|
410
|
+
...item,
|
|
411
|
+
properties: item.type === "path"
|
|
412
|
+
? transformPathHighlightProperties(item.properties, style)
|
|
413
|
+
: transformRectangularProperties(item.properties, style, offset)
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
290
417
|
function applyRectangularHighlight(
|
|
291
418
|
program,
|
|
292
419
|
args,
|
|
@@ -301,12 +428,8 @@ function applyRectangularHighlight(
|
|
|
301
428
|
throw new Error(`${operation} requires a ${markType} selection.`);
|
|
302
429
|
}
|
|
303
430
|
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
|
-
}));
|
|
431
|
+
return editSelectedItems(program, resolved, keys, item =>
|
|
432
|
+
transformRectangularHighlightChild(item, args.style, offset));
|
|
310
433
|
}
|
|
311
434
|
|
|
312
435
|
export const applyBarHighlight = action(
|
|
@@ -415,7 +538,7 @@ export const rematerializeMarkHighlights = action(
|
|
|
415
538
|
}
|
|
416
539
|
const prepared = args.highlights.map(([id, config]) => ({
|
|
417
540
|
id,
|
|
418
|
-
config,
|
|
541
|
+
config: normalizeStoredHighlightConfig(this, id, config),
|
|
419
542
|
keys: resolveStoredSelection(this, config.selection).keys
|
|
420
543
|
}));
|
|
421
544
|
let next = this;
|
|
@@ -492,6 +615,7 @@ export const highlightMarks = action(
|
|
|
492
615
|
selection,
|
|
493
616
|
markType: layer.mark.type,
|
|
494
617
|
style,
|
|
618
|
+
paintSource: requestedPaintSource(args, layer.mark.type, style),
|
|
495
619
|
dimOthers,
|
|
496
620
|
bringToFront
|
|
497
621
|
};
|
|
@@ -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;
|
|
@@ -1,25 +1,71 @@
|
|
|
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";
|
|
12
|
+
|
|
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
|
+
}
|
|
4
30
|
|
|
5
31
|
export const applyTheme = 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
|
);
|
|
@@ -27,17 +73,26 @@ export const applyTheme = action(
|
|
|
27
73
|
export const removeTheme = 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
|
);
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
import { freezeOwned } from "../../core/immutable.js";
|
|
2
|
+
import { materializeCompositionGraphics } from
|
|
3
|
+
"../../materialization/composition.js";
|
|
4
|
+
import { materializeFacetGraphics } from "../../materialization/facets.js";
|
|
5
|
+
import {
|
|
6
|
+
compositionThemeOwner,
|
|
7
|
+
createThemeFrame,
|
|
8
|
+
moveLocalThemeScope,
|
|
9
|
+
normalizeThemeState,
|
|
10
|
+
removeThemeFrameOwner,
|
|
11
|
+
upsertThemeFrame
|
|
12
|
+
} from "./state.js";
|
|
13
|
+
import { reconcileProgramTheme } from "./reconcile.js";
|
|
14
|
+
|
|
15
|
+
const DESCRIPTION = "Apply inherited visual defaults to a composition child.";
|
|
16
|
+
|
|
17
|
+
function materializeComposition(program) {
|
|
18
|
+
return program.compositionSpec.type === "facet"
|
|
19
|
+
? materializeFacetGraphics(program)
|
|
20
|
+
: materializeCompositionGraphics(program);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function withThemeState(program, state) {
|
|
24
|
+
return program._withMaterializationConfig(["theme"], state);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function addFrame(program, frame, { descendants, local = false }) {
|
|
28
|
+
const composition = program.compositionSpec !== undefined;
|
|
29
|
+
const previous = normalizeThemeState(
|
|
30
|
+
program.materializationConfigs.theme,
|
|
31
|
+
{ composition }
|
|
32
|
+
);
|
|
33
|
+
return withThemeState(program, {
|
|
34
|
+
...previous,
|
|
35
|
+
frames: upsertThemeFrame(previous.frames, frame),
|
|
36
|
+
...(composition
|
|
37
|
+
? {
|
|
38
|
+
descendantFrames: descendants
|
|
39
|
+
? upsertThemeFrame(previous.descendantFrames, frame)
|
|
40
|
+
: previous.descendantFrames
|
|
41
|
+
}
|
|
42
|
+
: {}),
|
|
43
|
+
localOrder: local
|
|
44
|
+
? moveLocalThemeScope(previous.localOrder, frame.scope)
|
|
45
|
+
: previous.localOrder
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function removeFrame(program, owner, { descendants, localScope }) {
|
|
50
|
+
const composition = program.compositionSpec !== undefined;
|
|
51
|
+
const previous = normalizeThemeState(
|
|
52
|
+
program.materializationConfigs.theme,
|
|
53
|
+
{ composition }
|
|
54
|
+
);
|
|
55
|
+
const root = removeThemeFrameOwner(previous.frames, owner);
|
|
56
|
+
const policies = composition && descendants
|
|
57
|
+
? removeThemeFrameOwner(previous.descendantFrames, owner)
|
|
58
|
+
: { frames: previous.descendantFrames, removed: false };
|
|
59
|
+
return {
|
|
60
|
+
program: withThemeState(program, {
|
|
61
|
+
...previous,
|
|
62
|
+
frames: root.frames,
|
|
63
|
+
...(composition ? { descendantFrames: policies.frames } : {}),
|
|
64
|
+
localOrder: localScope === undefined
|
|
65
|
+
? previous.localOrder
|
|
66
|
+
: freezeOwned(previous.localOrder.filter(scope => scope !== localScope))
|
|
67
|
+
}),
|
|
68
|
+
removed: root.removed || policies.removed
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function inheritedMetadata(op) {
|
|
73
|
+
return freezeOwned({ op, description: DESCRIPTION, scope: "any" });
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function enterInheritedAction(program, op, frame) {
|
|
77
|
+
return program._enterAction({
|
|
78
|
+
op,
|
|
79
|
+
description: DESCRIPTION,
|
|
80
|
+
args: op === "applyTheme"
|
|
81
|
+
? freezeOwned({
|
|
82
|
+
theme: freezeOwned({
|
|
83
|
+
base: frame.name,
|
|
84
|
+
tokens: frame.tokens
|
|
85
|
+
}),
|
|
86
|
+
scope: "descendants",
|
|
87
|
+
inheritedFrom: frame.owner
|
|
88
|
+
})
|
|
89
|
+
: freezeOwned({ inheritedFrom: frame.owner })
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function applyInheritedFrame(program, frame) {
|
|
94
|
+
const source = program;
|
|
95
|
+
let next = enterInheritedAction(program, "applyTheme", frame);
|
|
96
|
+
next = addFrame(next, frame, {
|
|
97
|
+
descendants: next.compositionSpec !== undefined
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
if (next.compositionSpec !== undefined) {
|
|
101
|
+
const children = Object.fromEntries(
|
|
102
|
+
next.compositionSpec.children.map(id => [
|
|
103
|
+
id,
|
|
104
|
+
applyInheritedFrame(next.children[id], frame)
|
|
105
|
+
])
|
|
106
|
+
);
|
|
107
|
+
next = next._withCompositionState({
|
|
108
|
+
children,
|
|
109
|
+
compositionSpec: next.compositionSpec
|
|
110
|
+
});
|
|
111
|
+
next = materializeComposition(next);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
next = reconcileProgramTheme(next, {
|
|
115
|
+
source,
|
|
116
|
+
metadata: inheritedMetadata("applyTheme")
|
|
117
|
+
});
|
|
118
|
+
return next._exitAction();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function removeInheritedFrame(program, frame) {
|
|
122
|
+
const source = program;
|
|
123
|
+
let next = enterInheritedAction(program, "removeTheme", frame);
|
|
124
|
+
const removed = removeFrame(next, frame.owner, {
|
|
125
|
+
descendants: next.compositionSpec !== undefined
|
|
126
|
+
});
|
|
127
|
+
next = removed.program;
|
|
128
|
+
|
|
129
|
+
if (next.compositionSpec !== undefined) {
|
|
130
|
+
const children = Object.fromEntries(
|
|
131
|
+
next.compositionSpec.children.map(id => [
|
|
132
|
+
id,
|
|
133
|
+
removeInheritedFrame(next.children[id], frame)
|
|
134
|
+
])
|
|
135
|
+
);
|
|
136
|
+
next = next._withCompositionState({
|
|
137
|
+
children,
|
|
138
|
+
compositionSpec: next.compositionSpec
|
|
139
|
+
});
|
|
140
|
+
next = materializeComposition(next);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
next = reconcileProgramTheme(next, {
|
|
144
|
+
source,
|
|
145
|
+
metadata: inheritedMetadata("removeTheme")
|
|
146
|
+
});
|
|
147
|
+
return next._exitAction();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function applyCompositionTheme(program, definition, scope) {
|
|
151
|
+
const id = program.compositionSpec.id;
|
|
152
|
+
const frame = createThemeFrame({
|
|
153
|
+
owner: compositionThemeOwner(id, scope),
|
|
154
|
+
scope,
|
|
155
|
+
definition
|
|
156
|
+
});
|
|
157
|
+
let next = addFrame(program, frame, {
|
|
158
|
+
descendants: scope === "descendants",
|
|
159
|
+
local: true
|
|
160
|
+
});
|
|
161
|
+
if (scope !== "descendants") return next;
|
|
162
|
+
|
|
163
|
+
const children = Object.fromEntries(
|
|
164
|
+
next.compositionSpec.children.map(childId => [
|
|
165
|
+
childId,
|
|
166
|
+
applyInheritedFrame(next.children[childId], frame)
|
|
167
|
+
])
|
|
168
|
+
);
|
|
169
|
+
next = next._withCompositionState({
|
|
170
|
+
children,
|
|
171
|
+
compositionSpec: next.compositionSpec
|
|
172
|
+
});
|
|
173
|
+
return materializeComposition(next);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function removeCompositionTheme(program) {
|
|
177
|
+
const state = normalizeThemeState(
|
|
178
|
+
program.materializationConfigs.theme,
|
|
179
|
+
{ composition: true }
|
|
180
|
+
);
|
|
181
|
+
const scope = state.localOrder.at(-1);
|
|
182
|
+
if (scope === undefined) {
|
|
183
|
+
throw new Error("removeTheme requires an active program theme.");
|
|
184
|
+
}
|
|
185
|
+
const owner = compositionThemeOwner(program.compositionSpec.id, scope);
|
|
186
|
+
const frame = state.frames.find(current => current.owner === owner) ??
|
|
187
|
+
state.descendantFrames.find(current => current.owner === owner);
|
|
188
|
+
if (frame === undefined) {
|
|
189
|
+
throw new Error("removeTheme requires an active program theme.");
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
let next = removeFrame(program, owner, {
|
|
193
|
+
descendants: scope === "descendants",
|
|
194
|
+
localScope: scope
|
|
195
|
+
}).program;
|
|
196
|
+
if (scope !== "descendants") return next;
|
|
197
|
+
|
|
198
|
+
const children = Object.fromEntries(
|
|
199
|
+
next.compositionSpec.children.map(id => [
|
|
200
|
+
id,
|
|
201
|
+
removeInheritedFrame(next.children[id], frame)
|
|
202
|
+
])
|
|
203
|
+
);
|
|
204
|
+
next = next._withCompositionState({
|
|
205
|
+
children,
|
|
206
|
+
compositionSpec: next.compositionSpec
|
|
207
|
+
});
|
|
208
|
+
return materializeComposition(next);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function replayCompositionThemeState(program, storedState) {
|
|
212
|
+
if (storedState === undefined) return program;
|
|
213
|
+
const state = normalizeThemeState(storedState, { composition: true });
|
|
214
|
+
let next = withThemeState(program, state);
|
|
215
|
+
for (const frame of state.descendantFrames) {
|
|
216
|
+
const children = Object.fromEntries(
|
|
217
|
+
next.compositionSpec.children.map(id => [
|
|
218
|
+
id,
|
|
219
|
+
applyInheritedFrame(next.children[id], frame)
|
|
220
|
+
])
|
|
221
|
+
);
|
|
222
|
+
next = next._withCompositionState({
|
|
223
|
+
children,
|
|
224
|
+
compositionSpec: next.compositionSpec
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
return materializeComposition(next);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export function replayInheritedThemeFrames(program, storedState) {
|
|
231
|
+
if (storedState === undefined) return program;
|
|
232
|
+
const state = normalizeThemeState(storedState, { composition: true });
|
|
233
|
+
let next = program;
|
|
234
|
+
for (const frame of state.descendantFrames) {
|
|
235
|
+
next = applyInheritedFrame(next, frame);
|
|
236
|
+
}
|
|
237
|
+
return next;
|
|
238
|
+
}
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
import { setActionCompletionHook } from "../../core/action.js";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
applyTheme,
|
|
4
|
+
registerCompositionThemeHandlers,
|
|
5
|
+
removeTheme
|
|
6
|
+
} from "./actions.js";
|
|
3
7
|
import { reconcileProgramTheme } from "./reconcile.js";
|
|
4
8
|
|
|
5
|
-
export function registerThemeActions(ProgramClass) {
|
|
9
|
+
export function registerThemeActions(ProgramClass, compositionHandlers) {
|
|
10
|
+
if (compositionHandlers !== undefined) {
|
|
11
|
+
registerCompositionThemeHandlers(compositionHandlers);
|
|
12
|
+
}
|
|
6
13
|
ProgramClass.prototype.applyTheme = applyTheme;
|
|
7
14
|
ProgramClass.prototype.removeTheme = removeTheme;
|
|
8
15
|
setActionCompletionHook(reconcileProgramTheme);
|