UNPKG

@atlaskit/renderer

Version:
150 lines (148 loc) 6.19 kB
/** * @jsxRuntime classic * @jsx jsx */ // eslint-disable-next-line @typescript-eslint/consistent-type-imports, @atlaskit/ui-styling-standard/use-compiled -- emotion jsx pragma; go/DSP-18766 import { css, jsx } from '@emotion/react'; // oxlint-ignore @typescript-eslint/consistent-type-imports -- classic @jsx jsx factory + jsx.JSX.Element types import React from 'react'; import memoizeOne from 'memoize-one'; import { getNodeRenderer } from '@atlaskit/editor-common/extensions'; import { WithProviders } from '@atlaskit/editor-common/provider-factory'; import { getExtensionRenderer } from '@atlaskit/editor-common/utils'; const inlineExtensionStyle = css({ display: 'inline-block', maxWidth: '100%', verticalAlign: 'middle', // 0px margin top is important here. // When running on server-side emotion will generate style tags before elements. // This caused packages/editor/editor-common/src/styles/shared/block-marks.ts to override the margin-top. // However as soon as the styles are extracted to <head> it adds back the margin. // The timing is tricky as it happens to be when UFO collects the dimension for the placeholder for TTVC calculation. // This resulted 1px mismatch on the image. Further cause everything on page to shift by 1px. // es-lint-disable-next-line @atlaskit/design-system/ensure-design-token-usage margin: `0px 1px ${"var(--ds-space-050, 4px)"}`, // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors -- Ignored via go/DSP-18766 '& .rich-media-item': { maxWidth: '100%' } }); const plainTextMacroStyle = css({ display: 'inline', verticalAlign: 'baseline', // eslint-disable-next-line @atlaskit/ui-styling-standard/no-nested-selectors '[data-macro-body]': { display: 'inline' } }); /** Renders extension (macro) nodes inside the ADF renderer. */ export default function ExtensionRenderer(props) { const { extensionHandlers, rendererContext, extensionType, extensionKey, parameters, content, text, type, localId, marks, actions, children } = props; const isMounted = React.useRef(true); const localGetNodeRenderer = React.useMemo(() => memoizeOne(getNodeRenderer), []); const [extensionProvider, setExtensionProvider] = React.useState(null); // Ignored via go/ees005 // eslint-disable-next-line @typescript-eslint/no-explicit-any const handleProvider = React.useCallback((_name, providerPromise) => { providerPromise && providerPromise.then(provider => { if (isMounted.current) { setExtensionProvider(provider); } }); }, []); const renderExtensionNode = React.useCallback(extensionProvider => { var _marks$find, _marks$find$attrs, _node$parameters, _node$parameters$macr; const fragmentLocalId = marks === null || marks === void 0 ? void 0 : (_marks$find = marks.find(m => m.type.name === 'fragment')) === null || _marks$find === void 0 ? void 0 : (_marks$find$attrs = _marks$find.attrs) === null || _marks$find$attrs === void 0 ? void 0 : _marks$find$attrs.localId; const node = { type, extensionKey, extensionType, parameters, content: content || text, localId, fragmentLocalId }; const isPlainTextMacro = Boolean(node === null || node === void 0 ? void 0 : (_node$parameters = node.parameters) === null || _node$parameters === void 0 ? void 0 : (_node$parameters$macr = _node$parameters.macroParams) === null || _node$parameters$macr === void 0 ? void 0 : _node$parameters$macr.__bodyContent); let result = null; try { if (extensionHandlers && extensionHandlers[extensionType]) { const render = getExtensionRenderer(extensionHandlers[extensionType]); result = render(node, rendererContext.adDoc); } if (!result && extensionProvider) { const NodeRenderer = localGetNodeRenderer(extensionProvider, extensionType, extensionKey); if (node.type === 'multiBodiedExtension') { result = jsx(NodeRenderer, { node: node, actions: actions }); } else if (node.type === 'inlineExtension') { result = jsx(InlineNodeRendererWrapper, { isPlainTextMacro: isPlainTextMacro }, jsx(NodeRenderer, { node: node })); } else { result = jsx(NodeRenderer, { node: node }); } } } catch { /** We don't want this error to block renderer */ /** We keep rendering the default content */ } return children({ node, result }); }, [actions, children, content, extensionHandlers, extensionKey, extensionType, localGetNodeRenderer, localId, marks, parameters, rendererContext === null || rendererContext === void 0 ? void 0 : rendererContext.adDoc, text, type]); const setupAndRenderExtensionNode = React.useCallback(providers => { if (!extensionProvider && providers.extensionProvider) { handleProvider('extensionProvider', providers.extensionProvider); } return renderExtensionNode(extensionProvider); }, [extensionProvider, handleProvider, renderExtensionNode]); React.useEffect(() => { isMounted.current = true; return () => { isMounted.current = false; }; }, []); if (!props.providers) { return setupAndRenderExtensionNode({}); } return jsx(WithProviders // eslint-disable-next-line @atlassian/perf-linting/no-unstable-inline-props -- Ignored via go/ees017 (to be fixed) , { providers: ['extensionProvider'], providerFactory: props.providers, renderNode: setupAndRenderExtensionNode }); } export const InlineNodeRendererWrapper = ({ children, isPlainTextMacro, ssrPlaceholder, ssrPlaceholderReplace }) => { return jsx("div", { // eslint-disable-next-line @atlaskit/ui-styling-standard/no-classname-prop -- Ignored via go/DSP-18766 className: `inline-extension-renderer ${isPlainTextMacro ? 'plain-text-macro' : ''}`, css: [inlineExtensionStyle, isPlainTextMacro && plainTextMacroStyle], "data-ssr-placeholder": ssrPlaceholder, "data-ssr-placeholder-replace": ssrPlaceholderReplace }, children); };