diff --git a/packages/board-plugins/src/index.ts b/packages/board-plugins/src/index.ts index 1d2463e9..2aeaf836 100644 --- a/packages/board-plugins/src/index.ts +++ b/packages/board-plugins/src/index.ts @@ -1,2 +1,3 @@ export * from './css-vars-plugin'; export * from './react-context-plugin'; +export * from './react-wrapper-plugin'; diff --git a/packages/board-plugins/src/react-wrapper-plugin.tsx b/packages/board-plugins/src/react-wrapper-plugin.tsx new file mode 100644 index 00000000..36970edd --- /dev/null +++ b/packages/board-plugins/src/react-wrapper-plugin.tsx @@ -0,0 +1,27 @@ +import { createPlugin } from '@wixc3/board-core'; +import type { IReactBoard } from '@wixc3/react-board'; +import React from 'react'; + +export interface WrapperPluginProps { + wrapper: React.ComponentType; +} + +export const reactWrapperPlugin = createPlugin()( + 'React-wrapper', + {}, + { + wrapRender({ wrapper: WrapperComponent }, _metaData, el) { + return {el}; + }, + }, + (params) => { + const usedWrappers = new Set(); + return params.filter((p) => { + if (usedWrappers.has(p.wrapper)) { + return false; + } + usedWrappers.add(p.wrapper); + return true; + }); + }, +); diff --git a/packages/board-plugins/test/fixtures/wrapper-user.board.tsx b/packages/board-plugins/test/fixtures/wrapper-user.board.tsx new file mode 100644 index 00000000..3842e4ff --- /dev/null +++ b/packages/board-plugins/test/fixtures/wrapper-user.board.tsx @@ -0,0 +1,14 @@ +import { reactWrapperPlugin } from '@wixc3/board-plugins'; +import { createBoard } from '@wixc3/react-board'; + +export default createBoard({ + name: 'Wrapper user', + Board: () => { + return 'board text'; + }, + plugins: [ + reactWrapperPlugin.use({ + wrapper: ({ children }: React.PropsWithChildren) =>
wrapper text {children}
, + }), + ], +}); diff --git a/packages/board-plugins/test/react-wrapper-plugin.spec.ts b/packages/board-plugins/test/react-wrapper-plugin.spec.ts new file mode 100644 index 00000000..b5639390 --- /dev/null +++ b/packages/board-plugins/test/react-wrapper-plugin.spec.ts @@ -0,0 +1,17 @@ +import { expect } from 'chai'; +import { createDisposables } from '@wixc3/create-disposables'; +import board from './fixtures/wrapper-user.board'; + +describe('react wrapper plugin', () => { + const disposables = createDisposables(); + afterEach(disposables.dispose); + + it('wraps the board with wrapper', async () => { + const { canvas, cleanup } = board.setupStage(); + disposables.add(cleanup); + const cleanupRender = await board.render(canvas); + disposables.add(cleanupRender); + + expect(canvas.innerText).to.include('wrapper text board text'); + }); +}); diff --git a/packages/react-board/src/create-board.tsx b/packages/react-board/src/create-board.tsx index 7f626205..07ed6cf8 100644 --- a/packages/react-board/src/create-board.tsx +++ b/packages/react-board/src/create-board.tsx @@ -3,17 +3,18 @@ import { reactErrorHandledRendering } from './react-error-handled-render'; import type { IReactBoard, OmitReactBoard } from './types'; export function createBoard(input: OmitReactBoard): IReactBoard { - const res: IReactBoard = createRenderableBase({ + return createRenderableBase({ ...input, render(target) { + const renderable = this as IReactBoard; return baseRender( - res, + renderable, async () => { - let element = ; - const wrapRenderPlugins = getPluginsWithHooks(res, 'wrapRender'); + let element = ; + const wrapRenderPlugins = getPluginsWithHooks(renderable, 'wrapRender'); for (const plugin of wrapRenderPlugins) { if (plugin.key.plugin?.wrapRender) { - const el = plugin.key.plugin.wrapRender(plugin.props as never, res, element, target); + const el = plugin.key.plugin.wrapRender(plugin.props as never, renderable, element, target); element = el || element; } } @@ -23,5 +24,4 @@ export function createBoard(input: OmitReactBoard): IReactBoard { ); }, }); - return res; } diff --git a/packages/react-board/test/create-board.spec.tsx b/packages/react-board/test/create-board.spec.tsx index 9e961731..eefdbb9c 100644 --- a/packages/react-board/test/create-board.spec.tsx +++ b/packages/react-board/test/create-board.spec.tsx @@ -47,7 +47,18 @@ describe('create board', () => { const cleanupRender = await board.render(canvas); disposables.add(cleanupRender); - // await board.render(canvas); await expect(board.render(canvas)).not.to.be.rejected; }); + + it('should allow render of renderable to access state in case of mutation', async () => { + const { canvas, cleanup } = board.setupStage(); + disposables.add(cleanup); + + const mutatedBoard = { ...board, Board: () => 'I was mutated' }; + + const cleanupRender = await mutatedBoard.render(canvas); + disposables.add(cleanupRender); + + expect(canvas.innerHTML).to.include('I was mutated'); + }); });