diff --git a/__tests__/integration/api-chart-options-callback-children.spec.ts b/__tests__/integration/api-chart-options-callback-children.spec.ts new file mode 100644 index 0000000000..b30f18ba4f --- /dev/null +++ b/__tests__/integration/api-chart-options-callback-children.spec.ts @@ -0,0 +1,27 @@ +import { chartOptionsCallbackChildren as render } from '../plots/api/chart-options-callback-children'; +import { createNodeGCanvas } from './utils/createNodeGCanvas'; +import { sleep } from './utils/sleep'; +import { kebabCase } from './utils/kebabCase'; +import './utils/useSnapshotMatchers'; +import './utils/useCustomFetch'; + +describe('chart.options', () => { + const dir = `${__dirname}/snapshots/api/${kebabCase(render.name)}`; + const canvas = createNodeGCanvas(480, 480); + let chart; + + it('chart.options should return node with callback children.', async () => { + const { finished, ...rest } = render({ + canvas, + container: document.createElement('div'), + }); + chart = rest.chart; + await finished; + await sleep(20); + await expect(canvas).toMatchCanvasSnapshot(dir, 'step0'); + }); + + afterAll(() => { + canvas?.destroy(); + }); +}); diff --git a/__tests__/integration/snapshots/api/chart-options-callback-children/step0.png b/__tests__/integration/snapshots/api/chart-options-callback-children/step0.png new file mode 100644 index 0000000000..51453f57a7 Binary files /dev/null and b/__tests__/integration/snapshots/api/chart-options-callback-children/step0.png differ diff --git a/__tests__/plots/api/chart-options-callback-children.ts b/__tests__/plots/api/chart-options-callback-children.ts new file mode 100644 index 0000000000..c97dfdf86f --- /dev/null +++ b/__tests__/plots/api/chart-options-callback-children.ts @@ -0,0 +1,34 @@ +import { Chart } from '../../../src'; + +export function chartOptionsCallbackChildren(context) { + const { container, canvas } = context; + + const chart = new Chart({ + container, + canvas, + }); + + chart.options({ + type: 'repeatMatrix', + width: 480, + height: 480, + paddingLeft: 50, + paddingBottom: 50, + data: { + type: 'fetch', + value: 'data/penguins.csv', + }, + encode: { + position: ['culmen_length_mm', 'culmen_depth_mm'], + color: 'species', + }, + children: () => ({ + type: 'point', + encode: { color: 'species' }, + }), + }); + + const finished = chart.render(); + + return { chart, finished }; +} diff --git a/__tests__/plots/api/index.ts b/__tests__/plots/api/index.ts index 12754ac91d..3f2767f7b7 100644 --- a/__tests__/plots/api/index.ts +++ b/__tests__/plots/api/index.ts @@ -51,3 +51,4 @@ export { chartRender3dLinePlot } from './chart-render-3d-line-plot'; export { chartRender3dLinePlotPerspective } from './chart-render-3d-line-plot-perspective'; export { chartOnBrushHighlightTooltip } from './chart-on-brush-highlight-tooltip'; export { chartChangeSizeCustomShape } from './chart-change-size-custom-shape'; +export { chartOptionsCallbackChildren } from './chart-options-callback-children'; diff --git a/src/api/utils.ts b/src/api/utils.ts index 11994400e5..d56419a34d 100644 --- a/src/api/utils.ts +++ b/src/api/utils.ts @@ -31,6 +31,8 @@ export const VIEW_KEYS = [ export const REMOVE_FLAG = '__remove__'; +export const CALLBACK_NODE = '__callback__'; + export function normalizeContainer( container: string | HTMLElement, ): HTMLElement { @@ -84,12 +86,16 @@ export function optionsOf(node: Node): Record { const value = nodeValue.get(node); const { children = [] } = node; for (const child of children) { - const childValue = valueOf(child); - const { children = [] } = value; - children.push(childValue); - discovered.push(child); - nodeValue.set(child, childValue); - value.children = children; + if (child.type === CALLBACK_NODE) { + value.children = child.value; + } else { + const childValue = valueOf(child); + const { children = [] } = value; + children.push(childValue); + discovered.push(child); + nodeValue.set(child, childValue); + value.children = children; + } } } return nodeValue.get(root); @@ -142,6 +148,12 @@ function createNode( mark: Record Node>, composition: Record Node>, ): Node { + if (typeof options === 'function') { + const node = new Node(); + node.value = options; + node.type = CALLBACK_NODE; + return node; + } const { type, children, ...value } = options; const Ctor = typeCtor(type, mark, composition); const node = new Ctor(); @@ -182,6 +194,8 @@ function appendNode( for (const child of children) { discovered.push([node, child]); } + } else if (typeof children === 'function') { + discovered.push([node, children]); } } } @@ -216,6 +230,8 @@ export function updateRoot( const oldChild = oldChildren[i]; discovered.push([oldNode, oldChild, newChild]); } + } else if (typeof newChildren === 'function') { + discovered.push([oldNode, null, newChildren]); } } }