ggaction 0.0.12 → 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.
Files changed (378) hide show
  1. package/CHANGELOG.md +127 -0
  2. package/README.md +20 -11
  3. package/knowledge/action-card.schema.json +1 -1
  4. package/knowledge/action-cards.json +1 -1
  5. package/knowledge/action-cards.schema.json +1 -1
  6. package/knowledge/extension-authoring.md +2 -1
  7. package/knowledge/intent-taxonomy.json +1 -1
  8. package/knowledge/mcp-resources.json +1 -1
  9. package/knowledge/task-resolver.js +1 -1
  10. package/package.json +10 -3
  11. package/src/actions/basic.js +4 -2
  12. package/src/actions/boxPlots/components.js +14 -4
  13. package/src/actions/boxPlots/edit.js +31 -5
  14. package/src/actions/boxPlots/materialize.js +13 -4
  15. package/src/actions/boxPlots/options.js +48 -16
  16. package/src/actions/canvas/actions.js +3 -1
  17. package/src/actions/canvas/fitting.js +211 -0
  18. package/src/actions/canvas/index.js +2 -0
  19. package/src/actions/categoryOrder/index.js +18 -6
  20. package/src/actions/charts/area.js +51 -0
  21. package/src/actions/charts/bar.js +13 -6
  22. package/src/actions/charts/beeswarm.js +70 -0
  23. package/src/actions/charts/density.js +48 -0
  24. package/src/actions/charts/ecdf.js +186 -0
  25. package/src/actions/charts/endpoints.js +473 -0
  26. package/src/actions/charts/heatmap.js +4 -3
  27. package/src/actions/charts/histogram.js +5 -4
  28. package/src/actions/charts/horizon.js +73 -0
  29. package/src/actions/charts/index.js +37 -0
  30. package/src/actions/charts/interval-regression.js +172 -0
  31. package/src/actions/charts/line.js +8 -6
  32. package/src/actions/charts/parallel.js +8 -2
  33. package/src/actions/charts/pie.js +52 -0
  34. package/src/actions/charts/polar.js +134 -0
  35. package/src/actions/charts/radar.js +305 -0
  36. package/src/actions/charts/radial.js +50 -0
  37. package/src/actions/charts/raincloud.js +422 -0
  38. package/src/actions/charts/rug-strip.js +283 -0
  39. package/src/actions/charts/scatter.js +11 -3
  40. package/src/actions/charts/shared.js +69 -10
  41. package/src/actions/composition/actions.js +129 -3
  42. package/src/actions/coordinates/actions.js +1 -1
  43. package/src/actions/coordinates/edit.js +76 -0
  44. package/src/actions/data/bin.js +29 -0
  45. package/src/actions/data/bin2d.js +57 -185
  46. package/src/actions/data/complete.js +26 -0
  47. package/src/actions/data/computed.js +24 -0
  48. package/src/actions/data/create.js +2 -2
  49. package/src/actions/data/density.js +12 -20
  50. package/src/actions/data/derived.js +111 -15
  51. package/src/actions/data/ecdf.js +38 -0
  52. package/src/actions/data/edit.js +539 -0
  53. package/src/actions/data/filter.js +226 -30
  54. package/src/actions/data/fold.js +24 -0
  55. package/src/actions/data/impute.js +26 -0
  56. package/src/actions/data/index.js +38 -0
  57. package/src/actions/data/interval.js +2 -0
  58. package/src/actions/data/intervalEdit.js +86 -4
  59. package/src/actions/data/normalize.js +27 -0
  60. package/src/actions/data/regression.js +19 -21
  61. package/src/actions/data/revisionBindings.js +145 -0
  62. package/src/actions/data/shared.js +20 -4
  63. package/src/actions/data/stack.js +26 -0
  64. package/src/actions/data/summary.js +26 -0
  65. package/src/actions/data/timeUnit.js +4 -1
  66. package/src/actions/data/window.js +1 -1
  67. package/src/actions/encodings/appearance.js +32 -13
  68. package/src/actions/encodings/barWidth.js +8 -0
  69. package/src/actions/encodings/basic.js +2 -0
  70. package/src/actions/encodings/channels.js +415 -0
  71. package/src/actions/encodings/color/continuous.js +19 -59
  72. package/src/actions/encodings/color/index.js +30 -23
  73. package/src/actions/encodings/color/layout.js +3 -97
  74. package/src/actions/encodings/color/policy.js +5 -8
  75. package/src/actions/encodings/density/resolve.js +37 -5
  76. package/src/actions/encodings/density.js +124 -34
  77. package/src/actions/encodings/histogram.js +3 -2
  78. package/src/actions/encodings/horizon/resolve.js +8 -4
  79. package/src/actions/encodings/horizon.js +18 -8
  80. package/src/actions/encodings/index.js +6 -0
  81. package/src/actions/encodings/offset.js +30 -29
  82. package/src/actions/encodings/parallel.js +2 -8
  83. package/src/actions/encodings/position/apply.js +63 -11
  84. package/src/actions/encodings/position/index.js +52 -6
  85. package/src/actions/encodings/position/policies/arc.js +14 -0
  86. package/src/actions/encodings/position/policies/area.js +4 -42
  87. package/src/actions/encodings/position/policies/bar.js +57 -13
  88. package/src/actions/encodings/position/resolve.js +88 -26
  89. package/src/actions/encodings/ranged.js +123 -97
  90. package/src/actions/encodings/remove.js +44 -34
  91. package/src/actions/encodings/ruleAppearance.js +24 -32
  92. package/src/actions/encodings/seriesLayout.js +105 -0
  93. package/src/actions/encodings/shared.js +107 -37
  94. package/src/actions/encodings/stroke.js +226 -0
  95. package/src/actions/encodings/strokeDash.js +9 -6
  96. package/src/actions/encodings/temporal.js +7 -0
  97. package/src/actions/encodings/text.js +30 -15
  98. package/src/actions/errorBands/create.js +41 -8
  99. package/src/actions/errorBands/edit.js +360 -25
  100. package/src/actions/errorBars/create.js +56 -17
  101. package/src/actions/errorBars/edit.js +372 -21
  102. package/src/actions/facets/actions.js +619 -41
  103. package/src/actions/facets/derive.js +139 -25
  104. package/src/actions/gradientPlots/components.js +43 -13
  105. package/src/actions/gradientPlots/edit.js +14 -4
  106. package/src/actions/gradientPlots/materialize.js +8 -8
  107. package/src/actions/gradientPlots/options.js +10 -2
  108. package/src/actions/guides/applicability.js +28 -19
  109. package/src/actions/guides/axes/axes.js +4 -3
  110. package/src/actions/guides/axes/axis.js +18 -18
  111. package/src/actions/guides/axes/components.js +43 -0
  112. package/src/actions/guides/axes/edit.js +16 -51
  113. package/src/actions/guides/axes/labels.js +184 -28
  114. package/src/actions/guides/axes/lines.js +13 -7
  115. package/src/actions/guides/axes/parallel/lifecycle.js +117 -0
  116. package/src/actions/guides/axes/parallel/policy.js +137 -0
  117. package/src/actions/guides/axes/parallel/resolve.js +50 -25
  118. package/src/actions/guides/axes/parallel.js +93 -217
  119. package/src/actions/guides/axes/policy.js +21 -67
  120. package/src/actions/guides/axes/tickGroups.js +15 -8
  121. package/src/actions/guides/axes/ticks.js +11 -6
  122. package/src/actions/guides/axes/titles.js +32 -11
  123. package/src/actions/guides/basic.js +2 -0
  124. package/src/actions/guides/facade.js +106 -0
  125. package/src/actions/guides/facadeAxes.js +200 -0
  126. package/src/actions/guides/facadeLegend.js +63 -0
  127. package/src/actions/guides/grids/grid.js +37 -33
  128. package/src/actions/guides/grids/resolve.js +17 -4
  129. package/src/actions/guides/guides.js +54 -31
  130. package/src/actions/guides/legends/blocks.js +426 -0
  131. package/src/actions/guides/legends/categorical/actions.js +309 -279
  132. package/src/actions/guides/legends/categorical/components.js +21 -17
  133. package/src/actions/guides/legends/categorical/index.js +37 -33
  134. package/src/actions/guides/legends/categorical/layout.js +123 -354
  135. package/src/actions/guides/legends/categorical/options.js +32 -16
  136. package/src/actions/guides/legends/categorical/recipes.js +114 -9
  137. package/src/actions/guides/legends/categorical/resolve.js +30 -15
  138. package/src/actions/guides/legends/categorical/symbols.js +87 -33
  139. package/src/actions/guides/legends/continuous/common.js +99 -26
  140. package/src/actions/guides/legends/continuous/gradient.js +120 -89
  141. package/src/actions/guides/legends/continuous/index.js +8 -2
  142. package/src/actions/guides/legends/continuous/interval.js +79 -95
  143. package/src/actions/guides/legends/continuous/opacity.js +113 -89
  144. package/src/actions/guides/legends/continuous/stroke.js +525 -0
  145. package/src/actions/guides/legends/creation.js +40 -0
  146. package/src/actions/guides/legends/edit.js +321 -90
  147. package/src/actions/guides/legends/focused.js +2 -2
  148. package/src/actions/guides/legends/index.js +2 -0
  149. package/src/actions/guides/legends/lane.js +149 -102
  150. package/src/actions/guides/legends/lifecycle.js +143 -0
  151. package/src/actions/guides/legends/remove.js +43 -78
  152. package/src/actions/guides/legends/sampling.js +140 -0
  153. package/src/actions/guides/legends/size.js +213 -116
  154. package/src/actions/guides/legends/strokeWidth.js +121 -73
  155. package/src/actions/guides/legends/target.js +123 -0
  156. package/src/actions/guides/legends/transition.js +192 -0
  157. package/src/actions/guides/polar/axes/facade.js +81 -66
  158. package/src/actions/guides/polar/axes/labels.js +28 -8
  159. package/src/actions/guides/polar/axes/lines.js +12 -5
  160. package/src/actions/guides/polar/axes/shared.js +22 -0
  161. package/src/actions/guides/polar/axes/ticks.js +6 -5
  162. package/src/actions/guides/polar/axes/titles.js +6 -5
  163. package/src/actions/guides/polar/grids.js +8 -8
  164. package/src/actions/guides/polar/resolve.js +12 -8
  165. package/src/actions/guides/reuse.js +44 -0
  166. package/src/actions/guides/tickValues.js +19 -21
  167. package/src/actions/index.js +15 -2
  168. package/src/actions/intervals/resolve.js +35 -15
  169. package/src/actions/marks/arc/actions.js +78 -20
  170. package/src/actions/marks/area/actions.js +51 -12
  171. package/src/actions/marks/area/materialize.js +22 -3
  172. package/src/actions/marks/bar/create.js +11 -2
  173. package/src/actions/marks/bar/edit.js +20 -3
  174. package/src/actions/marks/bar/materialize.js +33 -9
  175. package/src/actions/marks/index.js +14 -0
  176. package/src/actions/marks/line/actions.js +71 -113
  177. package/src/actions/marks/line/materialize.js +57 -56
  178. package/src/actions/marks/point/create.js +8 -2
  179. package/src/actions/marks/point/edit.js +29 -21
  180. package/src/actions/marks/point/index.js +1 -0
  181. package/src/actions/marks/point/jitter.js +3 -0
  182. package/src/actions/marks/point/materialize.js +154 -16
  183. package/src/actions/marks/point/packing.js +68 -0
  184. package/src/actions/marks/rect/actions.js +33 -12
  185. package/src/actions/marks/references.js +658 -0
  186. package/src/actions/marks/remove.js +87 -4
  187. package/src/actions/marks/rule/actions.js +77 -9
  188. package/src/actions/marks/rule/appearance.js +26 -0
  189. package/src/actions/marks/shared.js +13 -13
  190. package/src/actions/marks/text/actions.js +296 -13
  191. package/src/actions/marks/text/index.js +4 -0
  192. package/src/actions/marks/text/layout.js +156 -8
  193. package/src/actions/marks/text/removal.js +173 -0
  194. package/src/actions/marks/text/selection.js +73 -0
  195. package/src/actions/marks/tick/actions.js +22 -5
  196. package/src/actions/primitives/createGraphics.js +3 -1
  197. package/src/actions/primitives/editGraphics.js +26 -0
  198. package/src/actions/primitives/semantic.js +3 -2
  199. package/src/actions/primitives/semanticAction.js +120 -10
  200. package/src/actions/primitives/semanticValidation/guide.js +10 -0
  201. package/src/actions/primitives/semanticValidation/index.js +9 -1
  202. package/src/actions/primitives/semanticValidation/layer.js +23 -1
  203. package/src/actions/primitives/semanticValidation/scale.js +38 -8
  204. package/src/actions/regression/components.js +26 -11
  205. package/src/actions/regression/create.js +11 -3
  206. package/src/actions/regression/edit.js +40 -13
  207. package/src/actions/regression/resolve.js +1 -1
  208. package/src/actions/resources/index.js +7 -0
  209. package/src/actions/resources/remove.js +172 -0
  210. package/src/actions/scales/channels.js +212 -0
  211. package/src/actions/scales/consumers/common.js +21 -54
  212. package/src/actions/scales/consumers/families.js +28 -14
  213. package/src/actions/scales/consumers/index.js +42 -4
  214. package/src/actions/scales/consumers/seriesLayout.js +57 -12
  215. package/src/actions/scales/create.js +58 -26
  216. package/src/actions/scales/definitions.js +109 -39
  217. package/src/actions/scales/edit.js +101 -34
  218. package/src/actions/scales/editPolicy.js +95 -35
  219. package/src/actions/scales/index.js +6 -0
  220. package/src/actions/scales/materialize.js +14 -49
  221. package/src/actions/scales/offset.js +48 -0
  222. package/src/actions/scales/parallel.js +71 -0
  223. package/src/actions/scales/patch.js +1 -1
  224. package/src/actions/scales/preview.js +140 -0
  225. package/src/actions/scales/quantitativeColor.js +9 -5
  226. package/src/actions/selection/actions.js +154 -30
  227. package/src/actions/selection/index.js +3 -0
  228. package/src/actions/theme/actions.js +98 -0
  229. package/src/actions/theme/composition.js +238 -0
  230. package/src/actions/theme/index.js +16 -0
  231. package/src/actions/theme/reconcile.js +1130 -0
  232. package/src/actions/theme/state.js +160 -0
  233. package/src/actions/titles/actions.js +11 -10
  234. package/src/actions/titles/resolve.js +1 -40
  235. package/src/actions/violinPlots/create.js +90 -43
  236. package/src/actions/violinPlots/edit.js +192 -0
  237. package/src/actions/violinPlots/index.js +2 -0
  238. package/src/core/ChartProgram.js +7 -0
  239. package/src/core/action.js +32 -2
  240. package/src/core/compositionState.js +141 -8
  241. package/src/core/programState.js +20 -0
  242. package/src/core/resourceReferences.js +332 -0
  243. package/src/core/vocabulary.js +16 -3
  244. package/src/grammar/aggregate.js +66 -23
  245. package/src/grammar/arcs.js +58 -1
  246. package/src/grammar/areaEndpoints.js +46 -0
  247. package/src/grammar/areaSeries.js +87 -41
  248. package/src/grammar/bars/aggregate.js +37 -13
  249. package/src/grammar/bars/geometry.js +44 -0
  250. package/src/grammar/bars/policy.js +9 -7
  251. package/src/grammar/bin.js +226 -0
  252. package/src/grammar/categoryOrder.js +34 -0
  253. package/src/grammar/complete.js +279 -0
  254. package/src/grammar/computed.js +351 -0
  255. package/src/grammar/coordinates.js +37 -0
  256. package/src/grammar/density.js +239 -37
  257. package/src/grammar/displayLabels.js +57 -0
  258. package/src/grammar/ecdf.js +198 -0
  259. package/src/grammar/facets/dependencies.js +133 -1
  260. package/src/grammar/facets/guides.js +3 -0
  261. package/src/grammar/facets/index.js +123 -52
  262. package/src/grammar/facets/scales.js +15 -18
  263. package/src/grammar/fold.js +123 -0
  264. package/src/grammar/horizon.js +6 -4
  265. package/src/grammar/impute.js +340 -0
  266. package/src/grammar/interval.js +37 -20
  267. package/src/grammar/lineSeries.js +20 -63
  268. package/src/grammar/markFilter.js +22 -4
  269. package/src/grammar/markLabelSelection.js +57 -0
  270. package/src/grammar/markLabels.js +110 -0
  271. package/src/grammar/normalize.js +366 -0
  272. package/src/grammar/parallelAxisTitles.js +16 -0
  273. package/src/grammar/pathSeries.js +109 -0
  274. package/src/grammar/pointPacking.js +183 -0
  275. package/src/grammar/pointShapes.js +13 -4
  276. package/src/grammar/polar.js +90 -8
  277. package/src/grammar/positionDatum.js +12 -0
  278. package/src/grammar/rects.js +9 -1
  279. package/src/grammar/regression/derive.js +4 -0
  280. package/src/grammar/regression/index.js +8 -2
  281. package/src/grammar/regression/models.js +22 -7
  282. package/src/grammar/regression/parameters.js +63 -13
  283. package/src/grammar/rotation.js +29 -0
  284. package/src/grammar/roundedRect.js +180 -0
  285. package/src/grammar/rules.js +8 -21
  286. package/src/grammar/scales/color.js +23 -1
  287. package/src/grammar/scales/colorConsumers.js +57 -0
  288. package/src/grammar/scales/continuous.js +2 -2
  289. package/src/grammar/scales/definition.js +42 -5
  290. package/src/grammar/scales/discretized.js +11 -5
  291. package/src/grammar/scales/fields.js +38 -8
  292. package/src/grammar/scales/index.js +1 -0
  293. package/src/grammar/scales/mapping.js +2 -0
  294. package/src/grammar/scales/ordinal.js +12 -3
  295. package/src/grammar/scales/policies.js +2 -2
  296. package/src/grammar/scales/radial.js +55 -0
  297. package/src/grammar/scales/size.js +456 -0
  298. package/src/grammar/scales/types.js +1 -0
  299. package/src/grammar/schemas/concreteGraphic.js +14 -2
  300. package/src/grammar/schemas/graphic.js +15 -0
  301. package/src/grammar/schemas/graphicBounds.js +179 -30
  302. package/src/grammar/schemas/semanticPath.js +23 -4
  303. package/src/grammar/stack.js +170 -0
  304. package/src/grammar/statisticalReference.js +103 -0
  305. package/src/grammar/statistics/confidenceInterval.js +101 -0
  306. package/src/grammar/strokeStyle.js +77 -0
  307. package/src/grammar/summary.js +245 -0
  308. package/src/grammar/text.js +22 -16
  309. package/src/grammar/timeUnit.js +234 -13
  310. package/src/grammar/transformTopology.js +10 -0
  311. package/src/grammar/transforms.js +418 -16
  312. package/src/grammar/valueFormat.js +112 -0
  313. package/src/grammar/weightedStatistics.js +374 -0
  314. package/src/grammar/window.js +232 -21
  315. package/src/layout/aspect.js +80 -0
  316. package/src/layout/facets.js +100 -12
  317. package/src/layout/guideCollisions.js +12 -0
  318. package/src/layout/labels.js +343 -0
  319. package/src/layout/legend.js +2 -10
  320. package/src/layout/legendItems.js +102 -0
  321. package/src/layout/legendLane.js +100 -11
  322. package/src/materialization/bars/aggregate.js +56 -147
  323. package/src/materialization/bars/histogram.js +104 -20
  324. package/src/materialization/bars/ranged.js +19 -3
  325. package/src/materialization/bars/resolve.js +7 -4
  326. package/src/materialization/categorySlotOffset.js +40 -0
  327. package/src/materialization/composition.js +3 -1
  328. package/src/materialization/compositionSnapshot.js +1 -1
  329. package/src/materialization/coordinateBounds.js +204 -0
  330. package/src/materialization/dependencies.js +93 -16
  331. package/src/materialization/encodings.js +1 -1
  332. package/src/materialization/facetGuides/legacyCategorical.js +3 -0
  333. package/src/materialization/facetGuides/placement.js +8 -2
  334. package/src/materialization/facetGuides/preparation.js +12 -7
  335. package/src/materialization/facetHeaders.js +346 -0
  336. package/src/materialization/facets.js +23 -66
  337. package/src/materialization/guides/layout.js +57 -0
  338. package/src/materialization/guides/resources.js +28 -2
  339. package/src/materialization/legends.js +11 -2
  340. package/src/materialization/marks/capabilities.js +20 -5
  341. package/src/materialization/marks/grouping.js +52 -0
  342. package/src/materialization/marks/index.js +68 -27
  343. package/src/materialization/marks/policies.js +4 -1
  344. package/src/materialization/rect.js +55 -42
  345. package/src/materialization/rectConfig.js +5 -1
  346. package/src/materialization/rowEncoding.js +13 -13
  347. package/src/materialization/scaleGuideDependencies.js +8 -5
  348. package/src/materialization/scales/map.js +6 -3
  349. package/src/materialization/scales/policies/arc.js +42 -0
  350. package/src/materialization/scales/policies/binnedPosition.js +7 -4
  351. package/src/materialization/scales/policies/offset.js +50 -8
  352. package/src/materialization/scales/policies/series.js +5 -1
  353. package/src/materialization/scales/resolve.js +65 -17
  354. package/src/materialization/selection/compatibility.js +11 -0
  355. package/src/materialization/selection/items/arc.js +28 -4
  356. package/src/materialization/selection/items/bar.js +42 -71
  357. package/src/materialization/selection/items/common.js +27 -6
  358. package/src/materialization/selection/items/path.js +3 -13
  359. package/src/materialization/selection/items/rect.js +35 -8
  360. package/src/materialization/selection/path.js +1 -1
  361. package/src/materialization/selection/point.js +3 -1
  362. package/src/materialization/text.js +324 -14
  363. package/src/mcp/adapter.js +2 -2
  364. package/src/renderers/canvas/circle.js +2 -3
  365. package/src/renderers/canvas/line.js +2 -3
  366. package/src/renderers/canvas/native.js +4 -4
  367. package/src/renderers/canvas/path.js +2 -3
  368. package/src/renderers/canvas/rect.js +2 -3
  369. package/src/renderers/canvas/stroke.js +11 -0
  370. package/src/renderers/svg.js +19 -0
  371. package/src/selectors/datasets.js +44 -0
  372. package/src/selectors/layers.js +7 -2
  373. package/src/selectors/scales.js +6 -0
  374. package/src/theme/defaults.js +140 -0
  375. package/types/basic.d.ts +17 -2
  376. package/types/index.d.ts +211 -0
  377. package/types/program.d.ts +2182 -204
  378. package/src/materialization/bars/grouped.js +0 -144
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ggaction",
3
- "version": "0.0.12",
3
+ "version": "0.0.15",
4
4
  "description": "Build charts through immutable, traceable graphical actions.",
5
5
  "license": "MIT",
6
6
  "author": "Hyeon Jeon",
@@ -111,18 +111,25 @@
111
111
  "docs:signatures:check": "node scripts/generate-doc-signatures.js --check",
112
112
  "examples:index": "node scripts/generate-examples-readme.js",
113
113
  "examples:index:check": "node scripts/generate-examples-readme.js --check",
114
- "docs:generate": "npm run examples:index && npm run docs:reference && npm run contracts:cards && npm run docs:actions && npm run docs:signatures && npm run docs:capabilities && npm run docs:metadata && npm run docs:search && npm run docs:images && npm run docs:machine && npm run docs:llms",
114
+ "docs:generate": "npm run docs:provenance && npm run docs:workflows && npm run examples:index && npm run docs:capabilities && npm run docs:reference && npm run contracts:relations && npm run contracts:cards && npm run docs:picker && npm run docs:scale-editors && npm run docs:actions && npm run docs:signatures && npm run docs:snippets && npm run docs:metadata && npm run docs:search && npm run docs:images && npm run docs:machine && npm run docs:llms",
115
115
  "docs:build": "bundle exec jekyll build --source docs --destination _site --baseurl /ggaction",
116
116
  "docs:verify": "npm run docs:preflight && npm run docs:generate && npm run test:docs && npm run docs:build && npm run test:docs:built && npm run test:docs:browser",
117
117
  "contracts:catalog": "node scripts/generate-action-catalog.js",
118
118
  "contracts:catalog:check": "node scripts/generate-action-catalog.js --check",
119
+ "contracts:relations": "node scripts/generate-action-relationships.js",
120
+ "contracts:relations:check": "node scripts/generate-action-relationships.js --check",
119
121
  "contracts:cards": "node scripts/generate-action-cards.js",
120
122
  "contracts:cards:check": "node scripts/generate-action-cards.js --check",
121
123
  "package:check": "node scripts/package-artifact.js --check",
122
124
  "package:pack": "node scripts/package-artifact.js --pack",
123
125
  "package:bundle": "node scripts/measure-browser-bundle.js",
124
126
  "test:package": "node scripts/package-consumer.js",
125
- "release:notes": "node scripts/release-notes.js"
127
+ "release:notes": "node scripts/release-notes.js",
128
+ "docs:workflows": "node scripts/generate-doc-workflows.js",
129
+ "docs:provenance": "node scripts/doc-provenance.js",
130
+ "docs:picker": "node scripts/generate-doc-chart-picker.js",
131
+ "docs:snippets": "node scripts/generate-doc-snippet-contracts.js",
132
+ "docs:scale-editors": "node scripts/generate-doc-scale-editors.js"
126
133
  },
127
134
  "engines": {
128
135
  "node": ">=20"
@@ -1,21 +1,23 @@
1
1
  import { registerBasicCanvasActions } from "./canvas/index.js";
2
2
  import { registerBasicChartActions } from "./charts/basic.js";
3
- import { registerCoordinateActions } from "./coordinates/actions.js";
3
+ import { registerBasicCoordinateActions } from "./coordinates/actions.js";
4
4
  import { registerBasicDataActions } from "./data/basic.js";
5
5
  import { registerBasicEncodingActions } from "./encodings/basic.js";
6
6
  import { registerBasicGuideActions } from "./guides/basic.js";
7
7
  import { registerBasicMarkActions } from "./marks/basic.js";
8
8
  import { registerBasicPrimitiveActions } from "./primitives/index.js";
9
9
  import { registerBasicScaleActions } from "./scales/index.js";
10
+ import { registerThemeActions } from "./theme/index.js";
10
11
 
11
12
  export function registerBasicActions(ProgramClass) {
13
+ registerThemeActions(ProgramClass);
12
14
  registerBasicPrimitiveActions(ProgramClass);
13
15
  registerBasicCanvasActions(ProgramClass);
14
16
  registerBasicDataActions(ProgramClass);
15
17
  registerBasicMarkActions(ProgramClass);
16
18
  registerBasicScaleActions(ProgramClass);
17
19
  registerBasicEncodingActions(ProgramClass);
18
- registerCoordinateActions(ProgramClass);
20
+ registerBasicCoordinateActions(ProgramClass);
19
21
  registerBasicGuideActions(ProgramClass);
20
22
  registerBasicChartActions(ProgramClass);
21
23
  }
@@ -1,14 +1,19 @@
1
1
  import { action } from "../../core/action.js";
2
2
  import { validateKeys } from "../../core/validation.js";
3
+ import {
4
+ requestedStrokeDetails,
5
+ STROKE_STYLE_PROPERTIES
6
+ } from "../../grammar/strokeStyle.js";
3
7
 
4
8
  const MEDIAN_OPTIONS = Object.freeze([
5
9
  "id", "owner", "data", "category", "categoryType", "measure",
6
10
  "coordinate", "categoryScale", "measureScale", "orientation", "stroke",
7
- "strokeWidth"
11
+ "strokeWidth", ...STROKE_STYLE_PROPERTIES
8
12
  ]);
9
13
  const OUTLIER_OPTIONS = Object.freeze([
10
14
  "id", "data", "category", "categoryType", "measure", "coordinate",
11
- "categoryScale", "measureScale", "orientation", "shape", "radius", "opacity"
15
+ "categoryScale", "measureScale", "orientation", "shape", "radius", "opacity",
16
+ ...STROKE_STYLE_PROPERTIES
12
17
  ]);
13
18
 
14
19
  export const createBoxMedian = action(
@@ -23,7 +28,11 @@ export const createBoxMedian = action(
23
28
  }
24
29
  const categoryAction = args.orientation === "vertical" ? "encodeX" : "encodeY";
25
30
  const measureAction = args.orientation === "vertical" ? "encodeY" : "encodeX";
26
- let next = this.createRuleMark({ id: args.id, data: args.data });
31
+ let next = this.createRuleMark({
32
+ id: args.id,
33
+ data: args.data,
34
+ ...requestedStrokeDetails(args, "Box median")
35
+ });
27
36
  next = next[categoryAction]({
28
37
  target: args.id,
29
38
  field: args.category,
@@ -65,7 +74,8 @@ export const createBoxOutliers = action(
65
74
  id: args.id,
66
75
  data: args.data,
67
76
  shape: args.shape,
68
- fill: "#111111"
77
+ fill: "#111111",
78
+ ...requestedStrokeDetails(args, "Box outlier")
69
79
  });
70
80
  next = next[categoryAction]({
71
81
  target: args.id,
@@ -24,6 +24,8 @@ import {
24
24
  resolveBoxWidth
25
25
  } from "./options.js";
26
26
  import { resolveBoxOrientation } from "./resolve.js";
27
+ import { requestedRectStyleDetails } from "../../grammar/roundedRect.js";
28
+ import { requestedStrokeDetails } from "../../grammar/strokeStyle.js";
27
29
 
28
30
  const OPTIONS = Object.freeze([
29
31
  "target", "data", "x", "y", "whisker", "width", "outliers", "box",
@@ -252,6 +254,8 @@ export const editBoxPlot = action(
252
254
  { ...current.outlier, ...outlierPatch },
253
255
  "editBoxPlot"
254
256
  );
257
+ const boxStyleDetails = requestedRectStyleDetails(box, "Box body");
258
+ const medianStyleDetails = requestedStrokeDetails(median, "Box median");
255
259
  if (Object.hasOwn(boxPatch, "fill") && owner.encoding?.color !== undefined) {
256
260
  throw new Error(
257
261
  "editBoxPlot box.fill cannot be combined with a color encoding."
@@ -333,6 +337,7 @@ export const editBoxPlot = action(
333
337
  ...next.markConfigs[current.whiskerId],
334
338
  errorBar: {
335
339
  ...next.markConfigs[current.whiskerId].errorBar,
340
+ source: summaryRevision.id,
336
341
  data: summaryRevision.id
337
342
  }
338
343
  });
@@ -360,7 +365,10 @@ export const editBoxPlot = action(
360
365
  fill: box.fill,
361
366
  opacity: box.opacity,
362
367
  stroke: box.stroke,
363
- strokeWidth: box.strokeWidth
368
+ strokeWidth: box.strokeWidth,
369
+ ...(Object.keys(boxStyleDetails).length === 0
370
+ ? {}
371
+ : { barAppearance: boxStyleDetails })
364
372
  });
365
373
  next = updateBoxPositions(next, owner, current, candidate, {
366
374
  outlierDataId: outlierRevision?.id,
@@ -385,7 +393,8 @@ export const editBoxPlot = action(
385
393
  measureScale: measure.scale,
386
394
  shape: outlier.shape,
387
395
  radius: outlier.radius,
388
- opacity: outlier.opacity
396
+ opacity: outlier.opacity,
397
+ ...requestedStrokeDetails(outlier, "Box outlier")
389
398
  });
390
399
  }
391
400
  next = next
@@ -394,12 +403,19 @@ export const editBoxPlot = action(
394
403
  target: current.medianId,
395
404
  value: median.strokeWidth
396
405
  });
406
+ if (Object.keys(medianStyleDetails).length > 0) {
407
+ next = next.editRuleMark({
408
+ target: current.medianId,
409
+ ...medianStyleDetails
410
+ });
411
+ }
397
412
  if (findLayer(next, current.outlierId) !== undefined) {
398
413
  next = next
399
414
  .editPointMark({
400
415
  target: current.outlierId,
401
416
  shape: outlier.shape,
402
- opacity: outlier.opacity
417
+ opacity: outlier.opacity,
418
+ ...requestedStrokeDetails(outlier, "Box outlier")
403
419
  })
404
420
  .encodeRadius({ target: current.outlierId, value: outlier.radius });
405
421
  }
@@ -445,7 +461,10 @@ export const editBoxPlot = action(
445
461
  fill: box.fill,
446
462
  opacity: box.opacity,
447
463
  stroke: box.stroke,
448
- strokeWidth: box.strokeWidth
464
+ strokeWidth: box.strokeWidth,
465
+ ...(Object.keys(boxStyleDetails).length === 0
466
+ ? {}
467
+ : { barAppearance: boxStyleDetails })
449
468
  });
450
469
 
451
470
  if (changesBox) next = next.rematerializeBarMark({ id: owner.id });
@@ -456,13 +475,20 @@ export const editBoxPlot = action(
456
475
  target: current.medianId,
457
476
  value: median.strokeWidth
458
477
  });
478
+ if (Object.keys(medianStyleDetails).length > 0) {
479
+ next = next.editRuleMark({
480
+ target: current.medianId,
481
+ ...medianStyleDetails
482
+ });
483
+ }
459
484
  }
460
485
  if (findLayer(next, current.outlierId) !== undefined && changesOutlier) {
461
486
  next = next
462
487
  .editPointMark({
463
488
  target: current.outlierId,
464
489
  shape: outlier.shape,
465
- opacity: outlier.opacity
490
+ opacity: outlier.opacity,
491
+ ...requestedStrokeDetails(outlier, "Box outlier")
466
492
  })
467
493
  .encodeRadius({ target: current.outlierId, value: outlier.radius });
468
494
  }
@@ -1,3 +1,4 @@
1
+ import { applyFacadeGuides } from "../charts/shared.js";
1
2
  import { action } from "../../core/action.js";
2
3
  import { validateUserId } from "../../core/identifiers.js";
3
4
  import {
@@ -8,6 +9,8 @@ import {
8
9
  import { findDataset } from "../../selectors/datasets.js";
9
10
  import { findLayer } from "../../selectors/layers.js";
10
11
  import { resolveBoxOrientation } from "./resolve.js";
12
+ import { requestedRectStyleDetails } from "../../grammar/roundedRect.js";
13
+ import { requestedStrokeDetails } from "../../grammar/strokeStyle.js";
11
14
  import { resolvePlotGraphicPlacement } from
12
15
  "../../materialization/graphicHierarchy.js";
13
16
 
@@ -42,6 +45,7 @@ export const materializeBoxPlot = action(
42
45
  const whiskerId = `${ownerId}Whisker`;
43
46
  const medianId = `${ownerId}Median`;
44
47
  const outlierId = `${ownerId}Outliers`;
48
+ const boxStyleDetails = requestedRectStyleDetails(config.box, "Box body");
45
49
  let next = this._withMarkConfig(ownerId, {
46
50
  ...this.markConfigs[ownerId],
47
51
  boxPlot: {
@@ -60,7 +64,10 @@ export const materializeBoxPlot = action(
60
64
  fill: config.box.fill,
61
65
  opacity: config.box.opacity,
62
66
  stroke: config.box.stroke,
63
- strokeWidth: config.box.strokeWidth
67
+ strokeWidth: config.box.strokeWidth,
68
+ ...(Object.keys(boxStyleDetails).length === 0
69
+ ? {}
70
+ : { barAppearance: boxStyleDetails })
64
71
  }).createBoxSummaryData({
65
72
  id: summaryId,
66
73
  source,
@@ -164,7 +171,8 @@ export const materializeBoxPlot = action(
164
171
  categoryScale: category.scale,
165
172
  measureScale: measure.scale,
166
173
  stroke: config.median.stroke,
167
- strokeWidth: config.median.strokeWidth
174
+ strokeWidth: config.median.strokeWidth,
175
+ ...requestedStrokeDetails(config.median, "Box median")
168
176
  });
169
177
  if (hasOutliers) {
170
178
  next = next.createBoxOutliers({
@@ -179,7 +187,8 @@ export const materializeBoxPlot = action(
179
187
  measureScale: measure.scale,
180
188
  shape: config.outlier.shape,
181
189
  radius: config.outlier.radius,
182
- opacity: config.outlier.opacity
190
+ opacity: config.outlier.opacity,
191
+ ...requestedStrokeDetails(config.outlier, "Box outlier")
183
192
  });
184
193
  }
185
194
  next = next._withMarkConfig(ownerId, {
@@ -190,7 +199,7 @@ export const materializeBoxPlot = action(
190
199
  }
191
200
  });
192
201
  if (config.guides !== false) {
193
- next = next.createGuides(config.guides);
202
+ next = applyFacadeGuides(next, config.guides, ownerId);
194
203
  }
195
204
  return next._withContext({ currentMark: ownerId, currentData: source });
196
205
  }
@@ -7,6 +7,14 @@ import {
7
7
  validateUnitInterval
8
8
  } from "../../core/validation.js";
9
9
  import { validatePointShape } from "../../grammar/pointShapes.js";
10
+ import {
11
+ requestedRectStyleDetails,
12
+ RECT_STYLE_PROPERTIES
13
+ } from "../../grammar/roundedRect.js";
14
+ import {
15
+ requestedStrokeDetails,
16
+ STROKE_STYLE_PROPERTIES
17
+ } from "../../grammar/strokeStyle.js";
10
18
  import { DEFAULT_COLORS } from "../../theme/defaults.js";
11
19
  import { normalizeGuides } from "../charts/shared.js";
12
20
 
@@ -45,24 +53,30 @@ function plainOptions(value, keys, label, operation = "createBoxPlot") {
45
53
  return value;
46
54
  }
47
55
 
48
- function resolveAppearance(value, defaults, label, operation) {
56
+ function resolveAppearance(value, defaults, label, operation, details) {
49
57
  const options = plainOptions(
50
58
  value,
51
- Object.keys(defaults),
59
+ [
60
+ ...Object.keys(defaults),
61
+ ...(details === requestedRectStyleDetails
62
+ ? RECT_STYLE_PROPERTIES
63
+ : STROKE_STYLE_PROPERTIES)
64
+ ],
52
65
  label,
53
66
  operation
54
67
  );
55
- return Object.freeze(Object.fromEntries(
56
- Object.entries(defaults).map(([key, fallback]) => [
57
- key,
58
- options[key] === undefined
59
- ? fallback
60
- : APPEARANCE_VALIDATORS[key](
61
- options[key],
62
- `createBoxPlot ${label}.${key}`
63
- )
64
- ])
65
- ));
68
+ return Object.freeze({
69
+ ...Object.fromEntries(Object.entries(defaults).map(([key, fallback]) => [
70
+ key,
71
+ options[key] === undefined
72
+ ? fallback
73
+ : APPEARANCE_VALIDATORS[key](
74
+ options[key],
75
+ `${operation} ${label}.${key}`
76
+ )
77
+ ])),
78
+ ...details(options, `${operation} ${label}`)
79
+ });
66
80
  }
67
81
 
68
82
  export function resolveBoxPosition(value, label, operation = "createBoxPlot") {
@@ -122,13 +136,31 @@ export function resolveBoxWidth(value, operation = "createBoxPlot") {
122
136
  }
123
137
 
124
138
  export function resolveBoxAppearance(value, operation = "createBoxPlot") {
125
- return resolveAppearance(value, DEFAULT_BOX, "box", operation);
139
+ return resolveAppearance(
140
+ value,
141
+ DEFAULT_BOX,
142
+ "box",
143
+ operation,
144
+ requestedRectStyleDetails
145
+ );
126
146
  }
127
147
 
128
148
  export function resolveBoxMedianAppearance(value, operation = "createBoxPlot") {
129
- return resolveAppearance(value, DEFAULT_MEDIAN, "median", operation);
149
+ return resolveAppearance(
150
+ value,
151
+ DEFAULT_MEDIAN,
152
+ "median",
153
+ operation,
154
+ requestedStrokeDetails
155
+ );
130
156
  }
131
157
 
132
158
  export function resolveBoxOutlierAppearance(value, operation = "createBoxPlot") {
133
- return resolveAppearance(value, DEFAULT_OUTLIER, "outlier", operation);
159
+ return resolveAppearance(
160
+ value,
161
+ DEFAULT_OUTLIER,
162
+ "outlier",
163
+ operation,
164
+ requestedStrokeDetails
165
+ );
134
166
  }
@@ -161,7 +161,9 @@ export const createBasicCanvas = action(
161
161
  background: Object.hasOwn(args, "background")
162
162
  ? args.background
163
163
  : DEFAULT_CANVAS.background,
164
- margin: normalizeMargin(args.margin, DEFAULT_MARGIN),
164
+ margin: Object.hasOwn(args, "margin")
165
+ ? normalizeMargin(args.margin, DEFAULT_MARGIN)
166
+ : DEFAULT_MARGIN,
165
167
  size: {
166
168
  width: Object.hasOwn(args, "width") ? "explicit" : "auto",
167
169
  height: Object.hasOwn(args, "height") ? "explicit" : "auto"
@@ -0,0 +1,211 @@
1
+ import { action } from "../../core/action.js";
2
+ import {
3
+ validateNonNegativeFinite,
4
+ validatePositiveFinite,
5
+ validateOptionObject
6
+ } from "../../core/validation.js";
7
+ import { resolveGraphicBounds } from "../../layout/canvas.js";
8
+ import { findCanvasGraphic } from
9
+ "../../materialization/graphicHierarchy.js";
10
+
11
+ const OPTIONS = Object.freeze([
12
+ "padding",
13
+ "minPlotWidth",
14
+ "minPlotHeight",
15
+ "iterationLimit",
16
+ "overflow"
17
+ ]);
18
+ const SIDES = Object.freeze(["top", "right", "bottom", "left"]);
19
+ const DEFAULTS = Object.freeze({
20
+ padding: 0,
21
+ minPlotWidth: 160,
22
+ minPlotHeight: 120,
23
+ iterationLimit: 32,
24
+ overflow: "error"
25
+ });
26
+ const UNITS_PER_PIXEL = 4;
27
+
28
+ function normalizeOptions(args) {
29
+ validateOptionObject(args, OPTIONS, "fitCanvas", { allowEmpty: true });
30
+ const policy = { ...DEFAULTS, ...args };
31
+ validateNonNegativeFinite(policy.padding, "fitCanvas padding");
32
+ validatePositiveFinite(policy.minPlotWidth, "fitCanvas minPlotWidth");
33
+ validatePositiveFinite(policy.minPlotHeight, "fitCanvas minPlotHeight");
34
+ if (!Number.isInteger(policy.iterationLimit) ||
35
+ policy.iterationLimit <= 0 || policy.iterationLimit > 64) {
36
+ throw new RangeError(
37
+ "fitCanvas iterationLimit must be an integer from 1 through 64."
38
+ );
39
+ }
40
+ if (!["error", "report"].includes(policy.overflow)) {
41
+ throw new Error(`Unsupported fitCanvas overflow policy "${policy.overflow}".`);
42
+ }
43
+ return policy;
44
+ }
45
+
46
+ function probe(program, margin) {
47
+ try {
48
+ return { ok: true, program: program.editCanvas({ margin }) };
49
+ } catch (error) {
50
+ return {
51
+ ok: false,
52
+ message: error instanceof Error ? error.message : String(error)
53
+ };
54
+ }
55
+ }
56
+
57
+ function marginWith(margin, side, value) {
58
+ return { ...margin, [side]: value };
59
+ }
60
+
61
+ function minimizeSide(program, margin, side, policy) {
62
+ const current = margin[side];
63
+ const floor = Math.ceil(policy.padding * UNITS_PER_PIXEL) /
64
+ UNITS_PER_PIXEL;
65
+ if (floor > current) {
66
+ const expanded = marginWith(margin, side, floor);
67
+ const result = probe(program, expanded);
68
+ return result.ok
69
+ ? { program: result.program, margin: expanded, iterations: 1, issues: [] }
70
+ : {
71
+ program,
72
+ margin,
73
+ iterations: 1,
74
+ issues: [`${side} padding: ${result.message}`]
75
+ };
76
+ }
77
+
78
+ let low = Math.ceil(policy.padding * UNITS_PER_PIXEL);
79
+ let high = Math.floor(current * UNITS_PER_PIXEL);
80
+ if (low > high) {
81
+ return { program, margin, iterations: 0, issues: [] };
82
+ }
83
+
84
+ const cache = new Map();
85
+ const test = units => {
86
+ if (cache.has(units)) return cache.get(units);
87
+ const result = probe(
88
+ program,
89
+ marginWith(margin, side, units / UNITS_PER_PIXEL)
90
+ );
91
+ cache.set(units, result);
92
+ return result;
93
+ };
94
+ let iterations = 0;
95
+ const upper = test(high);
96
+ iterations += 1;
97
+ if (!upper.ok) {
98
+ return { program, margin, iterations, issues: [] };
99
+ }
100
+
101
+ while (low < high && iterations < policy.iterationLimit) {
102
+ const middle = Math.floor((low + high) / 2);
103
+ const result = test(middle);
104
+ iterations += 1;
105
+ if (result.ok) high = middle;
106
+ else low = middle + 1;
107
+ }
108
+ const best = test(high);
109
+ const fittedMargin = marginWith(
110
+ margin,
111
+ side,
112
+ high / UNITS_PER_PIXEL
113
+ );
114
+ return {
115
+ program: best.program,
116
+ margin: fittedMargin,
117
+ iterations,
118
+ issues: low === high
119
+ ? []
120
+ : [`${side} fitting reached iterationLimit ${policy.iterationLimit}`]
121
+ };
122
+ }
123
+
124
+ function fitMargins(program, policy) {
125
+ let probeProgram = program;
126
+ let margin = { ...program.materializationConfigs.canvas.margin };
127
+ let iterations = 0;
128
+ const issues = [];
129
+ for (const side of SIDES) {
130
+ const result = minimizeSide(probeProgram, margin, side, policy);
131
+ probeProgram = result.program;
132
+ margin = result.margin;
133
+ iterations += result.iterations;
134
+ issues.push(...result.issues);
135
+ }
136
+ return { margin, iterations, issues };
137
+ }
138
+
139
+ function sameMargin(first, second) {
140
+ return SIDES.every(side => first[side] === second[side]);
141
+ }
142
+
143
+ function samePolicy(first, second) {
144
+ return OPTIONS.every(option => first?.[option] === second[option]);
145
+ }
146
+
147
+ function layoutSignature(program) {
148
+ const source = JSON.stringify({
149
+ graphicSpec: program.graphicSpec,
150
+ canvas: program.materializationConfigs.canvas,
151
+ guides: program.materializationConfigs.guides,
152
+ title: program.materializationConfigs.title
153
+ });
154
+ let hash = 0xcbf29ce484222325n;
155
+ for (let index = 0; index < source.length; index += 1) {
156
+ hash ^= BigInt(source.charCodeAt(index));
157
+ hash = BigInt.asUintN(64, hash * 0x100000001b3n);
158
+ }
159
+ return hash.toString(16).padStart(16, "0");
160
+ }
161
+
162
+ export const fitCanvas = action(
163
+ {
164
+ op: "fitCanvas",
165
+ description: "Fit Canvas margins around existing layout resources."
166
+ },
167
+ function (args = {}) {
168
+ const policy = normalizeOptions(args);
169
+ const canvas = findCanvasGraphic(this);
170
+ if (canvas?.type !== "canvas" ||
171
+ this.materializationConfigs.canvas?.margin === undefined) {
172
+ throw new Error("fitCanvas requires an existing Canvas.");
173
+ }
174
+ const previous = this.materializationConfigs.fitting;
175
+ if (samePolicy(previous?.policy, policy) &&
176
+ previous?.result?.signature === layoutSignature(this)) {
177
+ return this;
178
+ }
179
+ const sourceMargin = this.materializationConfigs.canvas.margin;
180
+ const fitted = fitMargins(this, policy);
181
+ let next = sameMargin(sourceMargin, fitted.margin)
182
+ ? this
183
+ : this.editCanvas({ margin: fitted.margin });
184
+ const plot = resolveGraphicBounds(next);
185
+ if (plot.width < policy.minPlotWidth) {
186
+ fitted.issues.push(
187
+ `plot width ${plot.width} is smaller than minPlotWidth ${policy.minPlotWidth}`
188
+ );
189
+ }
190
+ if (plot.height < policy.minPlotHeight) {
191
+ fitted.issues.push(
192
+ `plot height ${plot.height} is smaller than minPlotHeight ${policy.minPlotHeight}`
193
+ );
194
+ }
195
+ if (fitted.issues.length > 0 && policy.overflow === "error") {
196
+ throw new Error(`fitCanvas overflow: ${fitted.issues.join("; ")}.`);
197
+ }
198
+ next = next._withMaterializationConfig(["fitting"], {
199
+ policy,
200
+ result: {
201
+ status: fitted.issues.length === 0 ? "fit" : "overflow",
202
+ margin: fitted.margin,
203
+ plot: { width: plot.width, height: plot.height },
204
+ iterations: fitted.iterations,
205
+ issues: fitted.issues,
206
+ signature: layoutSignature(next)
207
+ }
208
+ });
209
+ return next;
210
+ }
211
+ );
@@ -1,8 +1,10 @@
1
1
  import { createBasicCanvas, createCanvas, editCanvas } from "./actions.js";
2
+ import { fitCanvas } from "./fitting.js";
2
3
 
3
4
  export function registerCanvasActions(ProgramClass) {
4
5
  ProgramClass.prototype.editCanvas = editCanvas;
5
6
  ProgramClass.prototype.createCanvas = createCanvas;
7
+ ProgramClass.prototype.fitCanvas = fitCanvas;
6
8
  }
7
9
 
8
10
  export function registerBasicCanvasActions(ProgramClass) {
@@ -8,9 +8,13 @@ import {
8
8
  applyMaterializationPlan,
9
9
  planScaleGuideRematerialization
10
10
  } from "../../materialization/dependencies.js";
11
- import { getMarkMaterializationStep } from "../../materialization/marks/index.js";
11
+ import {
12
+ getMarkMaterializationStep,
13
+ getSourceDependentMarkSteps
14
+ } from "../../materialization/marks/index.js";
12
15
  import { buildMaterializationPlan } from "../../materialization/planner.js";
13
16
  import {
17
+ CATEGORY_ORDER_CHANNELS,
14
18
  normalizeCategoryOrder,
15
19
  resolveCategoryOrder
16
20
  } from "../../grammar/categoryOrder.js";
@@ -19,8 +23,8 @@ const ORDER_OPTIONS = Object.freeze(["target", "channel", "values", "by", "direc
19
23
  const REMOVE_OPTIONS = Object.freeze(["target", "channel"]);
20
24
 
21
25
  function resolveAssignment(program, args, operation, { activeOnly = false } = {}) {
22
- if (!["x", "y"].includes(args.channel)) {
23
- throw new Error(`${operation} channel must be x or y.`);
26
+ if (!CATEGORY_ORDER_CHANNELS.includes(args.channel)) {
27
+ throw new Error(`${operation} channel must be x, y, or theta.`);
24
28
  }
25
29
  const requested = args.target === undefined
26
30
  ? undefined
@@ -55,14 +59,22 @@ function resolveAssignment(program, args, operation, { activeOnly = false } = {}
55
59
 
56
60
  function rematerializeAssignment(program, scaleId) {
57
61
  const consumers = findScaleConsumers(program, scaleId);
62
+ const directMarks = consumers.map(consumer =>
63
+ getMarkMaterializationStep(program, consumer.layer)
64
+ );
58
65
  return applyMaterializationPlan(program, buildMaterializationPlan({
59
66
  scales: [{
60
67
  op: "rematerializeScale",
61
68
  args: { id: scaleId, guides: false, marks: false }
62
69
  }],
63
- marks: consumers.map(consumer =>
64
- getMarkMaterializationStep(program, consumer.layer)
65
- ),
70
+ marks: [
71
+ ...directMarks,
72
+ ...directMarks.flatMap(step =>
73
+ step === undefined
74
+ ? []
75
+ : getSourceDependentMarkSteps(program, step.args.id)
76
+ )
77
+ ],
66
78
  guides: planScaleGuideRematerialization(program, scaleId)
67
79
  }));
68
80
  }