@strapi/content-manager 5.45.0 → 5.46.0

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 (82) hide show
  1. package/dist/admin/content-manager.js +26 -2
  2. package/dist/admin/content-manager.js.map +1 -1
  3. package/dist/admin/content-manager.mjs +26 -2
  4. package/dist/admin/content-manager.mjs.map +1 -1
  5. package/dist/admin/hooks/useContentTypeSchema.js +4 -1
  6. package/dist/admin/hooks/useContentTypeSchema.js.map +1 -1
  7. package/dist/admin/hooks/useContentTypeSchema.mjs +4 -1
  8. package/dist/admin/hooks/useContentTypeSchema.mjs.map +1 -1
  9. package/dist/admin/hooks/useDocumentLayout.js +67 -45
  10. package/dist/admin/hooks/useDocumentLayout.js.map +1 -1
  11. package/dist/admin/hooks/useDocumentLayout.mjs +67 -45
  12. package/dist/admin/hooks/useDocumentLayout.mjs.map +1 -1
  13. package/dist/admin/hooks/usePersistentQueryParams.js +4 -1
  14. package/dist/admin/hooks/usePersistentQueryParams.js.map +1 -1
  15. package/dist/admin/hooks/usePersistentQueryParams.mjs +4 -1
  16. package/dist/admin/hooks/usePersistentQueryParams.mjs.map +1 -1
  17. package/dist/admin/pages/ComponentConfigurationPage.js +7 -3
  18. package/dist/admin/pages/ComponentConfigurationPage.js.map +1 -1
  19. package/dist/admin/pages/ComponentConfigurationPage.mjs +7 -3
  20. package/dist/admin/pages/ComponentConfigurationPage.mjs.map +1 -1
  21. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.js +21 -4
  22. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.js.map +1 -1
  23. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.mjs +19 -2
  24. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.mjs.map +1 -1
  25. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.mjs +1 -1
  26. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js +9 -6
  27. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js.map +1 -1
  28. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs +10 -7
  29. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs.map +1 -1
  30. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js +1 -34
  31. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js.map +1 -1
  32. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs +3 -35
  33. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs.map +1 -1
  34. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js +33 -18
  35. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js.map +1 -1
  36. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs +34 -19
  37. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs.map +1 -1
  38. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/DefaultBlocksStore.js +22 -0
  39. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/DefaultBlocksStore.js.map +1 -0
  40. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/DefaultBlocksStore.mjs +20 -0
  41. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/DefaultBlocksStore.mjs.map +1 -0
  42. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js +15 -4
  43. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js.map +1 -1
  44. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs +16 -5
  45. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs.map +1 -1
  46. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js +26 -4
  47. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js.map +1 -1
  48. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs +26 -4
  49. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs.map +1 -1
  50. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.js +31 -0
  51. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.js.map +1 -1
  52. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.mjs +31 -0
  53. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.mjs.map +1 -1
  54. package/dist/admin/preview/components/InputPopover.js +3 -0
  55. package/dist/admin/preview/components/InputPopover.js.map +1 -1
  56. package/dist/admin/preview/components/InputPopover.mjs +3 -0
  57. package/dist/admin/preview/components/InputPopover.mjs.map +1 -1
  58. package/dist/admin/preview/hooks/usePreviewInputManager.js +24 -0
  59. package/dist/admin/preview/hooks/usePreviewInputManager.js.map +1 -1
  60. package/dist/admin/preview/hooks/usePreviewInputManager.mjs +24 -0
  61. package/dist/admin/preview/hooks/usePreviewInputManager.mjs.map +1 -1
  62. package/dist/admin/preview/utils/previewScript.js +616 -78
  63. package/dist/admin/preview/utils/previewScript.js.map +1 -1
  64. package/dist/admin/preview/utils/previewScript.mjs +616 -78
  65. package/dist/admin/preview/utils/previewScript.mjs.map +1 -1
  66. package/dist/admin/src/content-manager.d.ts +26 -0
  67. package/dist/admin/src/exports.d.ts +1 -0
  68. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.d.ts +14 -8
  69. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/DefaultBlocksStore.d.ts +3 -0
  70. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCard.d.ts +1 -1
  71. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +11 -1
  72. package/dist/server/homepage/services/homepage.js +12 -8
  73. package/dist/server/homepage/services/homepage.js.map +1 -1
  74. package/dist/server/homepage/services/homepage.mjs +12 -8
  75. package/dist/server/homepage/services/homepage.mjs.map +1 -1
  76. package/dist/server/services/metrics.js +1 -5
  77. package/dist/server/services/metrics.js.map +1 -1
  78. package/dist/server/services/metrics.mjs +1 -5
  79. package/dist/server/services/metrics.mjs.map +1 -1
  80. package/dist/server/src/homepage/services/homepage.d.ts.map +1 -1
  81. package/dist/server/src/services/metrics.d.ts.map +1 -1
  82. package/package.json +6 -6
@@ -1 +1 @@
1
- {"version":3,"file":"BlocksEditor.js","sources":["../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { createContext, type FieldValue, useIsMobile } from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { flushSync } from 'react-dom';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms, Element } from 'slate';\nimport { withHistory } from 'slate-history';\nimport { type RenderElementProps, Slate, withReact, ReactEditor, useSlate } from 'slate-react';\nimport { styled, type CSSProperties } from 'styled-components';\n\nimport { getTranslation } from '../../../../../utils/translations';\n\nimport { codeBlocks } from './Blocks/Code';\nimport { headingBlocks } from './Blocks/Heading';\nimport { imageBlocks } from './Blocks/Image';\nimport { linkBlocks } from './Blocks/Link';\nimport { listBlocks } from './Blocks/List';\nimport { paragraphBlocks } from './Blocks/Paragraph';\nimport { quoteBlocks } from './Blocks/Quote';\nimport { BlocksContent, type BlocksContentProps } from './BlocksContent';\nimport { BlocksToolbar } from './BlocksToolbar';\nimport { EditorLayout } from './EditorLayout';\nimport { type ModifiersStore, modifiers } from './Modifiers';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\nimport { isNonNullable } from './utils/types';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\n /** Function to check if a given node is of this type of block */\n matchNode: (node: Schema.Attribute.BlocksNode) => boolean;\n handleConvert?: (editor: Editor) => void | (() => React.JSX.Element);\n handleEnterKey?: (editor: Editor) => void;\n handleBackspaceKey?: (editor: Editor, event: React.KeyboardEvent<HTMLElement>) => void;\n handleTab?: (editor: Editor) => void;\n handleShiftTab?: (editor: Editor) => void;\n snippets?: string[];\n /** Adjust the vertical positioning of the drag-to-reorder grip icon */\n dragHandleTopMargin?: CSSProperties['marginTop'];\n /** A Slate plugin: function that will wrap the editor creation */\n plugin?: (editor: Editor) => Editor;\n /**\n * Function that checks if an element should be draggable\n * @default () => true */\n isDraggable?: (element: Element) => boolean;\n}\n\ninterface NonSelectorBlock extends BaseBlock {\n isInBlocksSelector: false;\n}\n\ninterface SelectorBlock extends BaseBlock {\n isInBlocksSelector: true;\n icon: React.ComponentType;\n label: MessageDescriptor;\n}\n\ntype NonSelectorBlockKey = 'list-item' | 'link';\n\nconst selectorBlockKeys = [\n 'paragraph',\n 'heading-one',\n 'heading-two',\n 'heading-three',\n 'heading-four',\n 'heading-five',\n 'heading-six',\n 'list-ordered',\n 'list-unordered',\n 'image',\n 'quote',\n 'code',\n] as const;\n\ntype SelectorBlockKey = (typeof selectorBlockKeys)[number];\n\nconst isSelectorBlockKey = (key: unknown): key is SelectorBlockKey => {\n return typeof key === 'string' && selectorBlockKeys.includes(key as SelectorBlockKey);\n};\n\ntype BlocksStore = {\n [K in SelectorBlockKey]: SelectorBlock;\n} & {\n [K in NonSelectorBlockKey]: NonSelectorBlock;\n};\n\ninterface BlocksEditorContextValue {\n blocks: BlocksStore;\n modifiers: ModifiersStore;\n disabled: boolean;\n name: string;\n setLiveText: (text: string) => void;\n isExpandedMode: boolean;\n /** Push debounced Slate → form sync immediately (e.g. on Editable blur before Save). */\n flushPendingFormSync: () => void;\n}\n\nconst [BlocksEditorProvider, usePartialBlocksEditorContext] =\n createContext<BlocksEditorContextValue>('BlocksEditor');\n\nfunction useBlocksEditorContext(\n consumerName: string\n): BlocksEditorContextValue & { editor: Editor } {\n const context = usePartialBlocksEditorContext(consumerName, (state) => state);\n const editor = useSlate();\n\n return {\n ...context,\n editor,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditor\n * -----------------------------------------------------------------------------------------------*/\n\nconst EditorDivider = styled(Divider)`\n background: ${({ theme }) => theme.colors.neutral200};\n`;\n\n/**\n * Forces an update of the Slate editor when the value prop changes from outside of Slate.\n * The root cause is that Slate is not a controlled component: https://github.com/ianstormtaylor/slate/issues/4612\n * Why not use JSON.stringify(value) as the key?\n * Because it would force a rerender of the entire editor every time the user types a character.\n * Why not use the entity id as the key, since it's unique for each locale?\n * Because it would not solve the problem when using the \"fill in from other locale\" feature\n */\nfunction useResetKey(value?: Schema.Attribute.BlocksValue): {\n key: number;\n incrementSlateUpdatesCount: () => void;\n} {\n // Keep track how many times Slate detected a change from a user interaction in the editor\n const slateUpdatesCount = React.useRef(0);\n // Keep track of how many times the value prop was updated, whether from within editor or from outside\n const valueUpdatesCount = React.useRef(0);\n // Use a key to force a rerender of the Slate editor when needed\n const [key, setKey] = React.useState(0);\n\n React.useEffect(() => {\n valueUpdatesCount.current += 1;\n\n // If the 2 refs are not equal, it means the value was updated from outside\n if (valueUpdatesCount.current !== slateUpdatesCount.current) {\n // So we change the key to force a rerender of the Slate editor,\n // which will pick up the new value through its initialValue prop\n setKey((previousKey) => previousKey + 1);\n\n // Then bring the 2 refs back in sync\n slateUpdatesCount.current = valueUpdatesCount.current;\n }\n }, [value]);\n\n const incrementSlateUpdatesCount = React.useCallback(() => {\n slateUpdatesCount.current += 1;\n }, []);\n\n return { key, incrementSlateUpdatesCount };\n}\n\nconst pipe =\n (...fns: ((baseEditor: Editor) => Editor)[]) =>\n (value: Editor) =>\n fns.reduce<Editor>((prev, fn) => fn(prev), value);\n\n/**\n * Normalize the blocks state to null if the editor state is considered empty,\n * otherwise return the state\n */\nconst normalizeBlocksState = (\n editor: Editor,\n value: Schema.Attribute.BlocksValue | Descendant[]\n): Schema.Attribute.BlocksValue | Descendant[] | null => {\n const isEmpty =\n value.length === 1 && Editor.isEmpty(editor, value[0] as Schema.Attribute.BlocksNode);\n\n return isEmpty ? null : value;\n};\n\ninterface BlocksEditorProps\n extends Pick<FieldValue<Schema.Attribute.BlocksValue>, 'onChange' | 'value' | 'error'>,\n BlocksContentProps {\n disabled?: boolean;\n name: string;\n}\n\nconst BlocksEditor = React.forwardRef<{ focus: () => void }, BlocksEditorProps>(\n ({ disabled = false, name, onChange, value, error, ...contentProps }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const isMobile = useIsMobile();\n\n const blocks = React.useMemo(\n () => ({\n ...paragraphBlocks,\n ...headingBlocks,\n ...listBlocks,\n ...linkBlocks,\n ...imageBlocks,\n ...quoteBlocks,\n ...codeBlocks,\n }),\n []\n ) satisfies BlocksStore;\n\n const blockRegisteredPlugins = Object.values(blocks)\n .map((block) => block.plugin)\n .filter(isNonNullable);\n\n const [editor] = React.useState(() =>\n pipe(withHistory, withStrapiSchema, withReact, ...blockRegisteredPlugins)(createEditor())\n );\n const [liveText, setLiveText] = React.useState('');\n const ariaDescriptionId = React.useId();\n const [isExpandedMode, handleToggleExpand] = React.useReducer((prev) => !prev, false);\n\n /**\n * Editable is not able to hold the ref, https://github.com/ianstormtaylor/slate/issues/4082\n * so with \"useImperativeHandle\" we can use ReactEditor methods to expose to the parent above\n * also not passing forwarded ref here, gives console warning.\n */\n React.useImperativeHandle(\n forwardedRef,\n () => ({\n focus() {\n ReactEditor.focus(editor);\n },\n }),\n [editor]\n );\n\n const { key, incrementSlateUpdatesCount } = useResetKey(value);\n\n const debounceTimeout = React.useRef<NodeJS.Timeout | null>(null);\n\n const flushPendingFormSync = React.useCallback(() => {\n if (!debounceTimeout.current) {\n return;\n }\n clearTimeout(debounceTimeout.current);\n debounceTimeout.current = null;\n incrementSlateUpdatesCount();\n // Ensure Strapi Form state updates before the next event (e.g. Save click) reads values.\n flushSync(() => {\n onChange(\n name,\n normalizeBlocksState(editor, editor.children) as Schema.Attribute.BlocksValue\n );\n });\n }, [editor, incrementSlateUpdatesCount, name, onChange]);\n\n const handleSlateChange = React.useCallback(\n (state: Descendant[]) => {\n const isAstChange = editor.operations.some((op) => op.type !== 'set_selection');\n\n if (isAstChange) {\n /**\n * Slate handles the state of the editor internally. We just need to keep Strapi's form\n * state in sync with it in order to make sure that things like the \"modified\" state\n * isn't broken. Updating the whole state on every change is very expensive however,\n * so we debounce calls to onChange to mitigate input lag.\n */\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n\n // Set a new debounce timeout\n debounceTimeout.current = setTimeout(() => {\n incrementSlateUpdatesCount();\n\n // Normalize the state (empty editor becomes null)\n onChange(name, normalizeBlocksState(editor, state) as Schema.Attribute.BlocksValue);\n debounceTimeout.current = null;\n }, 300);\n }\n },\n [editor, incrementSlateUpdatesCount, name, onChange]\n );\n\n // Clean up the timeout on unmount\n React.useEffect(() => {\n return () => {\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n };\n }, []);\n\n // Ensure the editor is in sync after discard\n React.useEffect(() => {\n // Never deselect while the editor is actively focused (typing / editing),\n if (ReactEditor.isFocused(editor)) {\n return;\n }\n\n // Normalize empty states for comparison to avoid losing focus on the editor when content is deleted\n const normalizedValue = value?.length ? value : null;\n const normalizedEditorState = normalizeBlocksState(editor, editor.children);\n\n // Compare the field value with the editor state to check for a stale selection\n if (\n normalizedValue &&\n normalizedEditorState &&\n JSON.stringify(normalizedEditorState) !== JSON.stringify(normalizedValue)\n ) {\n // When there is a diff, unset selection to avoid an invalid state\n Transforms.deselect(editor);\n }\n }, [editor, value]);\n\n return (\n <>\n <VisuallyHidden id={ariaDescriptionId}>\n {formatMessage({\n id: getTranslation('components.Blocks.dnd.instruction'),\n defaultMessage: `To reorder blocks, press Command or Control along with Shift and the Up or Down arrow keys`,\n })}\n </VisuallyHidden>\n <VisuallyHidden aria-live=\"assertive\">{liveText}</VisuallyHidden>\n <Slate\n editor={editor}\n initialValue={\n value?.length ? value : [{ type: 'paragraph', children: [{ type: 'text', text: '' }] }]\n }\n onChange={handleSlateChange}\n key={key}\n >\n <BlocksEditorProvider\n blocks={blocks}\n modifiers={modifiers}\n disabled={disabled}\n name={name}\n setLiveText={setLiveText}\n isExpandedMode={isExpandedMode}\n flushPendingFormSync={flushPendingFormSync}\n >\n <EditorLayout\n error={error}\n disabled={disabled}\n onToggleExpand={handleToggleExpand}\n ariaDescriptionId={ariaDescriptionId}\n >\n <BlocksToolbar />\n <EditorDivider width=\"100%\" />\n <BlocksContent {...contentProps} />\n {!isExpandedMode && !isMobile && (\n <IconButton\n position=\"absolute\"\n bottom=\"1.2rem\"\n right=\"1.2rem\"\n shadow=\"filterShadow\"\n label={formatMessage({\n id: getTranslation('components.Blocks.expand'),\n defaultMessage: 'Expand',\n })}\n onClick={handleToggleExpand}\n >\n <Expand />\n </IconButton>\n )}\n </EditorLayout>\n </BlocksEditorProvider>\n </Slate>\n </>\n );\n }\n);\n\nexport {\n type BlocksStore,\n type SelectorBlockKey,\n BlocksEditor,\n BlocksEditorProvider,\n useBlocksEditorContext,\n isSelectorBlockKey,\n normalizeBlocksState,\n};\n"],"names":["selectorBlockKeys","isSelectorBlockKey","key","includes","BlocksEditorProvider","usePartialBlocksEditorContext","createContext","useBlocksEditorContext","consumerName","context","state","editor","useSlate","EditorDivider","styled","Divider","theme","colors","neutral200","useResetKey","value","slateUpdatesCount","React","useRef","valueUpdatesCount","setKey","useState","useEffect","current","previousKey","incrementSlateUpdatesCount","useCallback","pipe","fns","reduce","prev","fn","normalizeBlocksState","isEmpty","length","Editor","BlocksEditor","forwardRef","disabled","name","onChange","error","contentProps","forwardedRef","formatMessage","useIntl","isMobile","useIsMobile","blocks","useMemo","paragraphBlocks","headingBlocks","listBlocks","linkBlocks","imageBlocks","quoteBlocks","codeBlocks","blockRegisteredPlugins","Object","values","map","block","plugin","filter","isNonNullable","withHistory","withStrapiSchema","withReact","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","flushPendingFormSync","clearTimeout","flushSync","children","handleSlateChange","isAstChange","operations","some","op","type","setTimeout","isFocused","normalizedValue","normalizedEditorState","JSON","stringify","Transforms","deselect","_jsxs","_Fragment","_jsx","VisuallyHidden","id","getTranslation","defaultMessage","aria-live","Slate","initialValue","text","modifiers","EditorLayout","onToggleExpand","BlocksToolbar","width","BlocksContent","IconButton","position","bottom","right","shadow","label","onClick","Expand"],"mappings":"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"}
1
+ {"version":3,"file":"BlocksEditor.js","sources":["../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n createContext,\n useStrapiApp,\n type FieldValue,\n useIsMobile,\n} from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { flushSync } from 'react-dom';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms, Element } from 'slate';\nimport { withHistory } from 'slate-history';\nimport { type RenderElementProps, Slate, withReact, ReactEditor, useSlate } from 'slate-react';\nimport { styled, type CSSProperties } from 'styled-components';\n\nimport { ContentManagerPlugin } from '../../../../../content-manager';\nimport { getTranslation } from '../../../../../utils/translations';\n\nimport { BlocksContent, type BlocksContentProps } from './BlocksContent';\nimport { BlocksToolbar } from './BlocksToolbar';\nimport { EditorLayout } from './EditorLayout';\nimport { type ModifiersStore, modifiers } from './Modifiers';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\nimport { isNonNullable } from './utils/types';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface CustomNode extends Omit<Schema.Attribute.BlocksNode, 'type'> {\n type: Schema.Attribute.BlocksNode['type'] | string;\n level?: number;\n format?: string;\n}\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\n /** Function to check if a given node is of this type of block */\n matchNode: (node: Schema.Attribute.BlocksNode | CustomNode) => boolean;\n handleConvert?: (editor: Editor) => void | (() => React.JSX.Element);\n handleEnterKey?: (editor: Editor) => void;\n handleBackspaceKey?: (editor: Editor, event: React.KeyboardEvent<HTMLElement>) => void;\n handleTab?: (editor: Editor) => void;\n handleShiftTab?: (editor: Editor) => void;\n snippets?: string[];\n /** Adjust the vertical positioning of the drag-to-reorder grip icon */\n dragHandleTopMargin?: CSSProperties['marginTop'];\n /** A Slate plugin: function that will wrap the editor creation */\n plugin?: (editor: Editor) => Editor;\n /**\n * Function that checks if an element should be draggable\n * @default () => true */\n isDraggable?: (element: Element) => boolean;\n}\n\nexport interface NonSelectorBlock extends BaseBlock {\n isInBlocksSelector?: false;\n}\n\nexport interface SelectorBlock extends BaseBlock {\n isInBlocksSelector: true;\n icon?: React.ComponentType;\n label: MessageDescriptor;\n}\n\ntype NonSelectorBlockKey = 'list-item' | 'link';\n\nconst selectorBlockKeys = [\n 'paragraph',\n 'heading-one',\n 'heading-two',\n 'heading-three',\n 'heading-four',\n 'heading-five',\n 'heading-six',\n 'list-ordered',\n 'list-unordered',\n 'image',\n 'quote',\n 'code',\n] as const;\n\ntype SelectorBlockKey = (typeof selectorBlockKeys)[number];\n\nconst isSelectorBlockKey = (key: unknown): key is SelectorBlockKey => {\n return typeof key === 'string' && selectorBlockKeys.includes(key as SelectorBlockKey);\n};\n\ntype BlocksStore = {\n [K in SelectorBlockKey]: SelectorBlock;\n} & {\n [K in NonSelectorBlockKey]: NonSelectorBlock;\n};\n\ntype RichTextBlocksStore = Partial<BlocksStore> & Record<string, SelectorBlock | NonSelectorBlock>;\n\ninterface BlocksEditorContextValue {\n blocks: RichTextBlocksStore;\n modifiers: ModifiersStore;\n disabled: boolean;\n name: string;\n setLiveText: (text: string) => void;\n isExpandedMode: boolean;\n /** Push debounced Slate → form sync immediately (e.g. on Editable blur before Save). */\n flushPendingFormSync: () => void;\n}\n\nconst [BlocksEditorProvider, usePartialBlocksEditorContext] =\n createContext<BlocksEditorContextValue>('BlocksEditor');\n\nfunction useBlocksEditorContext(consumerName: string): BlocksEditorContextValue & {\n editor: Editor;\n} {\n const context = usePartialBlocksEditorContext(consumerName, (state) => state);\n const editor = useSlate();\n\n return {\n ...context,\n editor,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditor\n * -----------------------------------------------------------------------------------------------*/\n\nconst EditorDivider = styled(Divider)`\n background: ${({ theme }) => theme.colors.neutral200};\n`;\n\n/**\n * Forces an update of the Slate editor when the value prop changes from outside of Slate.\n * The root cause is that Slate is not a controlled component: https://github.com/ianstormtaylor/slate/issues/4612\n * Why not use JSON.stringify(value) as the key?\n * Because it would force a rerender of the entire editor every time the user types a character.\n * Why not use the entity id as the key, since it's unique for each locale?\n * Because it would not solve the problem when using the \"fill in from other locale\" feature\n */\nfunction useResetKey(value?: Schema.Attribute.BlocksValue): {\n key: number;\n incrementSlateUpdatesCount: () => void;\n} {\n // Keep track how many times Slate detected a change from a user interaction in the editor\n const slateUpdatesCount = React.useRef(0);\n // Keep track of how many times the value prop was updated, whether from within editor or from outside\n const valueUpdatesCount = React.useRef(0);\n // Use a key to force a rerender of the Slate editor when needed\n const [key, setKey] = React.useState(0);\n\n React.useEffect(() => {\n valueUpdatesCount.current += 1;\n\n // If the 2 refs are not equal, it means the value was updated from outside\n if (valueUpdatesCount.current !== slateUpdatesCount.current) {\n // So we change the key to force a rerender of the Slate editor,\n // which will pick up the new value through its initialValue prop\n setKey((previousKey) => previousKey + 1);\n\n // Then bring the 2 refs back in sync\n slateUpdatesCount.current = valueUpdatesCount.current;\n }\n }, [value]);\n\n const incrementSlateUpdatesCount = React.useCallback(() => {\n slateUpdatesCount.current += 1;\n }, []);\n\n return { key, incrementSlateUpdatesCount };\n}\n\nconst pipe =\n (...fns: ((baseEditor: Editor) => Editor)[]) =>\n (value: Editor) =>\n fns.reduce<Editor>((prev, fn) => fn(prev), value);\n\n/**\n * Normalize the blocks state to null if the editor state is considered empty,\n * otherwise return the state\n */\nconst normalizeBlocksState = (\n editor: Editor,\n value: Schema.Attribute.BlocksValue | Descendant[]\n): Schema.Attribute.BlocksValue | Descendant[] | null => {\n const isEmpty =\n value.length === 1 && Editor.isEmpty(editor, value[0] as Schema.Attribute.BlocksNode);\n\n return isEmpty ? null : value;\n};\n\ninterface BlocksEditorProps\n extends Pick<FieldValue<Schema.Attribute.BlocksValue>, 'onChange' | 'value' | 'error'>,\n BlocksContentProps {\n disabled?: boolean;\n name: string;\n}\n\nconst BlocksEditor = React.forwardRef<{ focus: () => void }, BlocksEditorProps>(\n ({ disabled = false, name, onChange, value, error, ...contentProps }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const isMobile = useIsMobile();\n\n const blocks = useStrapiApp(\n 'BlocksEditor',\n (state) =>\n (\n state.plugins['content-manager']?.apis as\n | ContentManagerPlugin['config']['apis']\n | undefined\n )?.getRichTextBlocks() ?? ({} as RichTextBlocksStore)\n );\n\n const blockRegisteredPlugins = Object.values(blocks)\n .map((block) => block.plugin)\n .filter(isNonNullable);\n\n const [editor] = React.useState(() =>\n pipe(withHistory, withStrapiSchema, withReact, ...blockRegisteredPlugins)(createEditor())\n );\n const [liveText, setLiveText] = React.useState('');\n const ariaDescriptionId = React.useId();\n const [isExpandedMode, handleToggleExpand] = React.useReducer((prev) => !prev, false);\n\n /**\n * Editable is not able to hold the ref, https://github.com/ianstormtaylor/slate/issues/4082\n * so with \"useImperativeHandle\" we can use ReactEditor methods to expose to the parent above\n * also not passing forwarded ref here, gives console warning.\n */\n React.useImperativeHandle(\n forwardedRef,\n () => ({\n focus() {\n ReactEditor.focus(editor);\n },\n }),\n [editor]\n );\n\n const { key, incrementSlateUpdatesCount } = useResetKey(value);\n\n const debounceTimeout = React.useRef<NodeJS.Timeout | null>(null);\n\n const flushPendingFormSync = React.useCallback(() => {\n if (!debounceTimeout.current) {\n return;\n }\n clearTimeout(debounceTimeout.current);\n debounceTimeout.current = null;\n incrementSlateUpdatesCount();\n // Ensure Strapi Form state updates before the next event (e.g. Save click) reads values.\n flushSync(() => {\n onChange(\n name,\n normalizeBlocksState(editor, editor.children) as Schema.Attribute.BlocksValue\n );\n });\n }, [editor, incrementSlateUpdatesCount, name, onChange]);\n\n const handleSlateChange = React.useCallback(\n (state: Descendant[]) => {\n const isAstChange = editor.operations.some((op) => op.type !== 'set_selection');\n\n if (isAstChange) {\n /**\n * Slate handles the state of the editor internally. We just need to keep Strapi's form\n * state in sync with it in order to make sure that things like the \"modified\" state\n * isn't broken. Updating the whole state on every change is very expensive however,\n * so we debounce calls to onChange to mitigate input lag.\n */\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n\n // Set a new debounce timeout\n debounceTimeout.current = setTimeout(() => {\n incrementSlateUpdatesCount();\n\n // Normalize the state (empty editor becomes null)\n onChange(name, normalizeBlocksState(editor, state) as Schema.Attribute.BlocksValue);\n debounceTimeout.current = null;\n }, 300);\n }\n },\n [editor, incrementSlateUpdatesCount, name, onChange]\n );\n\n // Clean up the timeout on unmount\n React.useEffect(() => {\n return () => {\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n };\n }, []);\n\n // Ensure the editor is in sync after discard\n React.useEffect(() => {\n // Never deselect while the editor is actively focused (typing / editing),\n if (ReactEditor.isFocused(editor)) {\n return;\n }\n\n // Normalize empty states for comparison to avoid losing focus on the editor when content is deleted\n const normalizedValue = value?.length ? value : null;\n const normalizedEditorState = normalizeBlocksState(editor, editor.children);\n\n // Compare the field value with the editor state to check for a stale selection\n if (\n normalizedValue &&\n normalizedEditorState &&\n JSON.stringify(normalizedEditorState) !== JSON.stringify(normalizedValue)\n ) {\n // When there is a diff, unset selection to avoid an invalid state\n Transforms.deselect(editor);\n }\n }, [editor, value]);\n\n return (\n <>\n <VisuallyHidden id={ariaDescriptionId}>\n {formatMessage({\n id: getTranslation('components.Blocks.dnd.instruction'),\n defaultMessage: `To reorder blocks, press Command or Control along with Shift and the Up or Down arrow keys`,\n })}\n </VisuallyHidden>\n <VisuallyHidden aria-live=\"assertive\">{liveText}</VisuallyHidden>\n <Slate\n editor={editor}\n initialValue={\n value?.length ? value : [{ type: 'paragraph', children: [{ type: 'text', text: '' }] }]\n }\n onChange={handleSlateChange}\n key={key}\n >\n <BlocksEditorProvider\n blocks={blocks}\n modifiers={modifiers}\n disabled={disabled}\n name={name}\n setLiveText={setLiveText}\n isExpandedMode={isExpandedMode}\n flushPendingFormSync={flushPendingFormSync}\n >\n <EditorLayout\n error={error}\n disabled={disabled}\n onToggleExpand={handleToggleExpand}\n ariaDescriptionId={ariaDescriptionId}\n >\n <BlocksToolbar />\n <EditorDivider width=\"100%\" />\n <BlocksContent {...contentProps} />\n {!isExpandedMode && !isMobile && (\n <IconButton\n position=\"absolute\"\n bottom=\"1.2rem\"\n right=\"1.2rem\"\n shadow=\"filterShadow\"\n label={formatMessage({\n id: getTranslation('components.Blocks.expand'),\n defaultMessage: 'Expand',\n })}\n onClick={handleToggleExpand}\n >\n <Expand />\n </IconButton>\n )}\n </EditorLayout>\n </BlocksEditorProvider>\n </Slate>\n </>\n );\n }\n);\n\nexport {\n type BlocksStore,\n type RichTextBlocksStore,\n type SelectorBlockKey,\n BlocksEditor,\n BlocksEditorProvider,\n useBlocksEditorContext,\n isSelectorBlockKey,\n normalizeBlocksState,\n};\n"],"names":["BlocksEditorProvider","usePartialBlocksEditorContext","createContext","useBlocksEditorContext","consumerName","context","state","editor","useSlate","EditorDivider","styled","Divider","theme","colors","neutral200","useResetKey","value","slateUpdatesCount","React","useRef","valueUpdatesCount","key","setKey","useState","useEffect","current","previousKey","incrementSlateUpdatesCount","useCallback","pipe","fns","reduce","prev","fn","normalizeBlocksState","isEmpty","length","Editor","BlocksEditor","forwardRef","disabled","name","onChange","error","contentProps","forwardedRef","formatMessage","useIntl","isMobile","useIsMobile","blocks","useStrapiApp","plugins","apis","getRichTextBlocks","blockRegisteredPlugins","Object","values","map","block","plugin","filter","isNonNullable","withHistory","withStrapiSchema","withReact","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","flushPendingFormSync","clearTimeout","flushSync","children","handleSlateChange","isAstChange","operations","some","op","type","setTimeout","isFocused","normalizedValue","normalizedEditorState","JSON","stringify","Transforms","deselect","_jsxs","_Fragment","_jsx","VisuallyHidden","id","getTranslation","defaultMessage","aria-live","Slate","initialValue","text","modifiers","EditorLayout","onToggleExpand","BlocksToolbar","width","BlocksContent","IconButton","position","bottom","right","shadow","label","onClick","Expand"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import { createContext, useIsMobile } from '@strapi/admin/strapi-admin';
3
+ import { createContext, useIsMobile, useStrapiApp } from '@strapi/admin/strapi-admin';
4
4
  import { Divider, VisuallyHidden, IconButton } from '@strapi/design-system';
5
5
  import { Expand } from '@strapi/icons';
6
6
  import { flushSync } from 'react-dom';
@@ -10,13 +10,6 @@ import { withHistory } from 'slate-history';
10
10
  import { withReact, ReactEditor, Slate, useSlate } from 'slate-react';
11
11
  import { styled } from 'styled-components';
12
12
  import { getTranslation } from '../../../../../utils/translations.mjs';
13
- import { codeBlocks } from './Blocks/Code.mjs';
14
- import { headingBlocks } from './Blocks/Heading.mjs';
15
- import { imageBlocks } from './Blocks/Image.mjs';
16
- import { linkBlocks } from './Blocks/Link.mjs';
17
- import { listBlocks } from './Blocks/List.mjs';
18
- import { paragraphBlocks } from './Blocks/Paragraph.mjs';
19
- import { quoteBlocks } from './Blocks/Quote.mjs';
20
13
  import { BlocksContent } from './BlocksContent.mjs';
21
14
  import { BlocksToolbar } from './BlocksToolbar.mjs';
22
15
  import { EditorLayout } from './EditorLayout.mjs';
@@ -24,23 +17,6 @@ import { modifiers } from './Modifiers.mjs';
24
17
  import { withStrapiSchema } from './plugins/withStrapiSchema.mjs';
25
18
  import { isNonNullable } from './utils/types.mjs';
26
19
 
27
- const selectorBlockKeys = [
28
- 'paragraph',
29
- 'heading-one',
30
- 'heading-two',
31
- 'heading-three',
32
- 'heading-four',
33
- 'heading-five',
34
- 'heading-six',
35
- 'list-ordered',
36
- 'list-unordered',
37
- 'image',
38
- 'quote',
39
- 'code'
40
- ];
41
- const isSelectorBlockKey = (key)=>{
42
- return typeof key === 'string' && selectorBlockKeys.includes(key);
43
- };
44
20
  const [BlocksEditorProvider, usePartialBlocksEditorContext] = createContext('BlocksEditor');
45
21
  function useBlocksEditorContext(consumerName) {
46
22
  const context = usePartialBlocksEditorContext(consumerName, (state)=>state);
@@ -101,15 +77,7 @@ const pipe = (...fns)=>(value)=>fns.reduce((prev, fn)=>fn(prev), value);
101
77
  const BlocksEditor = /*#__PURE__*/ React.forwardRef(({ disabled = false, name, onChange, value, error, ...contentProps }, forwardedRef)=>{
102
78
  const { formatMessage } = useIntl();
103
79
  const isMobile = useIsMobile();
104
- const blocks = React.useMemo(()=>({
105
- ...paragraphBlocks,
106
- ...headingBlocks,
107
- ...listBlocks,
108
- ...linkBlocks,
109
- ...imageBlocks,
110
- ...quoteBlocks,
111
- ...codeBlocks
112
- }), []);
80
+ const blocks = useStrapiApp('BlocksEditor', (state)=>state.plugins['content-manager']?.apis?.getRichTextBlocks() ?? {});
113
81
  const blockRegisteredPlugins = Object.values(blocks).map((block)=>block.plugin).filter(isNonNullable);
114
82
  const [editor] = React.useState(()=>pipe(withHistory, withStrapiSchema, withReact, ...blockRegisteredPlugins)(createEditor()));
115
83
  const [liveText, setLiveText] = React.useState('');
@@ -264,5 +232,5 @@ const BlocksEditor = /*#__PURE__*/ React.forwardRef(({ disabled = false, name, o
264
232
  });
265
233
  });
266
234
 
267
- export { BlocksEditor, BlocksEditorProvider, isSelectorBlockKey, normalizeBlocksState, useBlocksEditorContext };
235
+ export { BlocksEditor, BlocksEditorProvider, normalizeBlocksState, useBlocksEditorContext };
268
236
  //# sourceMappingURL=BlocksEditor.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"BlocksEditor.mjs","sources":["../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { createContext, type FieldValue, useIsMobile } from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { flushSync } from 'react-dom';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms, Element } from 'slate';\nimport { withHistory } from 'slate-history';\nimport { type RenderElementProps, Slate, withReact, ReactEditor, useSlate } from 'slate-react';\nimport { styled, type CSSProperties } from 'styled-components';\n\nimport { getTranslation } from '../../../../../utils/translations';\n\nimport { codeBlocks } from './Blocks/Code';\nimport { headingBlocks } from './Blocks/Heading';\nimport { imageBlocks } from './Blocks/Image';\nimport { linkBlocks } from './Blocks/Link';\nimport { listBlocks } from './Blocks/List';\nimport { paragraphBlocks } from './Blocks/Paragraph';\nimport { quoteBlocks } from './Blocks/Quote';\nimport { BlocksContent, type BlocksContentProps } from './BlocksContent';\nimport { BlocksToolbar } from './BlocksToolbar';\nimport { EditorLayout } from './EditorLayout';\nimport { type ModifiersStore, modifiers } from './Modifiers';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\nimport { isNonNullable } from './utils/types';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\n /** Function to check if a given node is of this type of block */\n matchNode: (node: Schema.Attribute.BlocksNode) => boolean;\n handleConvert?: (editor: Editor) => void | (() => React.JSX.Element);\n handleEnterKey?: (editor: Editor) => void;\n handleBackspaceKey?: (editor: Editor, event: React.KeyboardEvent<HTMLElement>) => void;\n handleTab?: (editor: Editor) => void;\n handleShiftTab?: (editor: Editor) => void;\n snippets?: string[];\n /** Adjust the vertical positioning of the drag-to-reorder grip icon */\n dragHandleTopMargin?: CSSProperties['marginTop'];\n /** A Slate plugin: function that will wrap the editor creation */\n plugin?: (editor: Editor) => Editor;\n /**\n * Function that checks if an element should be draggable\n * @default () => true */\n isDraggable?: (element: Element) => boolean;\n}\n\ninterface NonSelectorBlock extends BaseBlock {\n isInBlocksSelector: false;\n}\n\ninterface SelectorBlock extends BaseBlock {\n isInBlocksSelector: true;\n icon: React.ComponentType;\n label: MessageDescriptor;\n}\n\ntype NonSelectorBlockKey = 'list-item' | 'link';\n\nconst selectorBlockKeys = [\n 'paragraph',\n 'heading-one',\n 'heading-two',\n 'heading-three',\n 'heading-four',\n 'heading-five',\n 'heading-six',\n 'list-ordered',\n 'list-unordered',\n 'image',\n 'quote',\n 'code',\n] as const;\n\ntype SelectorBlockKey = (typeof selectorBlockKeys)[number];\n\nconst isSelectorBlockKey = (key: unknown): key is SelectorBlockKey => {\n return typeof key === 'string' && selectorBlockKeys.includes(key as SelectorBlockKey);\n};\n\ntype BlocksStore = {\n [K in SelectorBlockKey]: SelectorBlock;\n} & {\n [K in NonSelectorBlockKey]: NonSelectorBlock;\n};\n\ninterface BlocksEditorContextValue {\n blocks: BlocksStore;\n modifiers: ModifiersStore;\n disabled: boolean;\n name: string;\n setLiveText: (text: string) => void;\n isExpandedMode: boolean;\n /** Push debounced Slate → form sync immediately (e.g. on Editable blur before Save). */\n flushPendingFormSync: () => void;\n}\n\nconst [BlocksEditorProvider, usePartialBlocksEditorContext] =\n createContext<BlocksEditorContextValue>('BlocksEditor');\n\nfunction useBlocksEditorContext(\n consumerName: string\n): BlocksEditorContextValue & { editor: Editor } {\n const context = usePartialBlocksEditorContext(consumerName, (state) => state);\n const editor = useSlate();\n\n return {\n ...context,\n editor,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditor\n * -----------------------------------------------------------------------------------------------*/\n\nconst EditorDivider = styled(Divider)`\n background: ${({ theme }) => theme.colors.neutral200};\n`;\n\n/**\n * Forces an update of the Slate editor when the value prop changes from outside of Slate.\n * The root cause is that Slate is not a controlled component: https://github.com/ianstormtaylor/slate/issues/4612\n * Why not use JSON.stringify(value) as the key?\n * Because it would force a rerender of the entire editor every time the user types a character.\n * Why not use the entity id as the key, since it's unique for each locale?\n * Because it would not solve the problem when using the \"fill in from other locale\" feature\n */\nfunction useResetKey(value?: Schema.Attribute.BlocksValue): {\n key: number;\n incrementSlateUpdatesCount: () => void;\n} {\n // Keep track how many times Slate detected a change from a user interaction in the editor\n const slateUpdatesCount = React.useRef(0);\n // Keep track of how many times the value prop was updated, whether from within editor or from outside\n const valueUpdatesCount = React.useRef(0);\n // Use a key to force a rerender of the Slate editor when needed\n const [key, setKey] = React.useState(0);\n\n React.useEffect(() => {\n valueUpdatesCount.current += 1;\n\n // If the 2 refs are not equal, it means the value was updated from outside\n if (valueUpdatesCount.current !== slateUpdatesCount.current) {\n // So we change the key to force a rerender of the Slate editor,\n // which will pick up the new value through its initialValue prop\n setKey((previousKey) => previousKey + 1);\n\n // Then bring the 2 refs back in sync\n slateUpdatesCount.current = valueUpdatesCount.current;\n }\n }, [value]);\n\n const incrementSlateUpdatesCount = React.useCallback(() => {\n slateUpdatesCount.current += 1;\n }, []);\n\n return { key, incrementSlateUpdatesCount };\n}\n\nconst pipe =\n (...fns: ((baseEditor: Editor) => Editor)[]) =>\n (value: Editor) =>\n fns.reduce<Editor>((prev, fn) => fn(prev), value);\n\n/**\n * Normalize the blocks state to null if the editor state is considered empty,\n * otherwise return the state\n */\nconst normalizeBlocksState = (\n editor: Editor,\n value: Schema.Attribute.BlocksValue | Descendant[]\n): Schema.Attribute.BlocksValue | Descendant[] | null => {\n const isEmpty =\n value.length === 1 && Editor.isEmpty(editor, value[0] as Schema.Attribute.BlocksNode);\n\n return isEmpty ? null : value;\n};\n\ninterface BlocksEditorProps\n extends Pick<FieldValue<Schema.Attribute.BlocksValue>, 'onChange' | 'value' | 'error'>,\n BlocksContentProps {\n disabled?: boolean;\n name: string;\n}\n\nconst BlocksEditor = React.forwardRef<{ focus: () => void }, BlocksEditorProps>(\n ({ disabled = false, name, onChange, value, error, ...contentProps }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const isMobile = useIsMobile();\n\n const blocks = React.useMemo(\n () => ({\n ...paragraphBlocks,\n ...headingBlocks,\n ...listBlocks,\n ...linkBlocks,\n ...imageBlocks,\n ...quoteBlocks,\n ...codeBlocks,\n }),\n []\n ) satisfies BlocksStore;\n\n const blockRegisteredPlugins = Object.values(blocks)\n .map((block) => block.plugin)\n .filter(isNonNullable);\n\n const [editor] = React.useState(() =>\n pipe(withHistory, withStrapiSchema, withReact, ...blockRegisteredPlugins)(createEditor())\n );\n const [liveText, setLiveText] = React.useState('');\n const ariaDescriptionId = React.useId();\n const [isExpandedMode, handleToggleExpand] = React.useReducer((prev) => !prev, false);\n\n /**\n * Editable is not able to hold the ref, https://github.com/ianstormtaylor/slate/issues/4082\n * so with \"useImperativeHandle\" we can use ReactEditor methods to expose to the parent above\n * also not passing forwarded ref here, gives console warning.\n */\n React.useImperativeHandle(\n forwardedRef,\n () => ({\n focus() {\n ReactEditor.focus(editor);\n },\n }),\n [editor]\n );\n\n const { key, incrementSlateUpdatesCount } = useResetKey(value);\n\n const debounceTimeout = React.useRef<NodeJS.Timeout | null>(null);\n\n const flushPendingFormSync = React.useCallback(() => {\n if (!debounceTimeout.current) {\n return;\n }\n clearTimeout(debounceTimeout.current);\n debounceTimeout.current = null;\n incrementSlateUpdatesCount();\n // Ensure Strapi Form state updates before the next event (e.g. Save click) reads values.\n flushSync(() => {\n onChange(\n name,\n normalizeBlocksState(editor, editor.children) as Schema.Attribute.BlocksValue\n );\n });\n }, [editor, incrementSlateUpdatesCount, name, onChange]);\n\n const handleSlateChange = React.useCallback(\n (state: Descendant[]) => {\n const isAstChange = editor.operations.some((op) => op.type !== 'set_selection');\n\n if (isAstChange) {\n /**\n * Slate handles the state of the editor internally. We just need to keep Strapi's form\n * state in sync with it in order to make sure that things like the \"modified\" state\n * isn't broken. Updating the whole state on every change is very expensive however,\n * so we debounce calls to onChange to mitigate input lag.\n */\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n\n // Set a new debounce timeout\n debounceTimeout.current = setTimeout(() => {\n incrementSlateUpdatesCount();\n\n // Normalize the state (empty editor becomes null)\n onChange(name, normalizeBlocksState(editor, state) as Schema.Attribute.BlocksValue);\n debounceTimeout.current = null;\n }, 300);\n }\n },\n [editor, incrementSlateUpdatesCount, name, onChange]\n );\n\n // Clean up the timeout on unmount\n React.useEffect(() => {\n return () => {\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n };\n }, []);\n\n // Ensure the editor is in sync after discard\n React.useEffect(() => {\n // Never deselect while the editor is actively focused (typing / editing),\n if (ReactEditor.isFocused(editor)) {\n return;\n }\n\n // Normalize empty states for comparison to avoid losing focus on the editor when content is deleted\n const normalizedValue = value?.length ? value : null;\n const normalizedEditorState = normalizeBlocksState(editor, editor.children);\n\n // Compare the field value with the editor state to check for a stale selection\n if (\n normalizedValue &&\n normalizedEditorState &&\n JSON.stringify(normalizedEditorState) !== JSON.stringify(normalizedValue)\n ) {\n // When there is a diff, unset selection to avoid an invalid state\n Transforms.deselect(editor);\n }\n }, [editor, value]);\n\n return (\n <>\n <VisuallyHidden id={ariaDescriptionId}>\n {formatMessage({\n id: getTranslation('components.Blocks.dnd.instruction'),\n defaultMessage: `To reorder blocks, press Command or Control along with Shift and the Up or Down arrow keys`,\n })}\n </VisuallyHidden>\n <VisuallyHidden aria-live=\"assertive\">{liveText}</VisuallyHidden>\n <Slate\n editor={editor}\n initialValue={\n value?.length ? value : [{ type: 'paragraph', children: [{ type: 'text', text: '' }] }]\n }\n onChange={handleSlateChange}\n key={key}\n >\n <BlocksEditorProvider\n blocks={blocks}\n modifiers={modifiers}\n disabled={disabled}\n name={name}\n setLiveText={setLiveText}\n isExpandedMode={isExpandedMode}\n flushPendingFormSync={flushPendingFormSync}\n >\n <EditorLayout\n error={error}\n disabled={disabled}\n onToggleExpand={handleToggleExpand}\n ariaDescriptionId={ariaDescriptionId}\n >\n <BlocksToolbar />\n <EditorDivider width=\"100%\" />\n <BlocksContent {...contentProps} />\n {!isExpandedMode && !isMobile && (\n <IconButton\n position=\"absolute\"\n bottom=\"1.2rem\"\n right=\"1.2rem\"\n shadow=\"filterShadow\"\n label={formatMessage({\n id: getTranslation('components.Blocks.expand'),\n defaultMessage: 'Expand',\n })}\n onClick={handleToggleExpand}\n >\n <Expand />\n </IconButton>\n )}\n </EditorLayout>\n </BlocksEditorProvider>\n </Slate>\n </>\n );\n }\n);\n\nexport {\n type BlocksStore,\n type SelectorBlockKey,\n BlocksEditor,\n BlocksEditorProvider,\n useBlocksEditorContext,\n isSelectorBlockKey,\n normalizeBlocksState,\n};\n"],"names":["selectorBlockKeys","isSelectorBlockKey","key","includes","BlocksEditorProvider","usePartialBlocksEditorContext","createContext","useBlocksEditorContext","consumerName","context","state","editor","useSlate","EditorDivider","styled","Divider","theme","colors","neutral200","useResetKey","value","slateUpdatesCount","React","useRef","valueUpdatesCount","setKey","useState","useEffect","current","previousKey","incrementSlateUpdatesCount","useCallback","pipe","fns","reduce","prev","fn","normalizeBlocksState","isEmpty","length","Editor","BlocksEditor","forwardRef","disabled","name","onChange","error","contentProps","forwardedRef","formatMessage","useIntl","isMobile","useIsMobile","blocks","useMemo","paragraphBlocks","headingBlocks","listBlocks","linkBlocks","imageBlocks","quoteBlocks","codeBlocks","blockRegisteredPlugins","Object","values","map","block","plugin","filter","isNonNullable","withHistory","withStrapiSchema","withReact","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","flushPendingFormSync","clearTimeout","flushSync","children","handleSlateChange","isAstChange","operations","some","op","type","setTimeout","isFocused","normalizedValue","normalizedEditorState","JSON","stringify","Transforms","deselect","_jsxs","_Fragment","_jsx","VisuallyHidden","id","getTranslation","defaultMessage","aria-live","Slate","initialValue","text","modifiers","EditorLayout","onToggleExpand","BlocksToolbar","width","BlocksContent","IconButton","position","bottom","right","shadow","label","onClick","Expand"],"mappings":"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"}
1
+ {"version":3,"file":"BlocksEditor.mjs","sources":["../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport {\n createContext,\n useStrapiApp,\n type FieldValue,\n useIsMobile,\n} from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { flushSync } from 'react-dom';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms, Element } from 'slate';\nimport { withHistory } from 'slate-history';\nimport { type RenderElementProps, Slate, withReact, ReactEditor, useSlate } from 'slate-react';\nimport { styled, type CSSProperties } from 'styled-components';\n\nimport { ContentManagerPlugin } from '../../../../../content-manager';\nimport { getTranslation } from '../../../../../utils/translations';\n\nimport { BlocksContent, type BlocksContentProps } from './BlocksContent';\nimport { BlocksToolbar } from './BlocksToolbar';\nimport { EditorLayout } from './EditorLayout';\nimport { type ModifiersStore, modifiers } from './Modifiers';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\nimport { isNonNullable } from './utils/types';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface CustomNode extends Omit<Schema.Attribute.BlocksNode, 'type'> {\n type: Schema.Attribute.BlocksNode['type'] | string;\n level?: number;\n format?: string;\n}\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\n /** Function to check if a given node is of this type of block */\n matchNode: (node: Schema.Attribute.BlocksNode | CustomNode) => boolean;\n handleConvert?: (editor: Editor) => void | (() => React.JSX.Element);\n handleEnterKey?: (editor: Editor) => void;\n handleBackspaceKey?: (editor: Editor, event: React.KeyboardEvent<HTMLElement>) => void;\n handleTab?: (editor: Editor) => void;\n handleShiftTab?: (editor: Editor) => void;\n snippets?: string[];\n /** Adjust the vertical positioning of the drag-to-reorder grip icon */\n dragHandleTopMargin?: CSSProperties['marginTop'];\n /** A Slate plugin: function that will wrap the editor creation */\n plugin?: (editor: Editor) => Editor;\n /**\n * Function that checks if an element should be draggable\n * @default () => true */\n isDraggable?: (element: Element) => boolean;\n}\n\nexport interface NonSelectorBlock extends BaseBlock {\n isInBlocksSelector?: false;\n}\n\nexport interface SelectorBlock extends BaseBlock {\n isInBlocksSelector: true;\n icon?: React.ComponentType;\n label: MessageDescriptor;\n}\n\ntype NonSelectorBlockKey = 'list-item' | 'link';\n\nconst selectorBlockKeys = [\n 'paragraph',\n 'heading-one',\n 'heading-two',\n 'heading-three',\n 'heading-four',\n 'heading-five',\n 'heading-six',\n 'list-ordered',\n 'list-unordered',\n 'image',\n 'quote',\n 'code',\n] as const;\n\ntype SelectorBlockKey = (typeof selectorBlockKeys)[number];\n\nconst isSelectorBlockKey = (key: unknown): key is SelectorBlockKey => {\n return typeof key === 'string' && selectorBlockKeys.includes(key as SelectorBlockKey);\n};\n\ntype BlocksStore = {\n [K in SelectorBlockKey]: SelectorBlock;\n} & {\n [K in NonSelectorBlockKey]: NonSelectorBlock;\n};\n\ntype RichTextBlocksStore = Partial<BlocksStore> & Record<string, SelectorBlock | NonSelectorBlock>;\n\ninterface BlocksEditorContextValue {\n blocks: RichTextBlocksStore;\n modifiers: ModifiersStore;\n disabled: boolean;\n name: string;\n setLiveText: (text: string) => void;\n isExpandedMode: boolean;\n /** Push debounced Slate → form sync immediately (e.g. on Editable blur before Save). */\n flushPendingFormSync: () => void;\n}\n\nconst [BlocksEditorProvider, usePartialBlocksEditorContext] =\n createContext<BlocksEditorContextValue>('BlocksEditor');\n\nfunction useBlocksEditorContext(consumerName: string): BlocksEditorContextValue & {\n editor: Editor;\n} {\n const context = usePartialBlocksEditorContext(consumerName, (state) => state);\n const editor = useSlate();\n\n return {\n ...context,\n editor,\n };\n}\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditor\n * -----------------------------------------------------------------------------------------------*/\n\nconst EditorDivider = styled(Divider)`\n background: ${({ theme }) => theme.colors.neutral200};\n`;\n\n/**\n * Forces an update of the Slate editor when the value prop changes from outside of Slate.\n * The root cause is that Slate is not a controlled component: https://github.com/ianstormtaylor/slate/issues/4612\n * Why not use JSON.stringify(value) as the key?\n * Because it would force a rerender of the entire editor every time the user types a character.\n * Why not use the entity id as the key, since it's unique for each locale?\n * Because it would not solve the problem when using the \"fill in from other locale\" feature\n */\nfunction useResetKey(value?: Schema.Attribute.BlocksValue): {\n key: number;\n incrementSlateUpdatesCount: () => void;\n} {\n // Keep track how many times Slate detected a change from a user interaction in the editor\n const slateUpdatesCount = React.useRef(0);\n // Keep track of how many times the value prop was updated, whether from within editor or from outside\n const valueUpdatesCount = React.useRef(0);\n // Use a key to force a rerender of the Slate editor when needed\n const [key, setKey] = React.useState(0);\n\n React.useEffect(() => {\n valueUpdatesCount.current += 1;\n\n // If the 2 refs are not equal, it means the value was updated from outside\n if (valueUpdatesCount.current !== slateUpdatesCount.current) {\n // So we change the key to force a rerender of the Slate editor,\n // which will pick up the new value through its initialValue prop\n setKey((previousKey) => previousKey + 1);\n\n // Then bring the 2 refs back in sync\n slateUpdatesCount.current = valueUpdatesCount.current;\n }\n }, [value]);\n\n const incrementSlateUpdatesCount = React.useCallback(() => {\n slateUpdatesCount.current += 1;\n }, []);\n\n return { key, incrementSlateUpdatesCount };\n}\n\nconst pipe =\n (...fns: ((baseEditor: Editor) => Editor)[]) =>\n (value: Editor) =>\n fns.reduce<Editor>((prev, fn) => fn(prev), value);\n\n/**\n * Normalize the blocks state to null if the editor state is considered empty,\n * otherwise return the state\n */\nconst normalizeBlocksState = (\n editor: Editor,\n value: Schema.Attribute.BlocksValue | Descendant[]\n): Schema.Attribute.BlocksValue | Descendant[] | null => {\n const isEmpty =\n value.length === 1 && Editor.isEmpty(editor, value[0] as Schema.Attribute.BlocksNode);\n\n return isEmpty ? null : value;\n};\n\ninterface BlocksEditorProps\n extends Pick<FieldValue<Schema.Attribute.BlocksValue>, 'onChange' | 'value' | 'error'>,\n BlocksContentProps {\n disabled?: boolean;\n name: string;\n}\n\nconst BlocksEditor = React.forwardRef<{ focus: () => void }, BlocksEditorProps>(\n ({ disabled = false, name, onChange, value, error, ...contentProps }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const isMobile = useIsMobile();\n\n const blocks = useStrapiApp(\n 'BlocksEditor',\n (state) =>\n (\n state.plugins['content-manager']?.apis as\n | ContentManagerPlugin['config']['apis']\n | undefined\n )?.getRichTextBlocks() ?? ({} as RichTextBlocksStore)\n );\n\n const blockRegisteredPlugins = Object.values(blocks)\n .map((block) => block.plugin)\n .filter(isNonNullable);\n\n const [editor] = React.useState(() =>\n pipe(withHistory, withStrapiSchema, withReact, ...blockRegisteredPlugins)(createEditor())\n );\n const [liveText, setLiveText] = React.useState('');\n const ariaDescriptionId = React.useId();\n const [isExpandedMode, handleToggleExpand] = React.useReducer((prev) => !prev, false);\n\n /**\n * Editable is not able to hold the ref, https://github.com/ianstormtaylor/slate/issues/4082\n * so with \"useImperativeHandle\" we can use ReactEditor methods to expose to the parent above\n * also not passing forwarded ref here, gives console warning.\n */\n React.useImperativeHandle(\n forwardedRef,\n () => ({\n focus() {\n ReactEditor.focus(editor);\n },\n }),\n [editor]\n );\n\n const { key, incrementSlateUpdatesCount } = useResetKey(value);\n\n const debounceTimeout = React.useRef<NodeJS.Timeout | null>(null);\n\n const flushPendingFormSync = React.useCallback(() => {\n if (!debounceTimeout.current) {\n return;\n }\n clearTimeout(debounceTimeout.current);\n debounceTimeout.current = null;\n incrementSlateUpdatesCount();\n // Ensure Strapi Form state updates before the next event (e.g. Save click) reads values.\n flushSync(() => {\n onChange(\n name,\n normalizeBlocksState(editor, editor.children) as Schema.Attribute.BlocksValue\n );\n });\n }, [editor, incrementSlateUpdatesCount, name, onChange]);\n\n const handleSlateChange = React.useCallback(\n (state: Descendant[]) => {\n const isAstChange = editor.operations.some((op) => op.type !== 'set_selection');\n\n if (isAstChange) {\n /**\n * Slate handles the state of the editor internally. We just need to keep Strapi's form\n * state in sync with it in order to make sure that things like the \"modified\" state\n * isn't broken. Updating the whole state on every change is very expensive however,\n * so we debounce calls to onChange to mitigate input lag.\n */\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n\n // Set a new debounce timeout\n debounceTimeout.current = setTimeout(() => {\n incrementSlateUpdatesCount();\n\n // Normalize the state (empty editor becomes null)\n onChange(name, normalizeBlocksState(editor, state) as Schema.Attribute.BlocksValue);\n debounceTimeout.current = null;\n }, 300);\n }\n },\n [editor, incrementSlateUpdatesCount, name, onChange]\n );\n\n // Clean up the timeout on unmount\n React.useEffect(() => {\n return () => {\n if (debounceTimeout.current) {\n clearTimeout(debounceTimeout.current);\n }\n };\n }, []);\n\n // Ensure the editor is in sync after discard\n React.useEffect(() => {\n // Never deselect while the editor is actively focused (typing / editing),\n if (ReactEditor.isFocused(editor)) {\n return;\n }\n\n // Normalize empty states for comparison to avoid losing focus on the editor when content is deleted\n const normalizedValue = value?.length ? value : null;\n const normalizedEditorState = normalizeBlocksState(editor, editor.children);\n\n // Compare the field value with the editor state to check for a stale selection\n if (\n normalizedValue &&\n normalizedEditorState &&\n JSON.stringify(normalizedEditorState) !== JSON.stringify(normalizedValue)\n ) {\n // When there is a diff, unset selection to avoid an invalid state\n Transforms.deselect(editor);\n }\n }, [editor, value]);\n\n return (\n <>\n <VisuallyHidden id={ariaDescriptionId}>\n {formatMessage({\n id: getTranslation('components.Blocks.dnd.instruction'),\n defaultMessage: `To reorder blocks, press Command or Control along with Shift and the Up or Down arrow keys`,\n })}\n </VisuallyHidden>\n <VisuallyHidden aria-live=\"assertive\">{liveText}</VisuallyHidden>\n <Slate\n editor={editor}\n initialValue={\n value?.length ? value : [{ type: 'paragraph', children: [{ type: 'text', text: '' }] }]\n }\n onChange={handleSlateChange}\n key={key}\n >\n <BlocksEditorProvider\n blocks={blocks}\n modifiers={modifiers}\n disabled={disabled}\n name={name}\n setLiveText={setLiveText}\n isExpandedMode={isExpandedMode}\n flushPendingFormSync={flushPendingFormSync}\n >\n <EditorLayout\n error={error}\n disabled={disabled}\n onToggleExpand={handleToggleExpand}\n ariaDescriptionId={ariaDescriptionId}\n >\n <BlocksToolbar />\n <EditorDivider width=\"100%\" />\n <BlocksContent {...contentProps} />\n {!isExpandedMode && !isMobile && (\n <IconButton\n position=\"absolute\"\n bottom=\"1.2rem\"\n right=\"1.2rem\"\n shadow=\"filterShadow\"\n label={formatMessage({\n id: getTranslation('components.Blocks.expand'),\n defaultMessage: 'Expand',\n })}\n onClick={handleToggleExpand}\n >\n <Expand />\n </IconButton>\n )}\n </EditorLayout>\n </BlocksEditorProvider>\n </Slate>\n </>\n );\n }\n);\n\nexport {\n type BlocksStore,\n type RichTextBlocksStore,\n type SelectorBlockKey,\n BlocksEditor,\n BlocksEditorProvider,\n useBlocksEditorContext,\n isSelectorBlockKey,\n normalizeBlocksState,\n};\n"],"names":["BlocksEditorProvider","usePartialBlocksEditorContext","createContext","useBlocksEditorContext","consumerName","context","state","editor","useSlate","EditorDivider","styled","Divider","theme","colors","neutral200","useResetKey","value","slateUpdatesCount","React","useRef","valueUpdatesCount","key","setKey","useState","useEffect","current","previousKey","incrementSlateUpdatesCount","useCallback","pipe","fns","reduce","prev","fn","normalizeBlocksState","isEmpty","length","Editor","BlocksEditor","forwardRef","disabled","name","onChange","error","contentProps","forwardedRef","formatMessage","useIntl","isMobile","useIsMobile","blocks","useStrapiApp","plugins","apis","getRichTextBlocks","blockRegisteredPlugins","Object","values","map","block","plugin","filter","isNonNullable","withHistory","withStrapiSchema","withReact","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","flushPendingFormSync","clearTimeout","flushSync","children","handleSlateChange","isAstChange","operations","some","op","type","setTimeout","isFocused","normalizedValue","normalizedEditorState","JSON","stringify","Transforms","deselect","_jsxs","_Fragment","_jsx","VisuallyHidden","id","getTranslation","defaultMessage","aria-live","Slate","initialValue","text","modifiers","EditorLayout","onToggleExpand","BlocksToolbar","width","BlocksContent","IconButton","position","bottom","right","shadow","label","onClick","Expand"],"mappings":"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"}
@@ -159,7 +159,7 @@ const ToolbarButton = ({ icon: Icon, name, label, isActive, disabled, handleClic
159
159
  height: 7,
160
160
  hasRadius: true,
161
161
  type: "button",
162
- children: /*#__PURE__*/ jsxRuntime.jsx(Icon, {
162
+ children: Icon && /*#__PURE__*/ jsxRuntime.jsx(Icon, {
163
163
  fill: disabled ? 'neutral300' : enabledColor
164
164
  })
165
165
  })
@@ -171,16 +171,15 @@ const BlocksDropdown = ()=>{
171
171
  const { formatMessage } = reactIntl.useIntl();
172
172
  const { modalElement, handleConversionResult } = useConversionModal();
173
173
  const isMobile = strapiAdmin.useIsMobile();
174
- const blockKeysToInclude = types.getEntries(blocks).reduce((currentKeys, entry)=>{
175
- const [key, block] = entry;
176
- return block.isInBlocksSelector ? [
174
+ const blockKeysToInclude = types.getEntries(blocks).reduce((currentKeys, [key, block])=>{
175
+ return block?.isInBlocksSelector ? [
177
176
  ...currentKeys,
178
177
  key
179
178
  ] : currentKeys;
180
179
  }, []);
181
180
  const [blockSelected, setBlockSelected] = React__namespace.useState('paragraph');
182
181
  const handleSelect = (optionKey)=>{
183
- if (!BlocksEditor.isSelectorBlockKey(optionKey)) {
182
+ if (typeof optionKey !== 'string' || !blocks[optionKey]) {
184
183
  return;
185
184
  }
186
185
  const editorIsEmpty = editor.children.length === 1 && slate.Editor.isEmpty(editor, editor.children[0]);
@@ -229,7 +228,7 @@ const BlocksDropdown = ()=>{
229
228
  return;
230
229
  }
231
230
  // Let the block handle the Slate conversion logic
232
- const maybeRenderModal = blocks[optionKey].handleConvert?.(editor);
231
+ const maybeRenderModal = blocks[optionKey]?.handleConvert?.(editor);
233
232
  handleConversionResult(maybeRenderModal);
234
233
  setBlockSelected(optionKey);
235
234
  slateReact.ReactEditor.focus(editor);
@@ -278,7 +277,7 @@ const BlocksDropdown = ()=>{
278
277
  }
279
278
  }
280
279
  // Find the block key that matches the anchor node
281
- const anchorBlockKey = types.getKeys(blocks).find((blockKey)=>!slate.Editor.isEditor(selectedNode) && blocks[blockKey].matchNode(selectedNode));
280
+ const anchorBlockKey = types.getKeys(blocks).find((blockKey)=>!slate.Editor.isEditor(selectedNode) && blocks[blockKey]?.matchNode(selectedNode));
282
281
  // Change the value selected in the dropdown if it doesn't match the anchor block key
283
282
  if (anchorBlockKey && anchorBlockKey !== blockSelected) {
284
283
  setBlockSelected(anchorBlockKey);
@@ -290,14 +289,27 @@ const BlocksDropdown = ()=>{
290
289
  blocks,
291
290
  blockSelected
292
291
  ]);
293
- const Icon = blocks[blockSelected].icon;
292
+ React__namespace.useEffect(()=>{
293
+ // If the selected block is not in the list of blocks to include, change the selected block to the first one
294
+ if (blockKeysToInclude.length > 0 && !blockKeysToInclude.includes(blockSelected)) {
295
+ setBlockSelected(blockKeysToInclude[0]);
296
+ }
297
+ }, [
298
+ blockKeysToInclude,
299
+ blockSelected
300
+ ]);
301
+ if (!blocks[blockSelected]) {
302
+ return null;
303
+ }
304
+ const selectedBlock = blocks[blockSelected];
305
+ const Icon = selectedBlock.icon;
294
306
  return /*#__PURE__*/ jsxRuntime.jsxs(jsxRuntime.Fragment, {
295
307
  children: [
296
308
  /*#__PURE__*/ jsxRuntime.jsx(SelectWrapper, {
297
309
  children: /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelect, {
298
- startIcon: /*#__PURE__*/ jsxRuntime.jsx(Icon, {}),
310
+ startIcon: Icon && /*#__PURE__*/ jsxRuntime.jsx(Icon, {}),
299
311
  onChange: handleSelect,
300
- customizeContent: ()=>isMobile ? '' : formatMessage(blocks[blockSelected].label),
312
+ customizeContent: ()=>isMobile ? '' : formatMessage(selectedBlock.label),
301
313
  value: blockSelected,
302
314
  onCloseAutoFocus: preventSelectFocus,
303
315
  "aria-label": formatMessage({
@@ -305,12 +317,15 @@ const BlocksDropdown = ()=>{
305
317
  defaultMessage: 'Select a block'
306
318
  }),
307
319
  disabled: disabled,
308
- children: blockKeysToInclude.map((key)=>/*#__PURE__*/ jsxRuntime.jsx(BlockOption, {
320
+ children: blockKeysToInclude.map((key)=>{
321
+ const selectorBlock = blocks[key];
322
+ return /*#__PURE__*/ jsxRuntime.jsx(BlockOption, {
309
323
  value: key,
310
- label: blocks[key].label,
311
- icon: blocks[key].icon,
324
+ label: selectorBlock.label,
325
+ icon: selectorBlock.icon,
312
326
  blockSelected: blockSelected
313
- }, key))
327
+ }, key);
328
+ })
314
329
  })
315
330
  }),
316
331
  modalElement
@@ -321,7 +336,7 @@ const BlockOption = ({ value, icon: Icon, label, blockSelected })=>{
321
336
  const { formatMessage } = reactIntl.useIntl();
322
337
  const isSelected = value === blockSelected;
323
338
  return /*#__PURE__*/ jsxRuntime.jsx(designSystem.SingleSelectOption, {
324
- startIcon: /*#__PURE__*/ jsxRuntime.jsx(Icon, {
339
+ startIcon: Icon && /*#__PURE__*/ jsxRuntime.jsx(Icon, {
325
340
  fill: isSelected ? 'primary600' : 'neutral500'
326
341
  }),
327
342
  value: value,
@@ -390,7 +405,7 @@ const ListButton = ({ block, format, location = 'toolbar' })=>{
390
405
  }
391
406
  if (!currentListEntry) {
392
407
  // If selection is not a list then convert it to list
393
- blocks[`list-${format}`].handleConvert(editor);
408
+ blocks[`list-${format}`]?.handleConvert(editor);
394
409
  return;
395
410
  }
396
411
  // If selection is already a list then toggle format
@@ -405,14 +420,14 @@ const ListButton = ({ block, format, location = 'toolbar' })=>{
405
420
  });
406
421
  } else {
407
422
  // Format is same, convert selected list-item to paragraph
408
- blocks['paragraph'].handleConvert(editor);
423
+ blocks['paragraph']?.handleConvert(editor);
409
424
  }
410
425
  }
411
426
  };
412
427
  if (location === 'menu') {
413
428
  const Icon = block.icon;
414
429
  return /*#__PURE__*/ jsxRuntime.jsx(StyledMenuItem, {
415
- startIcon: /*#__PURE__*/ jsxRuntime.jsx(Icon, {}),
430
+ startIcon: Icon && /*#__PURE__*/ jsxRuntime.jsx(Icon, {}),
416
431
  onSelect: ()=>toggleList(format),
417
432
  isActive: isListActive(),
418
433
  disabled: isListDisabled(),