ggaction 0.0.10 → 0.0.12

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 (224) hide show
  1. package/CHANGELOG.md +97 -0
  2. package/README.md +5 -3
  3. package/knowledge/action-card.schema.json +1 -0
  4. package/knowledge/action-cards.json +1 -10941
  5. package/knowledge/action-cards.schema.json +1 -0
  6. package/knowledge/intent-taxonomy.json +1 -183
  7. package/knowledge/intent-taxonomy.schema.json +1 -0
  8. package/knowledge/mcp-resources.json +1 -95
  9. package/knowledge/mcp-resources.schema.json +1 -0
  10. package/knowledge/task-packet.schema.json +1 -159
  11. package/knowledge/task-resolver.js +1 -1230
  12. package/package.json +18 -2
  13. package/src/actions/boxPlots/edit.js +45 -298
  14. package/src/actions/boxPlots/options.js +46 -77
  15. package/src/actions/boxPlots/resolve.js +1 -1
  16. package/src/actions/charts/bar.js +3 -0
  17. package/src/actions/charts/heatmap.js +73 -83
  18. package/src/actions/charts/index.js +1 -1
  19. package/src/actions/charts/parallel.js +35 -1
  20. package/src/actions/charts/shared.js +20 -0
  21. package/src/actions/composition/actions.js +46 -49
  22. package/src/actions/data/bin2d.js +105 -2
  23. package/src/actions/data/box.js +17 -17
  24. package/src/actions/data/density.js +42 -78
  25. package/src/actions/data/gradientProfile.js +22 -52
  26. package/src/actions/data/horizon.js +16 -41
  27. package/src/actions/data/index.js +10 -10
  28. package/src/actions/data/interval.js +16 -38
  29. package/src/actions/data/intervalEdit.js +55 -0
  30. package/src/actions/data/regression.js +7 -17
  31. package/src/actions/data/shared.js +47 -0
  32. package/src/actions/data/timeUnit.js +14 -38
  33. package/src/actions/data/window.js +14 -38
  34. package/src/actions/distributions/revision.js +154 -34
  35. package/src/actions/encodings/angle.js +9 -10
  36. package/src/actions/encodings/appearance.js +17 -51
  37. package/src/actions/encodings/density/resolve.js +3 -1
  38. package/src/actions/encodings/density.js +1 -15
  39. package/src/actions/encodings/horizon/resolve.js +13 -3
  40. package/src/actions/encodings/horizon.js +8 -7
  41. package/src/actions/encodings/index.js +9 -9
  42. package/src/actions/encodings/offset.js +41 -45
  43. package/src/actions/encodings/parallel.js +9 -10
  44. package/src/actions/encodings/pathOrder.js +6 -13
  45. package/src/actions/encodings/position/apply.js +30 -0
  46. package/src/actions/encodings/position/policies/arc.js +23 -2
  47. package/src/actions/encodings/position/policies/index.js +4 -4
  48. package/src/actions/encodings/position/policies/line.js +47 -17
  49. package/src/actions/encodings/position/resolve.js +36 -7
  50. package/src/actions/encodings/ranged.js +18 -23
  51. package/src/actions/encodings/remove.js +15 -25
  52. package/src/actions/encodings/ruleAppearance.js +9 -24
  53. package/src/actions/encodings/shared.js +37 -0
  54. package/src/actions/encodings/strokeDash.js +8 -23
  55. package/src/actions/encodings/text.js +9 -10
  56. package/src/actions/errorBands/create.js +105 -39
  57. package/src/actions/errorBands/edit.js +89 -93
  58. package/src/actions/errorBands/index.js +1 -2
  59. package/src/actions/errorBars/create.js +212 -30
  60. package/src/actions/errorBars/edit.js +91 -48
  61. package/src/actions/errorBars/index.js +1 -2
  62. package/src/actions/facets/actions.js +45 -69
  63. package/src/actions/facets/derive.js +38 -53
  64. package/src/actions/facets/replay.js +0 -1
  65. package/src/actions/gradientPlots/components.js +59 -48
  66. package/src/actions/gradientPlots/edit.js +35 -216
  67. package/src/actions/gradientPlots/index.js +11 -10
  68. package/src/actions/gradientPlots/materialize.js +21 -35
  69. package/src/actions/gradientPlots/options.js +5 -7
  70. package/src/actions/gradientPlots/paint.js +9 -6
  71. package/src/actions/gradientPlots/resolve.js +1 -1
  72. package/src/actions/guides/axes/index.js +3 -3
  73. package/src/actions/guides/axes/labels.js +68 -26
  74. package/src/actions/guides/axes/lines.js +22 -2
  75. package/src/actions/guides/axes/policy.js +28 -8
  76. package/src/actions/guides/axes/ticks.js +27 -9
  77. package/src/actions/guides/axes/titles.js +113 -65
  78. package/src/actions/guides/grids/resolve.js +14 -0
  79. package/src/actions/guides/guides.js +2 -4
  80. package/src/actions/guides/index.js +2 -2
  81. package/src/actions/guides/legends/categorical/actions.js +44 -68
  82. package/src/actions/guides/legends/categorical/components.js +6 -1
  83. package/src/actions/guides/legends/categorical/index.js +2 -2
  84. package/src/actions/guides/legends/categorical/layout.js +148 -175
  85. package/src/actions/guides/legends/categorical/recipes.js +5 -0
  86. package/src/actions/guides/legends/categorical/resolve.js +8 -1
  87. package/src/actions/guides/legends/continuous/common.js +117 -66
  88. package/src/actions/guides/legends/continuous/gradient.js +38 -37
  89. package/src/actions/guides/legends/continuous/interval.js +97 -76
  90. package/src/actions/guides/legends/continuous/opacity.js +28 -38
  91. package/src/actions/guides/legends/edit.js +14 -1
  92. package/src/actions/guides/legends/index.js +1 -1
  93. package/src/actions/guides/legends/lane.js +2 -1
  94. package/src/actions/guides/legends/remove.js +8 -0
  95. package/src/actions/guides/legends/size.js +36 -43
  96. package/src/actions/guides/legends/strokeWidth.js +20 -26
  97. package/src/actions/guides/polar/axes/labels.js +17 -1
  98. package/src/actions/guides/polar/axes/shared.js +7 -1
  99. package/src/actions/guides/polar/axes/titles.js +19 -2
  100. package/src/actions/guides/polar/grids.js +4 -0
  101. package/src/actions/guides/polar/resolve.js +6 -0
  102. package/src/actions/index.js +13 -13
  103. package/src/actions/intervals/resolve.js +87 -117
  104. package/src/actions/marks/arc/actions.js +31 -36
  105. package/src/actions/marks/area/actions.js +23 -31
  106. package/src/actions/marks/index.js +6 -6
  107. package/src/actions/marks/line/actions.js +33 -52
  108. package/src/actions/marks/line/materialize.js +7 -5
  109. package/src/actions/marks/point/materialize.js +38 -16
  110. package/src/actions/marks/remove.js +21 -0
  111. package/src/actions/marks/rule/actions.js +79 -54
  112. package/src/actions/marks/shared.js +8 -4
  113. package/src/actions/marks/text/actions.js +14 -6
  114. package/src/actions/marks/text/layout.js +21 -45
  115. package/src/actions/marks/tick/actions.js +22 -21
  116. package/src/actions/primitives/createGraphics.js +4 -0
  117. package/src/actions/primitives/editGraphics.js +4 -0
  118. package/src/actions/primitives/index.js +3 -3
  119. package/src/actions/primitives/semantic.js +1 -1
  120. package/src/actions/primitives/semanticValidation/index.js +2 -2
  121. package/src/actions/primitives/semanticValidation/layer.js +1 -1
  122. package/src/actions/regression/edit.js +3 -43
  123. package/src/actions/scales/consumers/families.js +24 -4
  124. package/src/actions/scales/consumers/index.js +1 -1
  125. package/src/actions/scales/consumers/seriesLayout.js +17 -0
  126. package/src/actions/scales/definitions.js +100 -103
  127. package/src/actions/scales/materialize.js +5 -0
  128. package/src/actions/selection/actions.js +79 -121
  129. package/src/actions/titles/actions.js +48 -94
  130. package/src/actions/titles/resolve.js +14 -27
  131. package/src/actions/violinPlots/create.js +37 -44
  132. package/src/core/textMetrics.js +74 -37
  133. package/src/core/validation.js +18 -0
  134. package/src/core/vocabulary.js +2 -2
  135. package/src/grammar/aggregate.js +48 -28
  136. package/src/grammar/arcs.js +170 -32
  137. package/src/grammar/areaSeries.js +14 -16
  138. package/src/grammar/bin2d.js +37 -23
  139. package/src/grammar/boxPlot.js +14 -13
  140. package/src/grammar/categoricalDensity.js +14 -14
  141. package/src/grammar/categoryOrder.js +8 -14
  142. package/src/grammar/curveCommands.js +87 -20
  143. package/src/grammar/density.js +162 -141
  144. package/src/grammar/facets/index.js +14 -0
  145. package/src/grammar/facets/scales.js +7 -4
  146. package/src/grammar/gradientProfile.js +12 -15
  147. package/src/grammar/histogram.js +145 -83
  148. package/src/grammar/horizon.js +60 -23
  149. package/src/grammar/interval.js +14 -13
  150. package/src/grammar/lineSeries.js +91 -61
  151. package/src/grammar/numeric.js +290 -0
  152. package/src/grammar/paint.js +3 -4
  153. package/src/grammar/palettes.js +21 -32
  154. package/src/grammar/pathCommands.js +6 -0
  155. package/src/grammar/polarPaths.js +5 -5
  156. package/src/grammar/positionCompatibility.js +1 -1
  157. package/src/grammar/regression/derive.js +48 -9
  158. package/src/grammar/regression/models.js +248 -69
  159. package/src/grammar/regression/parameters.js +8 -0
  160. package/src/grammar/rules.js +2 -0
  161. package/src/grammar/scales/color.js +35 -26
  162. package/src/grammar/scales/continuous.js +71 -24
  163. package/src/grammar/scales/definition.js +1 -1
  164. package/src/grammar/scales/discretized.js +42 -12
  165. package/src/grammar/scales/fields.js +21 -4
  166. package/src/grammar/scales/ordinal.js +139 -60
  167. package/src/grammar/scales/temporal.js +40 -11
  168. package/src/grammar/scales/transformed.js +199 -52
  169. package/src/grammar/schemas/graphicBounds.js +270 -79
  170. package/src/grammar/seriesLayout.js +50 -18
  171. package/src/grammar/ticks.js +123 -53
  172. package/src/grammar/timeUnit.js +18 -8
  173. package/src/grammar/transforms.js +4 -1
  174. package/src/grammar/window.js +70 -57
  175. package/src/index.js +1 -1
  176. package/src/layout/canvas.js +4 -8
  177. package/src/layout/composition.js +39 -40
  178. package/src/layout/facets.js +55 -30
  179. package/src/layout/labels.js +91 -15
  180. package/src/layout/legend.js +22 -20
  181. package/src/layout/legendLane.js +54 -40
  182. package/src/layout/title.js +7 -7
  183. package/src/materialization/bars/aggregate.js +14 -40
  184. package/src/materialization/bars/grouped.js +7 -18
  185. package/src/materialization/bars/histogram.js +2 -19
  186. package/src/materialization/bars/ranged.js +20 -15
  187. package/src/materialization/bars/resolve.js +21 -0
  188. package/src/materialization/facetGuides/legacyCategorical.js +9 -2
  189. package/src/materialization/facetGuides/placement.js +49 -19
  190. package/src/materialization/facetGuides/preparation.js +35 -6
  191. package/src/materialization/facets.js +42 -28
  192. package/src/materialization/guides/resources.js +2 -1
  193. package/src/materialization/marks/capabilities.js +15 -4
  194. package/src/materialization/marks/index.js +29 -6
  195. package/src/materialization/rowEncoding.js +57 -1
  196. package/src/materialization/scales/policies/bar.js +61 -102
  197. package/src/materialization/scales/policies/binnedPosition.js +34 -0
  198. package/src/materialization/scales/policies/offset.js +54 -0
  199. package/src/materialization/scales/policies/series.js +13 -7
  200. package/src/materialization/scales/resolve.js +6 -9
  201. package/src/materialization/selection/items/arc.js +16 -2
  202. package/src/materialization/selection/items/bar.js +4 -2
  203. package/src/materialization/selection/items/common.js +21 -1
  204. package/src/materialization/selection/items/path.js +19 -2
  205. package/src/materialization/selection/items/point.js +4 -16
  206. package/src/materialization/selection/items/tick.js +13 -21
  207. package/src/materialization/selection/point.js +11 -4
  208. package/src/materialization/selection/styles.js +19 -27
  209. package/src/materialization/text.js +4 -1
  210. package/src/mcp/adapter.js +8 -3
  211. package/src/renderers/canvas/fill.js +2 -2
  212. package/src/renderers/canvas/index.js +35 -2
  213. package/src/renderers/canvas/native.js +160 -0
  214. package/src/renderers/pdf.js +14 -0
  215. package/src/renderers/svg.js +37 -4
  216. package/types/index.d.ts +3 -0
  217. package/types/program.d.ts +523 -131
  218. package/types/svg.d.ts +1 -0
  219. package/src/actions/errorBands/components.js +0 -81
  220. package/src/actions/errorBands/options.js +0 -39
  221. package/src/actions/errorBands/resolve.js +0 -28
  222. package/src/actions/errorBars/components.js +0 -62
  223. package/src/actions/errorBars/options.js +0 -58
  224. package/src/actions/errorBars/resolve.js +0 -25
@@ -1,5 +1,6 @@
1
1
  import { validateUserId } from "../../../core/identifiers.js";
2
2
  import {
3
+ validateGeneratedItemLimit,
3
4
  validateOptionObject,
4
5
  validateNonEmptyString,
5
6
  validateNonNegativeFinite
@@ -58,12 +59,18 @@ function validateStrokeDash(value) {
58
59
 
59
60
  export function validateGridCreateArgs(args, operation) {
60
61
  validateOptionObject(args, GRID_OPTIONS, operation);
62
+ if (Array.isArray(args.values)) {
63
+ validateGeneratedItemLimit(args.values.length, "Grid value count");
64
+ }
61
65
  if (Object.hasOwn(args, "count") && Object.hasOwn(args, "values")) {
62
66
  throw new Error(`${operation} cannot use count and values together.`);
63
67
  }
64
68
  if (Object.hasOwn(args, "count") && (!Number.isInteger(args.count) || args.count <= 0)) {
65
69
  throw new RangeError("Grid count must be a positive integer.");
66
70
  }
71
+ if (Number.isInteger(args.count)) {
72
+ validateGeneratedItemLimit(args.count, "Grid count");
73
+ }
67
74
  if (Object.hasOwn(args, "values") && (
68
75
  !Array.isArray(args.values) ||
69
76
  args.values.length === 0 ||
@@ -84,6 +91,9 @@ export function validateGridEditArgs(args, operation) {
84
91
  validateOptionObject(args, GRID_EDIT_OPTIONS, operation, {
85
92
  allowEmpty: false
86
93
  });
94
+ if (Array.isArray(args.values)) {
95
+ validateGeneratedItemLimit(args.values.length, "Grid value count");
96
+ }
87
97
  if (Object.hasOwn(args, "count") && Object.hasOwn(args, "values")) {
88
98
  throw new Error(`${operation} cannot use count and values together.`);
89
99
  }
@@ -92,6 +102,9 @@ export function validateGridEditArgs(args, operation) {
92
102
  )) {
93
103
  throw new RangeError("Grid count must be a positive integer.");
94
104
  }
105
+ if (Number.isInteger(args.count)) {
106
+ validateGeneratedItemLimit(args.count, "Grid count");
107
+ }
95
108
  if (Object.hasOwn(args, "values") && args.values !== "auto" && (
96
109
  !Array.isArray(args.values) ||
97
110
  args.values.length === 0 ||
@@ -235,6 +248,7 @@ export function resolveGridGeometry(program, config) {
235
248
  throw new Error("Grid materialization requires a continuous scale and Canvas bounds.");
236
249
  }
237
250
  const values = valuesFromTickConfig(program, config);
251
+ validateGeneratedItemLimit(values.length, "Grid value count");
238
252
  const low = Math.min(...scale.domain);
239
253
  const high = Math.max(...scale.domain);
240
254
  if (!values.every(value => value >= low && value <= high)) {
@@ -8,6 +8,7 @@ import {
8
8
  import { findDataset } from "../../selectors/datasets.js";
9
9
  import { findUpstreamTransform } from
10
10
  "../../materialization/dataProvenance.js";
11
+ import { sampleNumericRange } from "../../grammar/numeric.js";
11
12
 
12
13
  const OPTIONS = Object.freeze(["axes", "grid", "legend"]);
13
14
 
@@ -60,10 +61,7 @@ function inferAxesOptions(program, applicability) {
60
61
  inferred.x = {
61
62
  ...(inferred.x ?? {}),
62
63
  ticksAndLabels: {
63
- values: Array.from(
64
- { length: 6 },
65
- (_, index) => low + (high - low) * index / 5
66
- )
64
+ values: sampleNumericRange(low, high, 6, "Horizon axis domain")
67
65
  }
68
66
  };
69
67
  }
@@ -1,11 +1,11 @@
1
- import { registerGuideAxisActions } from "./axes/index.js";
1
+ import { registerLegendActions } from "./legends/index.js";
2
2
  import { registerGuideCollectionActions } from "./guides.js";
3
3
  import { registerGridActions } from "./grids/index.js";
4
- import { registerLegendActions } from "./legends/index.js";
5
4
  import {
6
5
  registerPolarAxisActions,
7
6
  registerPolarGridActions
8
7
  } from "./polar/index.js";
8
+ import { registerGuideAxisActions } from "./axes/index.js";
9
9
 
10
10
  export function registerGuideActions(ProgramClass) {
11
11
  registerGuideAxisActions(ProgramClass);
@@ -21,6 +21,40 @@ import {
21
21
  sameValues
22
22
  } from "./resolve.js";
23
23
 
24
+ function finishLegend(program) {
25
+ return hasMultiLegendLane(program) ? program.rematerializeLegend() : program;
26
+ }
27
+
28
+ function requestedCandidate(program, target, candidates) {
29
+ if (target === undefined) {
30
+ return candidates.length === 1 ? candidates[0] : undefined;
31
+ }
32
+ const layer = findLayer(program, target);
33
+ return candidates.includes(layer) ? layer : undefined;
34
+ }
35
+
36
+ function createStandaloneLegend(program, args, kind) {
37
+ const { target, count, position, channels: _channels, ...unsupported } = args;
38
+ const label = kind === "size" ? "size" : "stroke-width";
39
+ const unsupportedKeys = Object.keys(unsupported);
40
+ if (unsupportedKeys.length > 0) {
41
+ throw new Error(
42
+ `Standalone ${label} legend does not support option "${unsupportedKeys[0]}".`
43
+ );
44
+ }
45
+ if (position !== undefined && position !== "right") {
46
+ throw new Error(
47
+ `Standalone ${label} legends currently require position "right".`
48
+ );
49
+ }
50
+ return finishLegend(program[kind === "size"
51
+ ? "createSizeLegend"
52
+ : "createStrokeWidthLegend"]({
53
+ ...(target === undefined ? {} : { target }),
54
+ ...(count === undefined ? {} : { count })
55
+ }));
56
+ }
57
+
24
58
  export const rematerializeLegend = action(
25
59
  { op: "rematerializeLegend", description: "Rematerialize every existing legend component." },
26
60
  function (args = {}) {
@@ -207,27 +241,7 @@ export const createLegend = action(
207
241
  !hasNonSizeLegendCandidate)
208
242
  );
209
243
  if (explicitSize || inferredSize) {
210
- const {
211
- target,
212
- count,
213
- position,
214
- channels: _channels,
215
- ...unsupported
216
- } = args;
217
- const unsupportedKeys = Object.keys(unsupported);
218
- if (unsupportedKeys.length > 0) {
219
- throw new Error(
220
- `Standalone size legend does not support option "${unsupportedKeys[0]}".`
221
- );
222
- }
223
- if (position !== undefined && position !== "right") {
224
- throw new Error('Standalone size legends currently require position "right".');
225
- }
226
- const next = this.createSizeLegend({
227
- ...(target === undefined ? {} : { target }),
228
- ...(count === undefined ? {} : { count })
229
- });
230
- return hasMultiLegendLane(next) ? next.rematerializeLegend() : next;
244
+ return createStandaloneLegend(this, args, "size");
231
245
  }
232
246
  const strokeWidthCandidates = this.semanticSpec.layers.filter(
233
247
  isStrokeWidthLegendLayer
@@ -248,23 +262,7 @@ export const createLegend = action(
248
262
  !hasOtherStrokeWidthLegendCandidate)
249
263
  );
250
264
  if (explicitStrokeWidth || inferredStrokeWidth) {
251
- const { target, count, position, channels: _channels, ...unsupported } = args;
252
- const unsupportedKeys = Object.keys(unsupported);
253
- if (unsupportedKeys.length > 0) {
254
- throw new Error(
255
- `Standalone stroke-width legend does not support option "${unsupportedKeys[0]}".`
256
- );
257
- }
258
- if (position !== undefined && position !== "right") {
259
- throw new Error(
260
- 'Standalone stroke-width legends currently require position "right".'
261
- );
262
- }
263
- const next = this.createStrokeWidthLegend({
264
- ...(target === undefined ? {} : { target }),
265
- ...(count === undefined ? {} : { count })
266
- });
267
- return hasMultiLegendLane(next) ? next.rematerializeLegend() : next;
265
+ return createStandaloneLegend(this, args, "strokeWidth");
268
266
  }
269
267
  const opacityCandidates = this.semanticSpec.layers.filter(layer =>
270
268
  layer.mark?.type === "point" && layer.encoding?.opacity?.scale !== undefined
@@ -279,8 +277,7 @@ export const createLegend = action(
279
277
  (channels === undefined && opacityCandidates.length === 1 &&
280
278
  !hasOtherLegendCandidate)
281
279
  ) {
282
- const next = this.createOpacityLegend(args);
283
- return hasMultiLegendLane(next) ? next.rematerializeLegend() : next;
280
+ return finishLegend(this.createOpacityLegend(args));
284
281
  }
285
282
  const continuousColorCandidates = this.semanticSpec.layers.filter(layer => {
286
283
  const encoding = ["point", "bar", "rect"].includes(layer.mark?.type)
@@ -289,41 +286,26 @@ export const createLegend = action(
289
286
  const scale = findSemanticScale(this, encoding?.scale);
290
287
  return scale?.type === "sequential";
291
288
  });
292
- const continuousColor = args.target === undefined
293
- ? continuousColorCandidates.length === 1
294
- ? continuousColorCandidates[0]
295
- : undefined
296
- : (() => {
297
- const layer = findLayer(this, args.target);
298
- return continuousColorCandidates.includes(layer) ? layer : undefined;
299
- })();
289
+ const continuousColor = requestedCandidate(
290
+ this, args.target, continuousColorCandidates
291
+ );
300
292
  if (
301
293
  (channels?.length === 1 && channels[0] === "color" && continuousColor) ||
302
294
  (channels === undefined && continuousColor)
303
295
  ) {
304
- const next = this.createGradientLegend(args);
305
- return hasMultiLegendLane(next) ? next.rematerializeLegend() : next;
296
+ return finishLegend(this.createGradientLegend(args));
306
297
  }
307
298
  const intervalColorCandidates = this.semanticSpec.layers.filter(layer => {
308
299
  const encoding = layer.mark?.type === "point" ? layer.encoding?.color : undefined;
309
300
  const scale = findSemanticScale(this, encoding?.scale);
310
301
  return ["quantize", "quantile", "threshold"].includes(scale?.type);
311
302
  });
312
- const intervalColor = args.target === undefined
313
- ? intervalColorCandidates.length === 1
314
- ? intervalColorCandidates[0]
315
- : undefined
316
- : (() => {
317
- const layer = findLayer(this, args.target);
318
- return intervalColorCandidates.includes(layer) ? layer : undefined;
319
- })();
320
303
  if (
321
304
  (channels?.length === 1 && channels[0] === "color" &&
322
305
  intervalColorCandidates.length > 0) ||
323
306
  (channels === undefined && intervalColorCandidates.length > 0)
324
307
  ) {
325
- const next = this.createIntervalLegend(args);
326
- return hasMultiLegendLane(next) ? next.rematerializeLegend() : next;
308
+ return finishLegend(this.createIntervalLegend(args));
327
309
  }
328
310
  const wantsShape = channels?.includes("shape") === true;
329
311
  const pointCandidates = this.semanticSpec.layers.filter(layer =>
@@ -331,12 +313,7 @@ export const createLegend = action(
331
313
  layer.encoding?.shape?.scale !== undefined &&
332
314
  (wantsShape || layer.encoding?.color?.scale !== undefined)
333
315
  );
334
- const requestedPoint = args.target === undefined
335
- ? pointCandidates.length === 1 ? pointCandidates[0] : undefined
336
- : (() => {
337
- const layer = findLayer(this, args.target);
338
- return pointCandidates.includes(layer) ? layer : undefined;
339
- })();
316
+ const requestedPoint = requestedCandidate(this, args.target, pointCandidates);
340
317
  if (requestedPoint !== undefined) {
341
318
  const { count, ...categoricalArgs } = args;
342
319
  if (
@@ -399,8 +376,7 @@ export const createLegend = action(
399
376
  }
400
377
  return next;
401
378
  }
402
- const next = this.createCategoricalLegend(args);
403
- return hasMultiLegendLane(next) ? next.rematerializeLegend() : next;
379
+ return finishLegend(this.createCategoricalLegend(args));
404
380
  }
405
381
  );
406
382
 
@@ -1,4 +1,5 @@
1
1
  import { action } from "../../../../core/action.js";
2
+ import { formatVisibleText } from "../../../../core/textMetrics.js";
2
3
  import { activeConfig, graphic, noOptions, resolveLayout } from "./layout.js";
3
4
  import { resolveLegendGraphicPlacement } from
4
5
  "../../../../materialization/graphicHierarchy.js";
@@ -17,7 +18,11 @@ export const rematerializeLegendLabels = action(
17
18
  .editGraphics({ target: id, property: "length", value: config.domain.length })
18
19
  .editGraphics({ target: id, property: "x", value: layout.labelX })
19
20
  .editGraphics({ target: id, property: "y", value: layout.itemY })
20
- .editGraphics({ target: id, property: "text", value: config.domain.map(String) })
21
+ .editGraphics({
22
+ target: id,
23
+ property: "text",
24
+ value: config.domain.map(formatVisibleText)
25
+ })
21
26
  .editGraphics({ target: id, property: "fill", value: config.labels.color })
22
27
  .editGraphics({ target: id, property: "fontSize", value: config.labels.fontSize })
23
28
  .editGraphics({ target: id, property: "fontFamily", value: config.labels.fontFamily })
@@ -1,4 +1,5 @@
1
1
  import { action } from "../../../../core/action.js";
2
+ import { editLegend } from "../edit.js";
2
3
  import { resolveStoredSelection } from
3
4
  "../../../../materialization/selection/state.js";
4
5
  import {
@@ -15,7 +16,6 @@ import {
15
16
  rematerializeLegendLabels,
16
17
  rematerializeLegendTitle
17
18
  } from "./components.js";
18
- import { activeConfig, noOptions, symbolGraphic } from "./layout.js";
19
19
  import {
20
20
  createLegendSymbolLines,
21
21
  createLegendSymbolPoints,
@@ -27,7 +27,7 @@ import {
27
27
  rematerializeLegendSymbols,
28
28
  rematerializeBasicLegendHighlights
29
29
  } from "./symbols.js";
30
- import { editLegend } from "../edit.js";
30
+ import { activeConfig, noOptions, symbolGraphic } from "./layout.js";
31
31
  import {
32
32
  rematerializeHorizontalLegendLane,
33
33
  rematerializeSideLegendLane