UNPKG

@atlaskit/editor-plugin-synced-block

Version:

SyncedBlock plugin for @atlaskit/editor-core

54 lines (53 loc) 2.87 kB
/** * @jsxRuntime classic * @jsx jsx */ import { useMemo } from 'react'; // Plugin content components need a global selector because the ProseMirror content is not a child // of this component. This follows the existing layout placeholder pattern. // eslint-disable-next-line @atlaskit/ui-styling-standard/no-global-styles, @atlaskit/ui-styling-standard/use-compiled, @typescript-eslint/consistent-type-imports import { css, Global, jsx } from '@emotion/react'; import { useIntl } from 'react-intl'; import { placeholderTextMessages } from '@atlaskit/editor-common/messages'; import { BodiedSyncBlockSharedCssClassName } from '@atlaskit/editor-common/sync-block'; const getSourceSyncBlockPlaceholderStyles = placeholderText => css({ // Emptiness is signalled by the node view via the `empty` class, which is derived from the // ProseMirror document. Keeping this visual state in CSS means typing, deletion, undo/redo, // and remote changes update it without decorations. // // This deliberately does NOT inspect the rendered DOM shape. The paragraph inside an empty // block routinely gains extra children that are not user content — the selection marker's // cursor widget (`.ProseMirror-widget`), ProseMirror's `.ProseMirror-separator` hack node, // and the `.ProseMirror-trailingBreak`. An earlier `:has(.ProseMirror-trailingBreak:only-child)` // form treated those decorations as content and hid the placeholder whenever the user placed // a cursor in the block and then blurred the editor. See EDITOR-8327. // eslint-disable-next-line @atlaskit/ui-styling-standard/no-imported-style-values, @atlaskit/ui-styling-standard/no-nested-selectors, @atlaskit/ui-styling-standard/no-unsafe-selectors, @atlaskit/ui-styling-standard/no-unsafe-values [`.ProseMirror .${BodiedSyncBlockSharedCssClassName.prefix}.${BodiedSyncBlockSharedCssClassName.empty} .${BodiedSyncBlockSharedCssClassName.content}[contenteditable="true"] > p:only-child`]: { position: 'relative', '&::before': { // JSON.stringify produces a quoted and escaped CSS string. // eslint-disable-next-line @atlaskit/ui-styling-standard/no-unsafe-values content: placeholderText, position: 'absolute', boxSizing: 'border-box', color: "var(--ds-text-subtlest, #6B6E76)", font: 'inherit', insetInlineStart: 0, width: '100%', overflow: 'hidden', pointerEvents: 'none', textOverflow: 'ellipsis', userSelect: 'none', whiteSpace: 'nowrap' } } }); export const SourceSyncBlockPlaceholder = () => { const { formatMessage } = useIntl(); const placeholderStyles = useMemo(() => getSourceSyncBlockPlaceholderStyles(JSON.stringify(formatMessage(placeholderTextMessages.sourceSyncBlockPlaceholderText))), [formatMessage]); return jsx(Global, { styles: placeholderStyles }); };