ggaction 0.0.23 → 0.0.26

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.
Files changed (228) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +2 -2
  3. package/knowledge/action-cards.json +1 -1
  4. package/knowledge/intent-taxonomy.json +1 -1
  5. package/knowledge/mcp-resources.json +1 -1
  6. package/knowledge/task-resolver.js +1 -1
  7. package/package.json +1 -1
  8. package/src/accessibility.js +13 -0
  9. package/src/actions/canvas/actions.js +2 -1
  10. package/src/actions/canvas/fitting.js +68 -13
  11. package/src/actions/charts/beeswarm.js +2 -1
  12. package/src/actions/charts/ecdf.js +2 -1
  13. package/src/actions/charts/endpoints.js +25 -16
  14. package/src/actions/charts/heatmap.js +6 -4
  15. package/src/actions/charts/missing.js +17 -0
  16. package/src/actions/charts/radar.js +70 -33
  17. package/src/actions/charts/raincloud.js +18 -4
  18. package/src/actions/charts/rug-strip.js +2 -2
  19. package/src/actions/charts/shared.js +17 -0
  20. package/src/actions/composition/actions.js +24 -7
  21. package/src/actions/composition/adjacent.js +90 -0
  22. package/src/actions/composition/index.js +11 -1
  23. package/src/actions/composition/layer.js +42 -0
  24. package/src/actions/composition/layerPlan.js +176 -0
  25. package/src/actions/composition/targets.js +105 -0
  26. package/src/actions/data/basicBin2d.js +1 -1
  27. package/src/actions/data/bin2d.js +2 -2
  28. package/src/actions/data/derived.js +3 -0
  29. package/src/actions/data/filter.js +1 -1
  30. package/src/actions/data/raincloudFilter.js +3 -1
  31. package/src/actions/encodings/appearance.js +26 -7
  32. package/src/actions/encodings/channels.js +1 -0
  33. package/src/actions/encodings/color/continuous.js +37 -34
  34. package/src/actions/encodings/color/index.js +57 -43
  35. package/src/actions/encodings/color/policy.js +15 -0
  36. package/src/actions/encodings/density/resolve.js +3 -2
  37. package/src/actions/encodings/density.js +2 -2
  38. package/src/actions/encodings/offset.js +2 -0
  39. package/src/actions/encodings/pathOrder.js +2 -0
  40. package/src/actions/encodings/position/areaAlignment.js +42 -0
  41. package/src/actions/encodings/position/index.js +37 -3
  42. package/src/actions/encodings/position/policies/line.js +1 -1
  43. package/src/actions/encodings/ranged.js +4 -2
  44. package/src/actions/encodings/remove.js +13 -10
  45. package/src/actions/encodings/ruleAppearance.js +14 -2
  46. package/src/actions/facets/actions.js +1 -1
  47. package/src/actions/guides/axes/axes.js +2 -1
  48. package/src/actions/guides/axes/components.js +5 -0
  49. package/src/actions/guides/axes/edit.js +1 -188
  50. package/src/actions/guides/axes/labels.js +2 -537
  51. package/src/actions/guides/axes/parallel/lifecycle.js +11 -4
  52. package/src/actions/guides/axes/parallel/policy.js +5 -2
  53. package/src/actions/guides/axes/parallel/resolve.js +3 -1
  54. package/src/actions/guides/axes/parallel.js +9 -4
  55. package/src/actions/guides/axes/tickGroups.js +16 -1
  56. package/src/actions/guides/axes/ticks.js +33 -24
  57. package/src/actions/guides/axes/titles.js +1 -389
  58. package/src/actions/guides/facadeLegend.js +3 -2
  59. package/src/actions/guides/grids/grid.js +3 -2
  60. package/src/actions/guides/grids/resolve.js +2 -1
  61. package/src/actions/guides/guides.js +3 -2
  62. package/src/actions/guides/legends/automatic.js +28 -0
  63. package/src/actions/guides/legends/blocks.js +15 -21
  64. package/src/actions/guides/legends/categorical/actions.js +1 -1
  65. package/src/actions/guides/legends/categorical/components.js +4 -3
  66. package/src/actions/guides/legends/categorical/layout.js +5 -2
  67. package/src/actions/guides/legends/categorical/options.js +9 -14
  68. package/src/actions/guides/legends/categorical/recipes.js +3 -0
  69. package/src/actions/guides/legends/categorical/resolve.js +7 -5
  70. package/src/actions/guides/legends/colorSize.js +51 -14
  71. package/src/actions/guides/legends/continuous/common.js +1 -1
  72. package/src/actions/guides/legends/continuous/gradient.js +1 -1
  73. package/src/actions/guides/legends/continuous/opacity.js +2 -0
  74. package/src/actions/guides/legends/edit.js +1 -1
  75. package/src/actions/guides/legends/focused.js +2 -2
  76. package/src/actions/guides/legends/group.js +1 -1
  77. package/src/actions/guides/legends/lane.js +1 -1
  78. package/src/actions/guides/legends/lifecycle.js +2 -2
  79. package/src/actions/guides/legends/remove.js +18 -4
  80. package/src/actions/guides/legends/size.js +1 -1
  81. package/src/actions/guides/legends/transition.js +15 -6
  82. package/src/actions/guides/polar/axes/facade.js +4 -2
  83. package/src/actions/guides/polar/axes/labels.js +6 -1
  84. package/src/actions/guides/polar/axes/shared.js +4 -4
  85. package/src/actions/guides/polar/axes/titles.js +13 -2
  86. package/src/actions/guides/polar/grids.js +6 -3
  87. package/src/actions/guides/tickValues.js +7 -1
  88. package/src/actions/index.js +2 -0
  89. package/src/actions/marks/area/actions.js +9 -2
  90. package/src/actions/marks/area/materialize.js +1 -1
  91. package/src/actions/marks/bar/materialize.js +4 -4
  92. package/src/actions/marks/lifecycle.js +14 -0
  93. package/src/actions/marks/line/actions.js +3 -0
  94. package/src/actions/marks/line/materialize.js +4 -2
  95. package/src/actions/marks/point/edit.js +2 -0
  96. package/src/actions/marks/point/jitter.js +2 -0
  97. package/src/actions/marks/point/materialize.js +5 -4
  98. package/src/actions/marks/point/packing.js +2 -0
  99. package/src/actions/marks/references.js +5 -3
  100. package/src/actions/marks/remove.js +16 -0
  101. package/src/actions/marks/shared.js +2 -1
  102. package/src/actions/marks/text/actions.js +5 -2
  103. package/src/actions/overlays/index.js +168 -0
  104. package/src/actions/overlays/snapshot.js +45 -0
  105. package/src/actions/primitives/editGraphics.js +21 -27
  106. package/src/actions/primitives/semanticAction.js +4 -5
  107. package/src/actions/primitives/semanticValidation/guide.js +1 -0
  108. package/src/actions/primitives/semanticValidation/layer.js +7 -0
  109. package/src/actions/scales/consumers/common.js +10 -0
  110. package/src/actions/scales/consumers/families.js +1 -1
  111. package/src/actions/scales/preview.js +1 -1
  112. package/src/actions/selection/actions.js +63 -11
  113. package/src/actions/titles/actions.js +3 -14
  114. package/src/actions/titles/resolve.js +23 -10
  115. package/src/core/action.js +41 -25
  116. package/src/core/compositionScales.js +12 -0
  117. package/src/core/compositionState.js +20 -3
  118. package/src/core/facetGap.js +44 -0
  119. package/src/core/immutable.js +11 -6
  120. package/src/core/programState.js +16 -0
  121. package/src/core/resourceReferences.js +19 -3
  122. package/src/core/validation.js +7 -0
  123. package/src/core/vocabulary.js +8 -2
  124. package/src/grammar/actionTargets.js +24 -0
  125. package/src/grammar/axisTextPlacement.js +1 -1
  126. package/src/grammar/bin2d.js +41 -4
  127. package/src/grammar/colorSizeLegend.js +56 -5
  128. package/src/grammar/displayLabels.js +10 -0
  129. package/src/grammar/facetHeaders.js +1 -1
  130. package/src/grammar/facets/dependencies.js +10 -3
  131. package/src/grammar/facets/guides.js +2 -1
  132. package/src/grammar/facets/legendIntent.js +7 -5
  133. package/src/grammar/legendBlocks.js +1 -1
  134. package/src/grammar/legendCombinations.js +1 -1
  135. package/src/grammar/legendGroups.js +1 -1
  136. package/src/grammar/legendItemsOffset.js +12 -0
  137. package/src/grammar/legendOverflow.js +25 -0
  138. package/src/grammar/lineSeries.js +1 -1
  139. package/src/grammar/markSelection.js +23 -0
  140. package/src/grammar/overlay.js +51 -0
  141. package/src/grammar/parallelCoordinates.js +1 -208
  142. package/src/grammar/pathCommands.js +8 -2
  143. package/src/grammar/pathSeries.js +1 -1
  144. package/src/grammar/plotComposition.js +152 -0
  145. package/src/grammar/pointShapes.js +18 -0
  146. package/src/grammar/scales/transformed.js +1 -1
  147. package/src/grammar/schemas/concreteGraphic.js +8 -1
  148. package/src/grammar/schemas/graphicBounds.js +8 -1
  149. package/src/grammar/schemas/graphicTree.js +18 -2
  150. package/src/grammar/schemas/semanticPath.js +3 -0
  151. package/src/grammar/strokeStyle.js +14 -8
  152. package/src/grammar/text.js +72 -0
  153. package/src/inspection.js +1 -1
  154. package/src/inspectionDescriptors.js +1 -1
  155. package/src/layout/composition.js +32 -10
  156. package/src/layout/compositionLegend.js +91 -0
  157. package/src/layout/facetContentFlow.js +15 -7
  158. package/src/layout/facetHeaderTitles.js +1 -1
  159. package/src/layout/facets.js +1 -1
  160. package/src/layout/labels.js +55 -27
  161. package/src/layout/legend.js +3 -2
  162. package/src/layout/legendGroup.js +1 -1
  163. package/src/layout/legendItems.js +7 -6
  164. package/src/layout/legendLane.js +1 -1
  165. package/src/layout/legendText.js +1 -1
  166. package/src/layout/title.js +1 -1
  167. package/src/materialization/adjacentSource.js +27 -0
  168. package/src/materialization/composition.js +165 -52
  169. package/src/materialization/compositionLegends.js +120 -0
  170. package/src/materialization/compositionScales.js +125 -0
  171. package/src/materialization/compositionTitle.js +96 -0
  172. package/src/materialization/facetGuides/edit.js +22 -2
  173. package/src/materialization/facetGuides/layout.js +1 -1
  174. package/src/materialization/facetGuides/owner.js +4 -3
  175. package/src/materialization/facetGuides/ownerLayout.js +12 -6
  176. package/src/materialization/facetGuides/placement.js +19 -22
  177. package/src/materialization/facetGuides/preparation.js +17 -5
  178. package/src/materialization/facetHeaders.js +5 -1
  179. package/src/materialization/facets.js +1 -1
  180. package/src/materialization/guides/layout.js +1 -1
  181. package/src/materialization/guides/resources.js +1 -1
  182. package/src/materialization/guides/visibility.js +105 -0
  183. package/src/materialization/legendClip.js +1 -1
  184. package/src/materialization/legendGroups.js +1 -1
  185. package/src/materialization/legendItemsOffset.js +68 -0
  186. package/src/materialization/legendSuppression.js +22 -0
  187. package/src/materialization/legends.js +3 -2
  188. package/src/materialization/marks/capabilities.js +4 -0
  189. package/src/materialization/marks/index.js +5 -1
  190. package/src/materialization/marks/pathOrder.js +1 -1
  191. package/src/materialization/marks/policies.js +2 -1
  192. package/src/materialization/overlayItems.js +154 -0
  193. package/src/materialization/planner.js +19 -4
  194. package/src/materialization/scales/policies/binnedPosition.js +43 -5
  195. package/src/materialization/scales/policies/series.js +12 -4
  196. package/src/materialization/scales/resolve.js +2 -0
  197. package/src/materialization/selection/items/bar.js +21 -3
  198. package/src/materialization/selection/items/common.js +18 -5
  199. package/src/materialization/selection/items/overlay.js +15 -0
  200. package/src/materialization/selection/items/path.js +1 -0
  201. package/src/materialization/selection/items/point.js +2 -3
  202. package/src/materialization/selection/items/tick.js +3 -12
  203. package/src/materialization/selection/path.js +2 -2
  204. package/src/materialization/selection/policies/bar.js +2 -0
  205. package/src/materialization/selection/policies/index.js +35 -1
  206. package/src/materialization/selection/policies/point.js +2 -0
  207. package/src/materialization/selection/policies/text.js +17 -0
  208. package/src/materialization/selection/rows.js +103 -0
  209. package/src/materialization/selection/state.js +19 -3
  210. package/src/materialization/selection/styles.js +8 -0
  211. package/src/materialization/text.js +6 -489
  212. package/src/materialization/textGeometry.js +503 -0
  213. package/src/materialization/textLines.js +20 -0
  214. package/src/persistence/validation.js +116 -25
  215. package/src/renderers/canvas/index.js +12 -7
  216. package/src/renderers/canvas/text.js +5 -5
  217. package/src/renderers/nativeBackend.js +25 -0
  218. package/src/renderers/pdf.js +3 -3
  219. package/src/renderers/png.js +4 -3
  220. package/src/renderers/svgSerialization.js +1 -643
  221. package/src/scene.js +5 -3
  222. package/src/selectors/plotComposition.js +115 -0
  223. package/src/selectors/selectionTargets.js +19 -0
  224. package/src/version.js +1 -1
  225. package/types/basic.d.ts +4 -2
  226. package/types/index.d.ts +14 -0
  227. package/types/inspection.d.ts +34 -0
  228. package/types/program.d.ts +572 -372
@@ -20,11 +20,11 @@ export const TICK_EDIT_OPTIONS = Object.freeze([
20
20
  ]);
21
21
  export const LABEL_CREATE_OPTIONS = Object.freeze([
22
22
  "scale", "coordinate", "angle", "count", "values", "offset", "format",
23
- "color", "fontSize", "fontFamily", "fontWeight"
23
+ "color", "fontSize", "fontFamily", "fontWeight", "align"
24
24
  ]);
25
25
  export const LABEL_EDIT_OPTIONS = Object.freeze([
26
26
  "count", "values", "offset", "format", "color", "fontSize",
27
- "fontFamily", "fontWeight"
27
+ "fontFamily", "fontWeight", "align"
28
28
  ]);
29
29
  const THETA_LABEL_CREATE_OPTIONS = Object.freeze([
30
30
  ...LABEL_CREATE_OPTIONS,
@@ -44,10 +44,10 @@ export function labelEditOptions(kind) {
44
44
  }
45
45
  export const TITLE_CREATE_OPTIONS = Object.freeze([
46
46
  "scale", "coordinate", "angle", "text", "offset", "color", "fontSize",
47
- "fontFamily", "fontWeight", "position"
47
+ "fontFamily", "fontWeight", "align", "position"
48
48
  ]);
49
49
  export const TITLE_EDIT_OPTIONS = Object.freeze([
50
- "text", "offset", "color", "fontSize", "fontFamily", "fontWeight",
50
+ "text", "offset", "color", "fontSize", "fontFamily", "fontWeight", "align",
51
51
  "position"
52
52
  ]);
53
53
 
@@ -1,6 +1,8 @@
1
1
  import { withGuideLayoutValidation } from "../../../../materialization/guides/layout.js";
2
2
  import { axisThemeTypography } from "../../../theme/state.js";
3
3
  import { action } from "../../../../core/action.js";
4
+ import { resolveTextLines } from "../../../../core/textMetrics.js";
5
+ import { materializeTextLines } from "../../../../materialization/textLines.js";
4
6
  import {
5
7
  validateNonEmptyString,
6
8
  validateNonNegativeFinite
@@ -33,7 +35,7 @@ import {
33
35
 
34
36
  function titleGeometry(program, kind, config, angle = resolveAngle(program, kind, {})) {
35
37
  const frame = resolvePolarFrameForProgram(program, config.coordinate);
36
- return kind === "theta"
38
+ const geometry = kind === "theta"
37
39
  ? resolveThetaAxisTitle({ frame, offset: config.offset })
38
40
  : resolveRadialAxisTitle({
39
41
  frame,
@@ -41,6 +43,7 @@ function titleGeometry(program, kind, config, angle = resolveAngle(program, kind
41
43
  offset: config.offset,
42
44
  position: config.position
43
45
  });
46
+ return config.align === undefined ? geometry : { ...geometry, textAlign: config.align };
44
47
  }
45
48
 
46
49
  function validateTitleGeometry(program, kind, config, geometry, text) {
@@ -50,6 +53,7 @@ function validateTitleGeometry(program, kind, config, geometry, text) {
50
53
  items: [{
51
54
  ...geometry,
52
55
  text,
56
+ lines: titleLines(text, config, geometry),
53
57
  fontSize: config.fontSize,
54
58
  fontFamily: config.fontFamily,
55
59
  fontWeight: config.fontWeight
@@ -57,10 +61,17 @@ function validateTitleGeometry(program, kind, config, geometry, text) {
57
61
  }, program.materializationConfigs.textMetrics);
58
62
  }
59
63
 
64
+ function titleLines(text, config, geometry) {
65
+ const lines = resolveTextLines(text, { fontSize: config.fontSize,
66
+ align: geometry.textAlign, baseline: geometry.textBaseline, blockAlign: "middle" });
67
+ return lines.length > 1 ? lines : undefined;
68
+ }
69
+
60
70
  function resolveTitleConfig(program, kind, args, resources, previous) {
61
71
  const typography = axisThemeTypography(program.materializationConfigs.theme, "title");
62
72
  const config = {
63
73
  ...(previous ?? {}),
74
+ ...(Object.hasOwn(args, "align") ? { align: args.align } : {}),
64
75
  scale: resources.scale,
65
76
  coordinate: resources.coordinate,
66
77
  inferredText: previous?.inferredText ?? !Object.hasOwn(args, "text"),
@@ -136,7 +147,7 @@ function makeEditTitle(kind) {
136
147
  for (const [property, value] of Object.entries(properties)) {
137
148
  next = next.editGraphics({ target: names.title, property, value });
138
149
  }
139
- return next;
150
+ return materializeTextLines(next, names.title, titleLines(text, config, geometry));
140
151
  }));
141
152
  }
142
153
 
@@ -1,3 +1,4 @@
1
+ import { withGuideVisibilityPaint } from "../../../materialization/guides/visibility.js";
1
2
  import { editGraphicProperties } from "../../primitives/graphicProperties.js";
2
3
  import { action } from "../../../core/action.js";
3
4
  import {
@@ -25,7 +26,7 @@ const CREATE_OPTIONS = Object.freeze([
25
26
  "scale", "coordinate", "count", "values", "color", "lineWidth",
26
27
  "strokeDash"
27
28
  ]);
28
- const EDIT_OPTIONS = Object.freeze([
29
+ const EDIT_OPTIONS = Object.freeze(["visible",
29
30
  "count", "values", "color", "lineWidth", "strokeDash"
30
31
  ]);
31
32
 
@@ -48,6 +49,7 @@ function validateStrokeDash(value) {
48
49
  }
49
50
 
50
51
  export function validatePolarGridOptions(args, operation, create) {
52
+ if (Object.hasOwn(args, "visible") && typeof args.visible !== "boolean") throw new TypeError("Grid visible must be a boolean.");
51
53
  validateOptionObject(
52
54
  args,
53
55
  create ? CREATE_OPTIONS : EDIT_OPTIONS,
@@ -86,6 +88,7 @@ function resolveConfig(program, kind, args, resources, previous) {
86
88
  : { mode: "count", count: previous.count, inferredValues: false };
87
89
  const config = {
88
90
  ...(previous ?? {}),
91
+ ...(Object.hasOwn(args, "visible") ? { visible: args.visible } : {}),
89
92
  kind,
90
93
  scale: resources.scale,
91
94
  coordinate: resources.coordinate,
@@ -156,7 +159,7 @@ function makeRematerialize(kind) {
156
159
  return action({
157
160
  op: operations.rematerialize,
158
161
  description: `Recompute concrete Polar ${kind} grid geometry.`
159
- }, function (args = {}) {
162
+ }, withGuideVisibilityPaint(function (args = {}) {
160
163
  noOptions(args, operations.rematerialize);
161
164
  const config = this.guideConfigs.grid?.[kind];
162
165
  const semantic = this.semanticSpec.guides.grid?.[kind];
@@ -175,7 +178,7 @@ function makeRematerialize(kind) {
175
178
  refreshed,
176
179
  geometry
177
180
  );
178
- });
181
+ }));
179
182
  }
180
183
 
181
184
  function makeCreate(kind) {
@@ -41,7 +41,13 @@ export function inferHistogramBoundaries(program, channel, scaleId) {
41
41
  values.some((value, index) => value !== unique[index]))) {
42
42
  throw new Error(`Guide values cannot infer shared histogram bins for scale "${scaleId}".`);
43
43
  }
44
- return unique;
44
+ const domain = program.resolvedScales[scaleId]?.domain;
45
+ // Retained histogram bins can extend beyond an auto domain after filtering.
46
+ // Inferred guides follow the displayed interval; user-specified tick values
47
+ // still use the normal strict validation path.
48
+ if (domain === undefined) return unique;
49
+ const minimum = Math.min(...domain), maximum = Math.max(...domain);
50
+ return unique.filter(value => value >= minimum && value <= maximum);
45
51
  }
46
52
 
47
53
  export function valuesFromTickConfig(program, config) {
@@ -21,6 +21,7 @@ import { registerResourceActions } from "./resources/index.js";
21
21
  import { registerTextMetricActions } from "./textMetrics/index.js";
22
22
  import { registerCompositionActions } from "./composition/index.js";
23
23
  import { registerFacetActions } from "./facets/index.js";
24
+ import { registerOverlayActions } from "./overlays/index.js";
24
25
  import { registerThemeActions } from "./theme/index.js";
25
26
  import {
26
27
  applyCompositionTheme,
@@ -38,6 +39,7 @@ export function registerActions(ProgramClass) {
38
39
  registerCanvasActions(ProgramClass);
39
40
  registerDataActions(ProgramClass);
40
41
  registerMarkActions(ProgramClass);
42
+ registerOverlayActions(ProgramClass);
41
43
  registerScaleActions(ProgramClass);
42
44
  registerEncodingActions(ProgramClass);
43
45
  registerBasicCoordinateActions(ProgramClass);
@@ -194,6 +194,7 @@ const rematerializeAreaMark = /* @__PURE__ */ action(
194
194
  }
195
195
  const colorEncoding = layer.encoding?.color;
196
196
  const strokeEncoding = layer.encoding?.stroke;
197
+ const opacityEncoding = layer.encoding?.opacity;
197
198
  let resolved = args.scales === false
198
199
  ? this
199
200
  : this
@@ -205,8 +206,11 @@ const rematerializeAreaMark = /* @__PURE__ */ action(
205
206
  if (args.scales !== false && strokeEncoding?.scale !== undefined) {
206
207
  resolved = resolved.rematerializeScale({ id: strokeEncoding.scale });
207
208
  }
209
+ if (args.scales !== false && opacityEncoding?.scale !== undefined) {
210
+ resolved = resolved.rematerializeScale({ id: opacityEncoding.scale });
211
+ }
208
212
  const config = validateAreaPaintConfig(this.markConfigs[id]);
209
- const { paths, fills, strokes } = resolveAreaMaterialization({
213
+ const { paths, fills, strokes, opacities } = resolveAreaMaterialization({
210
214
  rows: dataset.values,
211
215
  layer,
212
216
  densityTransform,
@@ -227,7 +231,7 @@ const rematerializeAreaMark = /* @__PURE__ */ action(
227
231
  length: paths.length,
228
232
  commands: paths,
229
233
  fill: fills,
230
- opacity: config.opacity,
234
+ opacity: opacities ?? config.opacity ?? 0.2,
231
235
  ...(hasOutline ? {
232
236
  stroke: strokes ?? (config.strokeFromFill === true ? fills : config.stroke),
233
237
  strokeWidth: config.strokeWidth ?? (strokes === undefined ? undefined : 1)
@@ -273,6 +277,9 @@ const editAreaMark = /* @__PURE__ */ action(
273
277
  "editAreaMark stroke conflicts with a field encoding; use encodeStroke with value to replace it."
274
278
  );
275
279
  }
280
+ if (Object.hasOwn(args, "opacity") && layer.encoding?.opacity !== undefined) {
281
+ throw new Error("editAreaMark opacity conflicts with a field encoding; use encodeOpacity with value to replace it.");
282
+ }
276
283
  if (args.stroke === false && Object.hasOwn(args, "strokeWidth")) {
277
284
  throw new Error("editAreaMark cannot set strokeWidth while removing stroke.");
278
285
  }
@@ -1 +1 @@
1
- import{deriveCenteredAreaSeries as P,deriveAreaSeries as V,deriveDensityAreaSeries as w,layoutDensityAreaSeries as z}from"../../../grammar/areaSeries.js";import{mapContinuousScaleValues as c,mapOrdinalPositionValues as D}from"../../../grammar/scales/index.js";import{mapScaleConsumerValues as b}from"../../../materialization/scales/map.js";import{buildAreaCurvePathCommands as A}from"../../../grammar/curveCommands.js";import{buildLinearPathCommands as k}from"../../../grammar/pathCommands.js";import{buildCategoricalDensityPaths as E}from"../../../grammar/categoricalDensity.js";import{derivePathSeriesFieldValues as C}from"../../../grammar/pathSeries.js";function q({derived:d,densityTransform:a,categoricalDensity:m,xScale:l,yScale:u,densityScale:x,layout:v,curve:r}){return m?E(d,{categoryScale:a.placement.channel==="x"?l:u,valueScale:a.placement.channel==="x"?u:l,curve:r}):d.series.map(o=>{if(a===void 0&&d.orientation==="horizontal"){const e=(["point","band"].includes(u.type)?D:c)(o.values.map(n=>n.y),u),t=c(o.values.map(n=>n.x),l),p=c(o.values.map(n=>n.x2),l);return A(e.map((n,s)=>({x:t[s],y:n})),e.map((n,s)=>({x:p[s],y:n})),r,{independentAxis:"y"})}if(a!==void 0&&d.mode==="x-density"){const e=(["point","band"].includes(u.type)?D:c)(o.values.map(n=>n.y),u),t=c(o.values.map(n=>n.x),l),p=c([0],x)[0];return r==="linear"?k([{x:p,y:e[0]},...e.map((n,s)=>({x:t[s],y:n})),{x:p,y:e.at(-1)}],{close:!0}):A(e.map(n=>({x:p,y:n})),e.map((n,s)=>({x:t[s],y:n})),r,{independentAxis:"y"})}const i=(["point","band"].includes(l.type)?D:c)(o.values.map(e=>e.x),l),g=a===void 0?d.mode==="y-center"?o.values.map(e=>e.lower):o.values.map(e=>e.y):d.mode==="y-density"?o.values.map(e=>e.lower):o.values.map(e=>e.y),h=c(g,u),y=a===void 0?d.mode==="y-center"?o.values.map(e=>e.upper):o.values.map(e=>e.y2):o.values.map(e=>e.upper),f=c(y,u);if(a!==void 0&&v==="overlay"){const e=c([0],u)[0];return r==="linear"?k([{x:i[0],y:e},...i.map((t,p)=>({x:t,y:f[p]})),{x:i.at(-1),y:e}],{close:!0}):A(i.map(t=>({x:t,y:e})),i.map((t,p)=>({x:t,y:f[p]})),r)}return A(i.map((e,t)=>({x:e,y:h[t]})),i.map((e,t)=>({x:e,y:f[t]})),r)})}function G({rows:d,layer:a,densityTransform:m,resolvedScales:l,config:u}){const x=l[a.encoding.x.scale],v=l[a.encoding.y.scale],r=m===void 0&&a.encoding?.y?.stack==="center",o=m===void 0?r?P(d,a,{xDomain:x.domain}):V(d,a,{xDomain:x.domain,yDomain:v.domain}):w(d,a,m),i=a.encoding?.color,g=a.layout?.mode??i?.layout??"overlay",h=m?.placement?.type==="category",y=m===void 0||h?o:z(o,g),f=m===void 0||h?void 0:y.mode==="y-density"?v:x;if(f!==void 0&&(f.domain[0]>0||f.domain[1]<0))throw new Error(`Density area mark "${a.id}" requires a scale domain containing zero.`);const e=q({derived:y,densityTransform:m,categoricalDensity:h,xScale:x,yScale:v,densityScale:f,layout:g,curve:u.curve??"linear"}),t=u.errorBand?.fill!==void 0?e.map(()=>u.errorBand.fill):i?.scale===void 0?e.map(()=>u.fill):b(i.fieldType!=="quantitative"&&(m!==void 0||r)?y.series.map(s=>s.key[i.field]):C(d,y.series,i.field,"color",i),l[i.scale],"color"),p=a.encoding?.stroke,n=p?.scale===void 0?void 0:b(C(d,y.series,p.field,"stroke",p),l[p.scale],"stroke");return{paths:e,fills:t,strokes:n}}export{G as resolveAreaMaterialization};
1
+ import{deriveCenteredAreaSeries as E,deriveAreaSeries as w,deriveDensityAreaSeries as z,layoutDensityAreaSeries as q}from"../../../grammar/areaSeries.js";import{mapContinuousScaleValues as s,mapOrdinalPositionValues as D}from"../../../grammar/scales/index.js";import{mapScaleConsumerValues as b}from"../../../materialization/scales/map.js";import{buildAreaCurvePathCommands as A}from"../../../grammar/curveCommands.js";import{buildLinearPathCommands as C}from"../../../grammar/pathCommands.js";import{buildCategoricalDensityPaths as B}from"../../../grammar/categoricalDensity.js";import{derivePathSeriesFieldValues as k}from"../../../grammar/pathSeries.js";function F({derived:p,densityTransform:o,categoricalDensity:m,xScale:c,yScale:u,densityScale:x,layout:v,curve:r}){return m?B(p,{categoryScale:o.placement.channel==="x"?c:u,valueScale:o.placement.channel==="x"?u:c,curve:r}):p.series.map(t=>{if(o===void 0&&p.orientation==="horizontal"){const e=(["point","band"].includes(u.type)?D:s)(t.values.map(n=>n.y),u),a=s(t.values.map(n=>n.x),c),d=s(t.values.map(n=>n.x2),c);return A(e.map((n,l)=>({x:a[l],y:n})),e.map((n,l)=>({x:d[l],y:n})),r,{independentAxis:"y"})}if(o!==void 0&&p.mode==="x-density"){const e=(["point","band"].includes(u.type)?D:s)(t.values.map(n=>n.y),u),a=s(t.values.map(n=>n.x),c),d=s([0],x)[0];return r==="linear"?C([{x:d,y:e[0]},...e.map((n,l)=>({x:a[l],y:n})),{x:d,y:e.at(-1)}],{close:!0}):A(e.map(n=>({x:d,y:n})),e.map((n,l)=>({x:a[l],y:n})),r,{independentAxis:"y"})}const i=(["point","band"].includes(c.type)?D:s)(t.values.map(e=>e.x),c),h=o===void 0?p.mode==="y-center"?t.values.map(e=>e.lower):t.values.map(e=>e.y):p.mode==="y-density"?t.values.map(e=>e.lower):t.values.map(e=>e.y),g=s(h,u),f=o===void 0?p.mode==="y-center"?t.values.map(e=>e.upper):t.values.map(e=>e.y2):t.values.map(e=>e.upper),y=s(f,u);if(o!==void 0&&v==="overlay"){const e=s([0],u)[0];return r==="linear"?C([{x:i[0],y:e},...i.map((a,d)=>({x:a,y:y[d]})),{x:i.at(-1),y:e}],{close:!0}):A(i.map(a=>({x:a,y:e})),i.map((a,d)=>({x:a,y:y[d]})),r)}return A(i.map((e,a)=>({x:e,y:g[a]})),i.map((e,a)=>({x:e,y:y[a]})),r)})}function I({rows:p,layer:o,densityTransform:m,resolvedScales:c,config:u}){const x=c[o.encoding.x.scale],v=c[o.encoding.y.scale],r=m===void 0&&o.encoding?.y?.stack==="center",t=m===void 0?r?E(p,o,{xDomain:x.domain}):w(p,o,{xDomain:x.domain,yDomain:v.domain}):z(p,o,m),i=o.encoding?.color,h=o.layout?.mode??i?.layout??"overlay",g=m?.placement?.type==="category",f=m===void 0||g?t:q(t,h),y=m===void 0||g?void 0:f.mode==="y-density"?v:x;if(y!==void 0&&(y.domain[0]>0||y.domain[1]<0))throw new Error(`Density area mark "${o.id}" requires a scale domain containing zero.`);const e=F({derived:f,densityTransform:m,categoricalDensity:g,xScale:x,yScale:v,densityScale:y,layout:h,curve:u.curve??"linear"}),a=u.errorBand?.fill!==void 0?e.map(()=>u.errorBand.fill):i?.scale===void 0?e.map(()=>u.fill):b(i.fieldType!=="quantitative"&&(m!==void 0||r)?f.series.map(V=>V.key[i.field]):k(p,f.series,i.field,"color",i),c[i.scale],"color"),d=o.encoding?.stroke,n=d?.scale===void 0?void 0:b(k(p,f.series,d.field,"stroke",d),c[d.scale],"stroke"),l=o.encoding?.opacity,P=l?.scale===void 0?void 0:b(k(p,f.series,l.field,"opacity",l),c[l.scale],"opacity");return{paths:e,fills:a,strokes:n,opacities:P}}export{I as resolveAreaMaterialization};
@@ -12,7 +12,7 @@ import {
12
12
  BAR_GRAINS,
13
13
  resolveBarOffsetChannel
14
14
  } from "../../../grammar/bars/policy.js";
15
- import { rematerializeHighlightBaseline } from "../lifecycle.js";
15
+ import { rematerializeHighlightBaseline, materializeFollowingOverlays } from "../lifecycle.js";
16
16
  import { offsetCategoryRectangles } from
17
17
  "../../../materialization/categorySlotOffset.js";
18
18
  import { materializeRectItem, RECT_STYLE_PROPERTIES } from "../../../grammar/roundedRect.js";
@@ -30,12 +30,12 @@ function editRectangles(program, id, rectangles) {
30
30
  item.properties?.blend !== undefined);
31
31
  if (hasShapeStyle || blend !== undefined || previousBlend) {
32
32
  const radius = appearance;
33
- return materializeMarkClip(replaceGraphicItems(
33
+ return materializeFollowingOverlays(materializeMarkClip(replaceGraphicItems(
34
34
  program,
35
35
  id,
36
36
  "rect",
37
37
  rectangles.map(rectangle => materializeRectItem(rectangle, radius))
38
- ), id);
38
+ ), id), id);
39
39
  }
40
40
  let next = editGraphicProperties(program, id, {
41
41
  length: rectangles.length,
@@ -54,7 +54,7 @@ function editRectangles(program, id, rectangles) {
54
54
  value: rectangles.map(rect => rect.opacity ?? 1)
55
55
  });
56
56
  }
57
- return materializeMarkClip(next, id);
57
+ return materializeFollowingOverlays(materializeMarkClip(next, id), id);
58
58
  }
59
59
 
60
60
  export const rematerializeBarMark = /* @__PURE__ */ action(
@@ -1,3 +1,17 @@
1
+ // Called explicitly by source mark materializers after their concrete geometry is complete.
2
+ // A surrounding plan owns any overlay rebuild that it has already scheduled.
3
+ export function materializeFollowingOverlays(program, source) {
4
+ const pending = program.context?.pendingMaterializationPlan;
5
+ const scheduled = new Set((pending?.steps.slice(pending.next) ?? [])
6
+ .filter(step => step.op === "rematerializeOverlay").map(step => step.args.id));
7
+ for (const layer of program.semanticSpec.layers) {
8
+ if (layer.derivedBindings?.overlay?.source === source && !scheduled.has(layer.id)) {
9
+ program = program.rematerializeOverlay({ id: layer.id });
10
+ }
11
+ }
12
+ return program;
13
+ }
14
+
1
15
  export function rematerializeHighlightBaseline(program, {
2
16
  target,
3
17
  operation,
@@ -1,3 +1,4 @@
1
+ import { assertIndependentOverlayGeometry } from "../../../grammar/overlay.js";
1
2
  import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
2
3
  import { action } from "../../../core/action.js";
3
4
  import { validateUserId } from "../../../core/identifiers.js";
@@ -209,6 +210,7 @@ const rematerializeLineMark = /* @__PURE__ */ action(
209
210
  "rematerializeLineMark"
210
211
  );
211
212
  const id = validateUserId(args.id, "Line mark id");
213
+ if (findLayer(this, id)?.derivedBindings?.overlay) return this.rematerializeOverlay({ id });
212
214
  const highlighted = rematerializeHighlightBaseline(this, {
213
215
  target: id,
214
216
  operation: "rematerializeLineMark",
@@ -301,6 +303,7 @@ const editLineMark = /* @__PURE__ */ action(
301
303
  predicate: candidate => candidate.mark?.type === "line",
302
304
  label: "line mark"
303
305
  });
306
+ if (Object.hasOwn(args, "missing")) assertIndependentOverlayGeometry(layer, "editLineMark missing");
304
307
  if (Object.hasOwn(args, "stroke") && (
305
308
  layer.encoding?.color !== undefined ||
306
309
  layer.encoding?.stroke !== undefined
@@ -101,7 +101,7 @@ export function resolvePositionedLineMaterialization({
101
101
  const radiusScaleId = layer.encoding?.radius?.scale;
102
102
  const lineOptions = polar
103
103
  ? { thetaDomain: resolvedScales[thetaScaleId].domain }
104
- : { xBinBoundaries, xDomain: resolvedScales[xScaleId].domain };
104
+ : { xBinBoundaries, xDomain: resolvedScales[xScaleId].domain, yDomain: resolvedScales[yScaleId].domain };
105
105
  const derived = deriveLineSeries(rows, layer, { ...lineOptions, scales: resolvedScales });
106
106
  const commands = polar
107
107
  ? derived.series.map(series => buildPolarLinePathCommands({
@@ -119,7 +119,9 @@ export function resolvePositionedLineMaterialization({
119
119
  series.values.map(value => value.x),
120
120
  resolvedScales[xScaleId]
121
121
  );
122
- const y = mapContinuousScaleValues(
122
+ const mapY = ["nominal", "ordinal"].includes(layer.encoding.y.fieldType)
123
+ ? mapOrdinalPositionValues : mapContinuousScaleValues;
124
+ const y = mapY(
123
125
  series.values.map(value => value.y),
124
126
  resolvedScales[yScaleId]
125
127
  );
@@ -1,3 +1,4 @@
1
+ import { assertIndependentOverlayGeometry } from "../../../grammar/overlay.js";
1
2
  import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
2
3
  import { action } from "../../../core/action.js";
3
4
  import { validateUserId } from "../../../core/identifiers.js";
@@ -45,6 +46,7 @@ export const editPointMark = /* @__PURE__ */ action(
45
46
  predicate: candidate => candidate.mark?.type === "point",
46
47
  label: "point mark"
47
48
  });
49
+ if (Object.hasOwn(args, "missing")) assertIndependentOverlayGeometry(layer, "editPointMark missing");
48
50
  const id = layer.id;
49
51
  if (Object.hasOwn(args, "shape") && layer.encoding?.shape !== undefined) {
50
52
  throw new Error(
@@ -1,3 +1,4 @@
1
+ import { assertIndependentOverlayGeometry } from "../../../grammar/overlay.js";
1
2
  import { closedAction } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
 
@@ -36,6 +37,7 @@ export const jitterPoints = /* @__PURE__ */ closedAction(
36
37
  function (args = {}) {
37
38
  const policy = normalizePointJitterPolicy(args);
38
39
  const layer = resolveJitterTarget(this, args.target);
40
+ assertIndependentOverlayGeometry(layer, "jitterPoints");
39
41
  if (this.materializationConfigs.pointPacking?.[layer.id] !== undefined) {
40
42
  throw new Error(`Point jitter on "${layer.id}" conflicts with point packing.`);
41
43
  }
@@ -34,7 +34,7 @@ import { findLayer } from "../../../selectors/layers.js";
34
34
  import { resolveGraphicItemCapacity } from "../../../selectors/graphicCapacity.js";
35
35
  import { getMarkGraphicTypes } from "../../../core/vocabulary.js";
36
36
  import { canMaterializePoint } from "../../../materialization/marks/capabilities.js";
37
- import { rematerializeHighlightBaseline } from "../lifecycle.js";
37
+ import { rematerializeHighlightBaseline, materializeFollowingOverlays } from "../lifecycle.js";
38
38
  import {
39
39
  resolveRowEncodingValues,
40
40
  resolveRowPositionValues
@@ -307,6 +307,7 @@ export const rematerializePointMark = /* @__PURE__ */ action(
307
307
  function (args = {}) {
308
308
  validateMarkOptions(args, REMATERIALIZE_OPTIONS, "rematerializePointMark");
309
309
  const id = validateUserId(args.id, "Point mark id");
310
+ if (findLayer(this, id)?.derivedBindings?.overlay) return this.rematerializeOverlay({ id });
310
311
  const highlighted = rematerializeHighlightBaseline(this, {
311
312
  target: id,
312
313
  operation: "rematerializePointMark",
@@ -453,11 +454,11 @@ export const rematerializePointMark = /* @__PURE__ */ action(
453
454
  ...strokeDetails
454
455
  });
455
456
  });
456
- return materializeMarkClip(jittered.program.editGraphics({
457
+ return materializeFollowingOverlays(materializeMarkClip(jittered.program.editGraphics({
457
458
  target: id,
458
459
  property: "items",
459
460
  value: items
460
- }), id);
461
+ }), id), id);
461
462
  }
462
463
 
463
464
  let next = graphic.items.length === dataset.values.length
@@ -552,6 +553,6 @@ export const rematerializePointMark = /* @__PURE__ */ action(
552
553
  for (const [property, value] of Object.entries(strokeDetails)) {
553
554
  next = next.editGraphics({ target: id, property, value });
554
555
  }
555
- return materializeMarkClip(next, id);
556
+ return materializeFollowingOverlays(materializeMarkClip(next, id), id);
556
557
  }
557
558
  );
@@ -1,3 +1,4 @@
1
+ import { assertIndependentOverlayGeometry } from "../../../grammar/overlay.js";
1
2
  import { closedAction } from "../../../core/action.js";
2
3
  import { validateUserId } from "../../../core/identifiers.js";
3
4
 
@@ -33,6 +34,7 @@ export const packPoints = /* @__PURE__ */ closedAction(
33
34
  function (args = {}) {
34
35
  const policy = normalizePointPackingPolicy(args);
35
36
  const layer = target(this, args.target, policy.channel);
37
+ assertIndependentOverlayGeometry(layer, "packPoints");
36
38
  if (this.materializationConfigs.jitters?.[layer.id] !== undefined) {
37
39
  throw new Error(`Point packing on "${layer.id}" conflicts with point jitter.`);
38
40
  }
@@ -410,14 +410,16 @@ function resolvePopulationValues(
410
410
  const { field } = resolveBoundPopulation(program, source, config, referenceId);
411
411
  if (field !== undefined) return strictFieldValues(dataset.values, field,
412
412
  `Statistical reference "${referenceId}" boundData`);
413
- if (source.mark.type === "line" && isAggregate(source.encoding?.y?.aggregate)) {
413
+ if (source.mark.type === "line" && (isAggregate(source.encoding?.y?.aggregate) || isAggregate(source.encoding?.x?.aggregate))) {
414
414
  const x = source.encoding.x;
415
415
  const bins = x.bin === undefined ? undefined : resolveLineBins(
416
416
  dataset.values, source, findSemanticScale(program, x.scale)
417
417
  );
418
418
  const derived = deriveLineSeries(dataset.values, source, {
419
419
  ...(bins === undefined ? {} : { xBinBoundaries: bins.boundaries }),
420
- allowSingleton: true
420
+ allowSingleton: true,
421
+ xDomain: program.resolvedScales[source.encoding.x.scale]?.domain,
422
+ yDomain: program.resolvedScales[source.encoding.y.scale]?.domain
421
423
  });
422
424
  return config.axis === "x" ? derived.xValues : derived.yValues;
423
425
  }
@@ -458,7 +460,7 @@ function statisticalRows(program, referenceId) {
458
460
  );
459
461
  const { dataset } = resolveBoundPopulation(program, source, { ...config, population }, referenceId);
460
462
  const groupBy = normalizeReferenceGroupBy(config.groupBy);
461
- if (population === "visibleItems" && findSelectionPolicy(source.mark?.type) === undefined) {
463
+ if (population === "visibleItems" && (source.mark?.type === "text" || findSelectionPolicy(source.mark?.type) === undefined)) {
462
464
  throw new Error(
463
465
  `Statistical reference "${referenceId}" visibleItems population is unavailable for ${source.mark?.type} marks. Use boundData.`
464
466
  );
@@ -4,6 +4,7 @@ import { isSourceOwnedText } from "../../grammar/text.js";
4
4
  import { closedAction } from "../../core/action.js";
5
5
  import { validateUserId } from "../../core/identifiers.js";
6
6
 
7
+ import { findSemanticScale } from "../../selectors/scales.js";
7
8
  import { findDataset } from "../../selectors/datasets.js";
8
9
  import { findLayer } from "../../selectors/layers.js";
9
10
  import { applyDetachedScaleRematerialization } from "../../materialization/dependencies.js";
@@ -113,6 +114,13 @@ function ownedDerivedData(program, ids) {
113
114
  candidates.add(dataset.id);
114
115
  }
115
116
  }
117
+ // Release leaf transforms before their complete-case input chain.
118
+ for (const id of ids) {
119
+ const config = program.markConfigs[id] ?? {};
120
+ for (const data of config.alignedPositionData ?? []) candidates.add(data);
121
+ for (const data of config.raincloudPlot?.ownedData ?? config.endpointPlot?.ownedData ?? []) candidates.add(data);
122
+ for (const data of [...(config.radarPlot?.ownedData ?? [])].reverse()) candidates.add(data);
123
+ }
116
124
  return candidates;
117
125
  }
118
126
 
@@ -165,6 +173,7 @@ export function removeOwnedMark(program, id, partial = false) {
165
173
  }
166
174
  return next
167
175
  ._withoutMaterializationConfig(["guides", "legendGroups", id])
176
+ ._withoutMaterializationConfig(["guides", "suppressedLegends", id])
168
177
  ._withoutMaterializationConfig(["marks", id])
169
178
  ._withContext({
170
179
  ...(program.context.currentMark === id ? { currentMark: undefined } : {}),
@@ -222,6 +231,7 @@ export const removeMark = /* @__PURE__ */ closedAction(
222
231
  }
223
232
  const previousLayers = ids.map(id => findLayer(this, id));
224
233
  const derived = ownedDerivedData(this, ids);
234
+ const ownedScales = new Set(ids.map(id => this.markConfigs[id]?.seriesOffsetScale).filter(Boolean));
225
235
  const positionScales = usedPositionScales(this, ids);
226
236
  let next = this;
227
237
 
@@ -264,6 +274,7 @@ export const removeMark = /* @__PURE__ */ closedAction(
264
274
  next = next.editGraphics({ target: id, remove: true });
265
275
  }
266
276
  next = next._withoutMaterializationConfig(["guides", "legendGroups", id]);
277
+ next = next._withoutMaterializationConfig(["guides", "suppressedLegends", id]);
267
278
  next = next._withoutMaterializationConfig(["marks", id]);
268
279
  next = next._withoutMaterializationConfig(["jitters", id]);
269
280
  next = next._withoutMaterializationConfig(["pointPacking", id]);
@@ -277,6 +288,11 @@ export const removeMark = /* @__PURE__ */ closedAction(
277
288
  }
278
289
  }
279
290
  next = applyDetachedScaleRematerialization(next, previousLayers);
291
+ for (const id of ownedScales) {
292
+ const references = collectResourceReferences(next, { kind: "scale", id })
293
+ .filter(reference => reference.strength !== "context");
294
+ if (references.length === 0 && findSemanticScale(next, id) !== undefined) next = next.removeScale({ id });
295
+ }
280
296
  return next._withContext({
281
297
  ...(ids.includes(this.context.currentMark) ? { currentMark: undefined } : {}),
282
298
  ...(selectionCleanup.selectionIds.includes(this.context.currentSelection)
@@ -1,4 +1,5 @@
1
1
  import { materializeMarkClip } from "../../materialization/markClip.js";
2
+ import { materializeFollowingOverlays } from "./lifecycle.js";
2
3
  import { isSourceOwnedText } from "../../grammar/text.js";
3
4
  import {
4
5
  resolveOptionalUserId,
@@ -244,5 +245,5 @@ export function editMarkGraphic(program, target, properties) {
244
245
  for (const [property, value] of Object.entries(properties)) {
245
246
  program = program.editGraphics({ target, property, value });
246
247
  }
247
- return materializeMarkClip(program, target);
248
+ return materializeFollowingOverlays(materializeMarkClip(program, target), target);
248
249
  }
@@ -1,3 +1,4 @@
1
+ import { rematerializeHighlightBaseline } from "../lifecycle.js";
1
2
  import { materializeMarkClip } from "../../../materialization/markClip.js";
2
3
  import { requestedMarkClip, validateMarkClipCoordinate } from "../../../selectors/markClip.js";
3
4
  import { TEXT_LABEL_LAYOUT_OPTIONS } from "./layout.js";
@@ -46,7 +47,7 @@ import { validateItemMissing } from "../../../grammar/itemMissing.js";
46
47
 
47
48
  const STYLE_OPTIONS = Object.freeze(["clip", ...TEXT_MARK_STYLE_OPTIONS]);
48
49
  const CREATE_OPTIONS = Object.freeze(["id", "data", "source", "text", "missing", ...STYLE_OPTIONS]);
49
- const EDIT_OPTIONS = Object.freeze(["target", "missing", ...STYLE_OPTIONS]);
50
+ const EDIT_OPTIONS = Object.freeze(["target", "missing", "textOverrides", ...STYLE_OPTIONS]);
50
51
  const REMATERIALIZE_OPTIONS = Object.freeze(["id", "replayLayout"]);
51
52
 
52
53
  function sourceMatchesData(program, layer, requestedData) {
@@ -460,6 +461,8 @@ const rematerializeTextMark = /* @__PURE__ */ action(
460
461
  ? next
461
462
  : next.materializeMarkLabelPlacement({ id });
462
463
  }
464
+ const highlighted = rematerializeHighlightBaseline(this, { target: id, operation: 'rematerializeTextMark', resetProperty: 'items', resetValue: [] });
465
+ if (highlighted) return highlighted;
463
466
  let next = materializeMarkClip(this.editGraphics({
464
467
  target: id,
465
468
  property: "items",
@@ -486,7 +489,7 @@ const editTextMark = /* @__PURE__ */ action(
486
489
  function (args = {}) {
487
490
  validateMarkOptions(args, EDIT_OPTIONS, "editTextMark");
488
491
  requestedMarkClip(args);
489
- if (!["missing", ...STYLE_OPTIONS].some(option => Object.hasOwn(args, option))) {
492
+ if (!["missing", "textOverrides", ...STYLE_OPTIONS].some(option => Object.hasOwn(args, option))) {
490
493
  throw new Error("editTextMark requires at least one editable property.");
491
494
  }
492
495
  const layer = requireTextLayer(this, args.target, "editTextMark");