@strapi/content-manager 5.33.2 → 5.33.4

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 (86) hide show
  1. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.js +23 -1
  2. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.js.map +1 -1
  3. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.mjs +23 -1
  4. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.mjs.map +1 -1
  5. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.js +14 -1
  6. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.js.map +1 -1
  7. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.mjs +14 -1
  8. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.mjs.map +1 -1
  9. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.js +157 -7
  10. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.js.map +1 -1
  11. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.mjs +154 -5
  12. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.mjs.map +1 -1
  13. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.js +28 -20
  14. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.js.map +1 -1
  15. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.mjs +25 -17
  16. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/List.mjs.map +1 -1
  17. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js +6 -3
  18. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js.map +1 -1
  19. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs +7 -4
  20. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs.map +1 -1
  21. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js +12 -12
  22. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js.map +1 -1
  23. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs +13 -13
  24. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs.map +1 -1
  25. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js +2 -2
  26. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js.map +1 -1
  27. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs +1 -1
  28. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs.map +1 -1
  29. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/types.js +4 -8
  30. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/types.js.map +1 -1
  31. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/types.mjs +4 -7
  32. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/types.mjs.map +1 -1
  33. package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js +2 -12
  34. package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.js.map +1 -1
  35. package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs +2 -12
  36. package/dist/admin/pages/EditView/components/FormInputs/Component/NonRepeatable.mjs.map +1 -1
  37. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js +48 -1
  38. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js.map +1 -1
  39. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs +49 -2
  40. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs.map +1 -1
  41. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js +47 -13
  42. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js.map +1 -1
  43. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs +49 -15
  44. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs.map +1 -1
  45. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.js +1 -0
  46. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.js.map +1 -1
  47. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.mjs +1 -0
  48. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/Field.mjs.map +1 -1
  49. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +10 -1
  50. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
  51. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +10 -1
  52. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
  53. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.js +5 -1
  54. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.js.map +1 -1
  55. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.mjs +5 -1
  56. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/Editor.mjs.map +1 -1
  57. package/dist/admin/pages/EditView/components/InputRenderer.js +6 -2
  58. package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
  59. package/dist/admin/pages/EditView/components/InputRenderer.mjs +6 -2
  60. package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
  61. package/dist/admin/pages/EditView/utils/data.js +22 -0
  62. package/dist/admin/pages/EditView/utils/data.js.map +1 -1
  63. package/dist/admin/pages/EditView/utils/data.mjs +22 -1
  64. package/dist/admin/pages/EditView/utils/data.mjs.map +1 -1
  65. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.d.ts +9 -1
  66. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.d.ts +9 -1
  67. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/plugins/withStrapiSchema.d.ts +1 -1
  68. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/types.d.ts +2 -4
  69. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +2 -1
  70. package/dist/admin/src/pages/EditView/utils/data.d.ts +6 -1
  71. package/package.json +9 -9
  72. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withImages.js +0 -17
  73. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withImages.js.map +0 -1
  74. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withImages.mjs +0 -15
  75. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withImages.mjs.map +0 -1
  76. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withLinks.js +0 -75
  77. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withLinks.js.map +0 -1
  78. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withLinks.mjs +0 -73
  79. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/plugins/withLinks.mjs.map +0 -1
  80. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.js +0 -88
  81. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.js.map +0 -1
  82. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.mjs +0 -84
  83. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.mjs.map +0 -1
  84. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/plugins/withImages.d.ts +0 -11
  85. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/plugins/withLinks.d.ts +0 -9
  86. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/links.d.ts +0 -12
@@ -192,6 +192,27 @@ const CodeEditor = (props)=>{
192
192
  ]
193
193
  });
194
194
  };
195
+ const withCode = (editor)=>{
196
+ const { insertData } = editor;
197
+ editor.insertData = (data)=>{
198
+ const pastedText = data.getData('text/plain');
199
+ if (pastedText && editor.selection) {
200
+ // Check if we're currently inside a code block
201
+ const codeBlockEntry = slate.Editor.above(editor, {
202
+ match: (node)=>!slate.Editor.isEditor(node) && node.type === 'code'
203
+ });
204
+ if (codeBlockEntry) {
205
+ // We're inside a code block, handle the paste specially
206
+ // Replace the selected content with the pasted text, preserving newlines
207
+ slate.Transforms.insertText(editor, pastedText);
208
+ return;
209
+ }
210
+ }
211
+ // For non-code blocks, use the default behavior
212
+ insertData(data);
213
+ };
214
+ return editor;
215
+ };
195
216
  const codeBlocks = {
196
217
  code: {
197
218
  renderElement: (props)=>/*#__PURE__*/ jsxRuntime.jsx(CodeEditor, {
@@ -215,7 +236,8 @@ const codeBlocks = {
215
236
  },
216
237
  snippets: [
217
238
  '```'
218
- ]
239
+ ],
240
+ plugin: withCode
219
241
  }
220
242
  };
221
243
 
@@ -1 +1 @@
1
- {"version":3,"file":"Code.js","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, SingleSelect, SingleSelectOption } from '@strapi/design-system';\nimport { CodeBlock as CodeBlockIcon } from '@strapi/icons';\nimport * as Prism from 'prismjs';\nimport { useIntl } from 'react-intl';\nimport { BaseRange, Element, Editor, Node, NodeEntry, Transforms } from 'slate';\nimport { useSelected, type RenderElementProps, useFocused, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\n\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { codeLanguages } from '../utils/constants';\nimport { baseHandleConvert } from '../utils/conversions';\nimport { pressEnterTwiceToExit } from '../utils/enterKey';\nimport { type Block } from '../utils/types';\n\nimport 'prismjs/themes/prism-solarizedlight.css';\nimport 'prismjs/components/prism-asmatmel';\nimport 'prismjs/components/prism-bash';\nimport 'prismjs/components/prism-basic';\nimport 'prismjs/components/prism-c';\nimport 'prismjs/components/prism-clojure';\nimport 'prismjs/components/prism-cobol';\nimport 'prismjs/components/prism-cpp';\nimport 'prismjs/components/prism-csharp';\nimport 'prismjs/components/prism-dart';\nimport 'prismjs/components/prism-docker';\nimport 'prismjs/components/prism-elixir';\nimport 'prismjs/components/prism-erlang';\nimport 'prismjs/components/prism-fortran';\nimport 'prismjs/components/prism-fsharp';\nimport 'prismjs/components/prism-go';\nimport 'prismjs/components/prism-graphql';\nimport 'prismjs/components/prism-groovy';\nimport 'prismjs/components/prism-haskell';\nimport 'prismjs/components/prism-haxe';\nimport 'prismjs/components/prism-ini';\nimport 'prismjs/components/prism-java';\nimport 'prismjs/components/prism-javascript';\nimport 'prismjs/components/prism-jsx';\nimport 'prismjs/components/prism-json';\nimport 'prismjs/components/prism-julia';\nimport 'prismjs/components/prism-kotlin';\nimport 'prismjs/components/prism-latex';\nimport 'prismjs/components/prism-lua';\nimport 'prismjs/components/prism-markdown';\nimport 'prismjs/components/prism-matlab';\nimport 'prismjs/components/prism-makefile';\nimport 'prismjs/components/prism-objectivec';\nimport 'prismjs/components/prism-perl';\nimport 'prismjs/components/prism-php';\nimport 'prismjs/components/prism-powershell';\nimport 'prismjs/components/prism-python';\nimport 'prismjs/components/prism-r';\nimport 'prismjs/components/prism-ruby';\nimport 'prismjs/components/prism-rust';\nimport 'prismjs/components/prism-sas';\nimport 'prismjs/components/prism-scala';\nimport 'prismjs/components/prism-scheme';\nimport 'prismjs/components/prism-sql';\nimport 'prismjs/components/prism-stata';\nimport 'prismjs/components/prism-swift';\nimport 'prismjs/components/prism-typescript';\nimport 'prismjs/components/prism-tsx';\nimport 'prismjs/components/prism-vbnet';\nimport 'prismjs/components/prism-yaml';\n\ntype BaseRangeCustom = BaseRange & { className: string };\n\nexport const decorateCode = ([node, path]: NodeEntry) => {\n const ranges: BaseRangeCustom[] = [];\n\n // make sure it is an Slate Element\n if (!Element.isElement(node) || node.type !== 'code') return ranges;\n // transform the Element into a string\n const text = Node.string(node);\n const language = codeLanguages.find((lang) => lang.value === node.language);\n const decorateKey = language?.decorate ?? language?.value;\n\n const selectedLanguage = Prism.languages[decorateKey || 'plaintext'];\n\n // create \"tokens\" with \"prismjs\" and put them in \"ranges\"\n const tokens = Prism.tokenize(text, selectedLanguage);\n let start = 0;\n for (const token of tokens) {\n const length = token.length;\n const end = start + length;\n if (typeof token !== 'string') {\n ranges.push({\n anchor: { path, offset: start },\n focus: { path, offset: end },\n className: `token ${token.type}`,\n });\n }\n start = end;\n }\n\n // these will be found in \"renderLeaf\" in \"leaf\" and their \"className\" will be applied\n return ranges;\n};\n\nconst CodeBlock = styled.pre`\n border-radius: ${({ theme }) => theme.borderRadius};\n background-color: ${({ theme }) => theme.colors.neutral100};\n max-width: 100%;\n overflow: auto;\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[4]}`};\n flex-shrink: 1;\n\n & > code {\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n color: ${({ theme }) => theme.colors.neutral800};\n overflow: auto;\n max-width: 100%;\n }\n`;\n\nconst CodeEditor = (props: RenderElementProps) => {\n const { editor } = useBlocksEditorContext('ImageDialog');\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n const { formatMessage } = useIntl();\n const [isSelectOpen, setIsSelectOpen] = React.useState(false);\n const shouldDisplayLanguageSelect = (editorIsFocused && imageIsSelected) || isSelectOpen;\n\n return (\n <Box position=\"relative\" width=\"100%\">\n <CodeBlock {...props.attributes}>\n <code>{props.children}</code>\n </CodeBlock>\n {shouldDisplayLanguageSelect && (\n <Box\n position=\"absolute\"\n background=\"neutral0\"\n borderColor=\"neutral150\"\n borderStyle=\"solid\"\n borderWidth=\"0.5px\"\n shadow=\"tableShadow\"\n top=\"100%\"\n marginTop={1}\n right={0}\n padding={1}\n hasRadius\n >\n <SingleSelect\n onChange={(open) => {\n Transforms.setNodes(\n editor,\n { language: open.toString() },\n { match: (node) => !Editor.isEditor(node) && node.type === 'code' }\n );\n }}\n value={(props.element.type === 'code' && props.element.language) || 'plaintext'}\n onOpenChange={(open) => {\n setIsSelectOpen(open);\n\n // Focus the editor again when closing the select so the user can continue typing\n if (!open) {\n ReactEditor.focus(editor);\n }\n }}\n onCloseAutoFocus={(e) => e.preventDefault()}\n aria-label={formatMessage({\n id: 'components.Blocks.blocks.code.languageLabel',\n defaultMessage: 'Select a language',\n })}\n >\n {codeLanguages.map(({ value, label }) => (\n <SingleSelectOption value={value} key={value}>\n {label}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n </Box>\n )}\n </Box>\n );\n};\n\nconst codeBlocks: Pick<BlocksStore, 'code'> = {\n code: {\n renderElement: (props) => <CodeEditor {...props} />,\n icon: CodeBlockIcon,\n label: {\n id: 'components.Blocks.blocks.code',\n defaultMessage: 'Code block',\n },\n matchNode: (node) => node.type === 'code',\n isInBlocksSelector: true,\n handleConvert(editor) {\n baseHandleConvert<Block<'code'>>(editor, { type: 'code', language: 'plaintext' });\n },\n handleEnterKey(editor) {\n pressEnterTwiceToExit(editor);\n },\n snippets: ['```'],\n },\n};\n\nexport { codeBlocks };\n"],"names":["decorateCode","node","path","ranges","Element","isElement","type","text","Node","string","language","codeLanguages","find","lang","value","decorateKey","decorate","selectedLanguage","Prism","languages","tokens","tokenize","start","token","length","end","push","anchor","offset","focus","className","CodeBlock","styled","pre","theme","borderRadius","colors","neutral100","spaces","neutral800","CodeEditor","props","editor","useBlocksEditorContext","editorIsFocused","useFocused","imageIsSelected","useSelected","formatMessage","useIntl","isSelectOpen","setIsSelectOpen","React","useState","shouldDisplayLanguageSelect","_jsxs","Box","position","width","_jsx","attributes","code","children","background","borderColor","borderStyle","borderWidth","shadow","top","marginTop","right","padding","hasRadius","SingleSelect","onChange","open","Transforms","setNodes","toString","match","Editor","isEditor","element","onOpenChange","ReactEditor","onCloseAutoFocus","e","preventDefault","aria-label","id","defaultMessage","map","label","SingleSelectOption","codeBlocks","renderElement","icon","CodeBlockIcon","matchNode","isInBlocksSelector","handleConvert","baseHandleConvert","handleEnterKey","pressEnterTwiceToExit","snippets"],"mappings":"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"}
1
+ {"version":3,"file":"Code.js","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, SingleSelect, SingleSelectOption } from '@strapi/design-system';\nimport { CodeBlock as CodeBlockIcon } from '@strapi/icons';\nimport * as Prism from 'prismjs';\nimport { useIntl } from 'react-intl';\nimport { BaseRange, Element, Editor, Node, NodeEntry, Transforms } from 'slate';\nimport { useSelected, type RenderElementProps, useFocused, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\n\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { codeLanguages } from '../utils/constants';\nimport { baseHandleConvert } from '../utils/conversions';\nimport { pressEnterTwiceToExit } from '../utils/enterKey';\nimport { type Block } from '../utils/types';\n\nimport 'prismjs/themes/prism-solarizedlight.css';\nimport 'prismjs/components/prism-asmatmel';\nimport 'prismjs/components/prism-bash';\nimport 'prismjs/components/prism-basic';\nimport 'prismjs/components/prism-c';\nimport 'prismjs/components/prism-clojure';\nimport 'prismjs/components/prism-cobol';\nimport 'prismjs/components/prism-cpp';\nimport 'prismjs/components/prism-csharp';\nimport 'prismjs/components/prism-dart';\nimport 'prismjs/components/prism-docker';\nimport 'prismjs/components/prism-elixir';\nimport 'prismjs/components/prism-erlang';\nimport 'prismjs/components/prism-fortran';\nimport 'prismjs/components/prism-fsharp';\nimport 'prismjs/components/prism-go';\nimport 'prismjs/components/prism-graphql';\nimport 'prismjs/components/prism-groovy';\nimport 'prismjs/components/prism-haskell';\nimport 'prismjs/components/prism-haxe';\nimport 'prismjs/components/prism-ini';\nimport 'prismjs/components/prism-java';\nimport 'prismjs/components/prism-javascript';\nimport 'prismjs/components/prism-jsx';\nimport 'prismjs/components/prism-json';\nimport 'prismjs/components/prism-julia';\nimport 'prismjs/components/prism-kotlin';\nimport 'prismjs/components/prism-latex';\nimport 'prismjs/components/prism-lua';\nimport 'prismjs/components/prism-markdown';\nimport 'prismjs/components/prism-matlab';\nimport 'prismjs/components/prism-makefile';\nimport 'prismjs/components/prism-objectivec';\nimport 'prismjs/components/prism-perl';\nimport 'prismjs/components/prism-php';\nimport 'prismjs/components/prism-powershell';\nimport 'prismjs/components/prism-python';\nimport 'prismjs/components/prism-r';\nimport 'prismjs/components/prism-ruby';\nimport 'prismjs/components/prism-rust';\nimport 'prismjs/components/prism-sas';\nimport 'prismjs/components/prism-scala';\nimport 'prismjs/components/prism-scheme';\nimport 'prismjs/components/prism-sql';\nimport 'prismjs/components/prism-stata';\nimport 'prismjs/components/prism-swift';\nimport 'prismjs/components/prism-typescript';\nimport 'prismjs/components/prism-tsx';\nimport 'prismjs/components/prism-vbnet';\nimport 'prismjs/components/prism-yaml';\n\ntype BaseRangeCustom = BaseRange & { className: string };\n\nexport const decorateCode = ([node, path]: NodeEntry) => {\n const ranges: BaseRangeCustom[] = [];\n\n // make sure it is an Slate Element\n if (!Element.isElement(node) || node.type !== 'code') return ranges;\n // transform the Element into a string\n const text = Node.string(node);\n const language = codeLanguages.find((lang) => lang.value === node.language);\n const decorateKey = language?.decorate ?? language?.value;\n\n const selectedLanguage = Prism.languages[decorateKey || 'plaintext'];\n\n // create \"tokens\" with \"prismjs\" and put them in \"ranges\"\n const tokens = Prism.tokenize(text, selectedLanguage);\n let start = 0;\n for (const token of tokens) {\n const length = token.length;\n const end = start + length;\n if (typeof token !== 'string') {\n ranges.push({\n anchor: { path, offset: start },\n focus: { path, offset: end },\n className: `token ${token.type}`,\n });\n }\n start = end;\n }\n\n // these will be found in \"renderLeaf\" in \"leaf\" and their \"className\" will be applied\n return ranges;\n};\n\nconst CodeBlock = styled.pre`\n border-radius: ${({ theme }) => theme.borderRadius};\n background-color: ${({ theme }) => theme.colors.neutral100};\n max-width: 100%;\n overflow: auto;\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[4]}`};\n flex-shrink: 1;\n\n & > code {\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n color: ${({ theme }) => theme.colors.neutral800};\n overflow: auto;\n max-width: 100%;\n }\n`;\n\nconst CodeEditor = (props: RenderElementProps) => {\n const { editor } = useBlocksEditorContext('ImageDialog');\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n const { formatMessage } = useIntl();\n const [isSelectOpen, setIsSelectOpen] = React.useState(false);\n const shouldDisplayLanguageSelect = (editorIsFocused && imageIsSelected) || isSelectOpen;\n\n return (\n <Box position=\"relative\" width=\"100%\">\n <CodeBlock {...props.attributes}>\n <code>{props.children}</code>\n </CodeBlock>\n {shouldDisplayLanguageSelect && (\n <Box\n position=\"absolute\"\n background=\"neutral0\"\n borderColor=\"neutral150\"\n borderStyle=\"solid\"\n borderWidth=\"0.5px\"\n shadow=\"tableShadow\"\n top=\"100%\"\n marginTop={1}\n right={0}\n padding={1}\n hasRadius\n >\n <SingleSelect\n onChange={(open) => {\n Transforms.setNodes(\n editor,\n { language: open.toString() },\n { match: (node) => !Editor.isEditor(node) && node.type === 'code' }\n );\n }}\n value={(props.element.type === 'code' && props.element.language) || 'plaintext'}\n onOpenChange={(open) => {\n setIsSelectOpen(open);\n\n // Focus the editor again when closing the select so the user can continue typing\n if (!open) {\n ReactEditor.focus(editor);\n }\n }}\n onCloseAutoFocus={(e) => e.preventDefault()}\n aria-label={formatMessage({\n id: 'components.Blocks.blocks.code.languageLabel',\n defaultMessage: 'Select a language',\n })}\n >\n {codeLanguages.map(({ value, label }) => (\n <SingleSelectOption value={value} key={value}>\n {label}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n </Box>\n )}\n </Box>\n );\n};\n\nconst withCode = (editor: Editor) => {\n const { insertData } = editor;\n\n editor.insertData = (data) => {\n const pastedText = data.getData('text/plain');\n\n if (pastedText && editor.selection) {\n // Check if we're currently inside a code block\n const codeBlockEntry = Editor.above(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'code',\n });\n\n if (codeBlockEntry) {\n // We're inside a code block, handle the paste specially\n // Replace the selected content with the pasted text, preserving newlines\n Transforms.insertText(editor, pastedText);\n return;\n }\n }\n\n // For non-code blocks, use the default behavior\n insertData(data);\n };\n\n return editor;\n};\n\nconst codeBlocks: Pick<BlocksStore, 'code'> = {\n code: {\n renderElement: (props) => <CodeEditor {...props} />,\n icon: CodeBlockIcon,\n label: {\n id: 'components.Blocks.blocks.code',\n defaultMessage: 'Code block',\n },\n matchNode: (node) => node.type === 'code',\n isInBlocksSelector: true,\n handleConvert(editor) {\n baseHandleConvert<Block<'code'>>(editor, { type: 'code', language: 'plaintext' });\n },\n handleEnterKey(editor) {\n pressEnterTwiceToExit(editor);\n },\n snippets: ['```'],\n plugin: withCode,\n },\n};\n\nexport { codeBlocks };\n"],"names":["decorateCode","node","path","ranges","Element","isElement","type","text","Node","string","language","codeLanguages","find","lang","value","decorateKey","decorate","selectedLanguage","Prism","languages","tokens","tokenize","start","token","length","end","push","anchor","offset","focus","className","CodeBlock","styled","pre","theme","borderRadius","colors","neutral100","spaces","neutral800","CodeEditor","props","editor","useBlocksEditorContext","editorIsFocused","useFocused","imageIsSelected","useSelected","formatMessage","useIntl","isSelectOpen","setIsSelectOpen","React","useState","shouldDisplayLanguageSelect","_jsxs","Box","position","width","_jsx","attributes","code","children","background","borderColor","borderStyle","borderWidth","shadow","top","marginTop","right","padding","hasRadius","SingleSelect","onChange","open","Transforms","setNodes","toString","match","Editor","isEditor","element","onOpenChange","ReactEditor","onCloseAutoFocus","e","preventDefault","aria-label","id","defaultMessage","map","label","SingleSelectOption","withCode","insertData","data","pastedText","getData","selection","codeBlockEntry","above","insertText","codeBlocks","renderElement","icon","CodeBlockIcon","matchNode","isInBlocksSelector","handleConvert","baseHandleConvert","handleEnterKey","pressEnterTwiceToExit","snippets","plugin"],"mappings":"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"}
@@ -170,6 +170,27 @@ const CodeEditor = (props)=>{
170
170
  ]
171
171
  });
172
172
  };
173
+ const withCode = (editor)=>{
174
+ const { insertData } = editor;
175
+ editor.insertData = (data)=>{
176
+ const pastedText = data.getData('text/plain');
177
+ if (pastedText && editor.selection) {
178
+ // Check if we're currently inside a code block
179
+ const codeBlockEntry = Editor.above(editor, {
180
+ match: (node)=>!Editor.isEditor(node) && node.type === 'code'
181
+ });
182
+ if (codeBlockEntry) {
183
+ // We're inside a code block, handle the paste specially
184
+ // Replace the selected content with the pasted text, preserving newlines
185
+ Transforms.insertText(editor, pastedText);
186
+ return;
187
+ }
188
+ }
189
+ // For non-code blocks, use the default behavior
190
+ insertData(data);
191
+ };
192
+ return editor;
193
+ };
173
194
  const codeBlocks = {
174
195
  code: {
175
196
  renderElement: (props)=>/*#__PURE__*/ jsx(CodeEditor, {
@@ -193,7 +214,8 @@ const codeBlocks = {
193
214
  },
194
215
  snippets: [
195
216
  '```'
196
- ]
217
+ ],
218
+ plugin: withCode
197
219
  }
198
220
  };
199
221
 
@@ -1 +1 @@
1
- {"version":3,"file":"Code.mjs","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, SingleSelect, SingleSelectOption } from '@strapi/design-system';\nimport { CodeBlock as CodeBlockIcon } from '@strapi/icons';\nimport * as Prism from 'prismjs';\nimport { useIntl } from 'react-intl';\nimport { BaseRange, Element, Editor, Node, NodeEntry, Transforms } from 'slate';\nimport { useSelected, type RenderElementProps, useFocused, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\n\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { codeLanguages } from '../utils/constants';\nimport { baseHandleConvert } from '../utils/conversions';\nimport { pressEnterTwiceToExit } from '../utils/enterKey';\nimport { type Block } from '../utils/types';\n\nimport 'prismjs/themes/prism-solarizedlight.css';\nimport 'prismjs/components/prism-asmatmel';\nimport 'prismjs/components/prism-bash';\nimport 'prismjs/components/prism-basic';\nimport 'prismjs/components/prism-c';\nimport 'prismjs/components/prism-clojure';\nimport 'prismjs/components/prism-cobol';\nimport 'prismjs/components/prism-cpp';\nimport 'prismjs/components/prism-csharp';\nimport 'prismjs/components/prism-dart';\nimport 'prismjs/components/prism-docker';\nimport 'prismjs/components/prism-elixir';\nimport 'prismjs/components/prism-erlang';\nimport 'prismjs/components/prism-fortran';\nimport 'prismjs/components/prism-fsharp';\nimport 'prismjs/components/prism-go';\nimport 'prismjs/components/prism-graphql';\nimport 'prismjs/components/prism-groovy';\nimport 'prismjs/components/prism-haskell';\nimport 'prismjs/components/prism-haxe';\nimport 'prismjs/components/prism-ini';\nimport 'prismjs/components/prism-java';\nimport 'prismjs/components/prism-javascript';\nimport 'prismjs/components/prism-jsx';\nimport 'prismjs/components/prism-json';\nimport 'prismjs/components/prism-julia';\nimport 'prismjs/components/prism-kotlin';\nimport 'prismjs/components/prism-latex';\nimport 'prismjs/components/prism-lua';\nimport 'prismjs/components/prism-markdown';\nimport 'prismjs/components/prism-matlab';\nimport 'prismjs/components/prism-makefile';\nimport 'prismjs/components/prism-objectivec';\nimport 'prismjs/components/prism-perl';\nimport 'prismjs/components/prism-php';\nimport 'prismjs/components/prism-powershell';\nimport 'prismjs/components/prism-python';\nimport 'prismjs/components/prism-r';\nimport 'prismjs/components/prism-ruby';\nimport 'prismjs/components/prism-rust';\nimport 'prismjs/components/prism-sas';\nimport 'prismjs/components/prism-scala';\nimport 'prismjs/components/prism-scheme';\nimport 'prismjs/components/prism-sql';\nimport 'prismjs/components/prism-stata';\nimport 'prismjs/components/prism-swift';\nimport 'prismjs/components/prism-typescript';\nimport 'prismjs/components/prism-tsx';\nimport 'prismjs/components/prism-vbnet';\nimport 'prismjs/components/prism-yaml';\n\ntype BaseRangeCustom = BaseRange & { className: string };\n\nexport const decorateCode = ([node, path]: NodeEntry) => {\n const ranges: BaseRangeCustom[] = [];\n\n // make sure it is an Slate Element\n if (!Element.isElement(node) || node.type !== 'code') return ranges;\n // transform the Element into a string\n const text = Node.string(node);\n const language = codeLanguages.find((lang) => lang.value === node.language);\n const decorateKey = language?.decorate ?? language?.value;\n\n const selectedLanguage = Prism.languages[decorateKey || 'plaintext'];\n\n // create \"tokens\" with \"prismjs\" and put them in \"ranges\"\n const tokens = Prism.tokenize(text, selectedLanguage);\n let start = 0;\n for (const token of tokens) {\n const length = token.length;\n const end = start + length;\n if (typeof token !== 'string') {\n ranges.push({\n anchor: { path, offset: start },\n focus: { path, offset: end },\n className: `token ${token.type}`,\n });\n }\n start = end;\n }\n\n // these will be found in \"renderLeaf\" in \"leaf\" and their \"className\" will be applied\n return ranges;\n};\n\nconst CodeBlock = styled.pre`\n border-radius: ${({ theme }) => theme.borderRadius};\n background-color: ${({ theme }) => theme.colors.neutral100};\n max-width: 100%;\n overflow: auto;\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[4]}`};\n flex-shrink: 1;\n\n & > code {\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n color: ${({ theme }) => theme.colors.neutral800};\n overflow: auto;\n max-width: 100%;\n }\n`;\n\nconst CodeEditor = (props: RenderElementProps) => {\n const { editor } = useBlocksEditorContext('ImageDialog');\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n const { formatMessage } = useIntl();\n const [isSelectOpen, setIsSelectOpen] = React.useState(false);\n const shouldDisplayLanguageSelect = (editorIsFocused && imageIsSelected) || isSelectOpen;\n\n return (\n <Box position=\"relative\" width=\"100%\">\n <CodeBlock {...props.attributes}>\n <code>{props.children}</code>\n </CodeBlock>\n {shouldDisplayLanguageSelect && (\n <Box\n position=\"absolute\"\n background=\"neutral0\"\n borderColor=\"neutral150\"\n borderStyle=\"solid\"\n borderWidth=\"0.5px\"\n shadow=\"tableShadow\"\n top=\"100%\"\n marginTop={1}\n right={0}\n padding={1}\n hasRadius\n >\n <SingleSelect\n onChange={(open) => {\n Transforms.setNodes(\n editor,\n { language: open.toString() },\n { match: (node) => !Editor.isEditor(node) && node.type === 'code' }\n );\n }}\n value={(props.element.type === 'code' && props.element.language) || 'plaintext'}\n onOpenChange={(open) => {\n setIsSelectOpen(open);\n\n // Focus the editor again when closing the select so the user can continue typing\n if (!open) {\n ReactEditor.focus(editor);\n }\n }}\n onCloseAutoFocus={(e) => e.preventDefault()}\n aria-label={formatMessage({\n id: 'components.Blocks.blocks.code.languageLabel',\n defaultMessage: 'Select a language',\n })}\n >\n {codeLanguages.map(({ value, label }) => (\n <SingleSelectOption value={value} key={value}>\n {label}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n </Box>\n )}\n </Box>\n );\n};\n\nconst codeBlocks: Pick<BlocksStore, 'code'> = {\n code: {\n renderElement: (props) => <CodeEditor {...props} />,\n icon: CodeBlockIcon,\n label: {\n id: 'components.Blocks.blocks.code',\n defaultMessage: 'Code block',\n },\n matchNode: (node) => node.type === 'code',\n isInBlocksSelector: true,\n handleConvert(editor) {\n baseHandleConvert<Block<'code'>>(editor, { type: 'code', language: 'plaintext' });\n },\n handleEnterKey(editor) {\n pressEnterTwiceToExit(editor);\n },\n snippets: ['```'],\n },\n};\n\nexport { codeBlocks };\n"],"names":["decorateCode","node","path","ranges","Element","isElement","type","text","Node","string","language","codeLanguages","find","lang","value","decorateKey","decorate","selectedLanguage","Prism","languages","tokens","tokenize","start","token","length","end","push","anchor","offset","focus","className","CodeBlock","styled","pre","theme","borderRadius","colors","neutral100","spaces","neutral800","CodeEditor","props","editor","useBlocksEditorContext","editorIsFocused","useFocused","imageIsSelected","useSelected","formatMessage","useIntl","isSelectOpen","setIsSelectOpen","React","useState","shouldDisplayLanguageSelect","_jsxs","Box","position","width","_jsx","attributes","code","children","background","borderColor","borderStyle","borderWidth","shadow","top","marginTop","right","padding","hasRadius","SingleSelect","onChange","open","Transforms","setNodes","toString","match","Editor","isEditor","element","onOpenChange","ReactEditor","onCloseAutoFocus","e","preventDefault","aria-label","id","defaultMessage","map","label","SingleSelectOption","codeBlocks","renderElement","icon","CodeBlockIcon","matchNode","isInBlocksSelector","handleConvert","baseHandleConvert","handleEnterKey","pressEnterTwiceToExit","snippets"],"mappings":"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"}
1
+ {"version":3,"file":"Code.mjs","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, SingleSelect, SingleSelectOption } from '@strapi/design-system';\nimport { CodeBlock as CodeBlockIcon } from '@strapi/icons';\nimport * as Prism from 'prismjs';\nimport { useIntl } from 'react-intl';\nimport { BaseRange, Element, Editor, Node, NodeEntry, Transforms } from 'slate';\nimport { useSelected, type RenderElementProps, useFocused, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\n\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { codeLanguages } from '../utils/constants';\nimport { baseHandleConvert } from '../utils/conversions';\nimport { pressEnterTwiceToExit } from '../utils/enterKey';\nimport { type Block } from '../utils/types';\n\nimport 'prismjs/themes/prism-solarizedlight.css';\nimport 'prismjs/components/prism-asmatmel';\nimport 'prismjs/components/prism-bash';\nimport 'prismjs/components/prism-basic';\nimport 'prismjs/components/prism-c';\nimport 'prismjs/components/prism-clojure';\nimport 'prismjs/components/prism-cobol';\nimport 'prismjs/components/prism-cpp';\nimport 'prismjs/components/prism-csharp';\nimport 'prismjs/components/prism-dart';\nimport 'prismjs/components/prism-docker';\nimport 'prismjs/components/prism-elixir';\nimport 'prismjs/components/prism-erlang';\nimport 'prismjs/components/prism-fortran';\nimport 'prismjs/components/prism-fsharp';\nimport 'prismjs/components/prism-go';\nimport 'prismjs/components/prism-graphql';\nimport 'prismjs/components/prism-groovy';\nimport 'prismjs/components/prism-haskell';\nimport 'prismjs/components/prism-haxe';\nimport 'prismjs/components/prism-ini';\nimport 'prismjs/components/prism-java';\nimport 'prismjs/components/prism-javascript';\nimport 'prismjs/components/prism-jsx';\nimport 'prismjs/components/prism-json';\nimport 'prismjs/components/prism-julia';\nimport 'prismjs/components/prism-kotlin';\nimport 'prismjs/components/prism-latex';\nimport 'prismjs/components/prism-lua';\nimport 'prismjs/components/prism-markdown';\nimport 'prismjs/components/prism-matlab';\nimport 'prismjs/components/prism-makefile';\nimport 'prismjs/components/prism-objectivec';\nimport 'prismjs/components/prism-perl';\nimport 'prismjs/components/prism-php';\nimport 'prismjs/components/prism-powershell';\nimport 'prismjs/components/prism-python';\nimport 'prismjs/components/prism-r';\nimport 'prismjs/components/prism-ruby';\nimport 'prismjs/components/prism-rust';\nimport 'prismjs/components/prism-sas';\nimport 'prismjs/components/prism-scala';\nimport 'prismjs/components/prism-scheme';\nimport 'prismjs/components/prism-sql';\nimport 'prismjs/components/prism-stata';\nimport 'prismjs/components/prism-swift';\nimport 'prismjs/components/prism-typescript';\nimport 'prismjs/components/prism-tsx';\nimport 'prismjs/components/prism-vbnet';\nimport 'prismjs/components/prism-yaml';\n\ntype BaseRangeCustom = BaseRange & { className: string };\n\nexport const decorateCode = ([node, path]: NodeEntry) => {\n const ranges: BaseRangeCustom[] = [];\n\n // make sure it is an Slate Element\n if (!Element.isElement(node) || node.type !== 'code') return ranges;\n // transform the Element into a string\n const text = Node.string(node);\n const language = codeLanguages.find((lang) => lang.value === node.language);\n const decorateKey = language?.decorate ?? language?.value;\n\n const selectedLanguage = Prism.languages[decorateKey || 'plaintext'];\n\n // create \"tokens\" with \"prismjs\" and put them in \"ranges\"\n const tokens = Prism.tokenize(text, selectedLanguage);\n let start = 0;\n for (const token of tokens) {\n const length = token.length;\n const end = start + length;\n if (typeof token !== 'string') {\n ranges.push({\n anchor: { path, offset: start },\n focus: { path, offset: end },\n className: `token ${token.type}`,\n });\n }\n start = end;\n }\n\n // these will be found in \"renderLeaf\" in \"leaf\" and their \"className\" will be applied\n return ranges;\n};\n\nconst CodeBlock = styled.pre`\n border-radius: ${({ theme }) => theme.borderRadius};\n background-color: ${({ theme }) => theme.colors.neutral100};\n max-width: 100%;\n overflow: auto;\n padding: ${({ theme }) => `${theme.spaces[3]} ${theme.spaces[4]}`};\n flex-shrink: 1;\n\n & > code {\n font-family: 'SF Mono', SFMono-Regular, ui-monospace, 'DejaVu Sans Mono', Menlo, Consolas,\n monospace;\n color: ${({ theme }) => theme.colors.neutral800};\n overflow: auto;\n max-width: 100%;\n }\n`;\n\nconst CodeEditor = (props: RenderElementProps) => {\n const { editor } = useBlocksEditorContext('ImageDialog');\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n const { formatMessage } = useIntl();\n const [isSelectOpen, setIsSelectOpen] = React.useState(false);\n const shouldDisplayLanguageSelect = (editorIsFocused && imageIsSelected) || isSelectOpen;\n\n return (\n <Box position=\"relative\" width=\"100%\">\n <CodeBlock {...props.attributes}>\n <code>{props.children}</code>\n </CodeBlock>\n {shouldDisplayLanguageSelect && (\n <Box\n position=\"absolute\"\n background=\"neutral0\"\n borderColor=\"neutral150\"\n borderStyle=\"solid\"\n borderWidth=\"0.5px\"\n shadow=\"tableShadow\"\n top=\"100%\"\n marginTop={1}\n right={0}\n padding={1}\n hasRadius\n >\n <SingleSelect\n onChange={(open) => {\n Transforms.setNodes(\n editor,\n { language: open.toString() },\n { match: (node) => !Editor.isEditor(node) && node.type === 'code' }\n );\n }}\n value={(props.element.type === 'code' && props.element.language) || 'plaintext'}\n onOpenChange={(open) => {\n setIsSelectOpen(open);\n\n // Focus the editor again when closing the select so the user can continue typing\n if (!open) {\n ReactEditor.focus(editor);\n }\n }}\n onCloseAutoFocus={(e) => e.preventDefault()}\n aria-label={formatMessage({\n id: 'components.Blocks.blocks.code.languageLabel',\n defaultMessage: 'Select a language',\n })}\n >\n {codeLanguages.map(({ value, label }) => (\n <SingleSelectOption value={value} key={value}>\n {label}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n </Box>\n )}\n </Box>\n );\n};\n\nconst withCode = (editor: Editor) => {\n const { insertData } = editor;\n\n editor.insertData = (data) => {\n const pastedText = data.getData('text/plain');\n\n if (pastedText && editor.selection) {\n // Check if we're currently inside a code block\n const codeBlockEntry = Editor.above(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'code',\n });\n\n if (codeBlockEntry) {\n // We're inside a code block, handle the paste specially\n // Replace the selected content with the pasted text, preserving newlines\n Transforms.insertText(editor, pastedText);\n return;\n }\n }\n\n // For non-code blocks, use the default behavior\n insertData(data);\n };\n\n return editor;\n};\n\nconst codeBlocks: Pick<BlocksStore, 'code'> = {\n code: {\n renderElement: (props) => <CodeEditor {...props} />,\n icon: CodeBlockIcon,\n label: {\n id: 'components.Blocks.blocks.code',\n defaultMessage: 'Code block',\n },\n matchNode: (node) => node.type === 'code',\n isInBlocksSelector: true,\n handleConvert(editor) {\n baseHandleConvert<Block<'code'>>(editor, { type: 'code', language: 'plaintext' });\n },\n handleEnterKey(editor) {\n pressEnterTwiceToExit(editor);\n },\n snippets: ['```'],\n plugin: withCode,\n },\n};\n\nexport { codeBlocks };\n"],"names":["decorateCode","node","path","ranges","Element","isElement","type","text","Node","string","language","codeLanguages","find","lang","value","decorateKey","decorate","selectedLanguage","Prism","languages","tokens","tokenize","start","token","length","end","push","anchor","offset","focus","className","CodeBlock","styled","pre","theme","borderRadius","colors","neutral100","spaces","neutral800","CodeEditor","props","editor","useBlocksEditorContext","editorIsFocused","useFocused","imageIsSelected","useSelected","formatMessage","useIntl","isSelectOpen","setIsSelectOpen","React","useState","shouldDisplayLanguageSelect","_jsxs","Box","position","width","_jsx","attributes","code","children","background","borderColor","borderStyle","borderWidth","shadow","top","marginTop","right","padding","hasRadius","SingleSelect","onChange","open","Transforms","setNodes","toString","match","Editor","isEditor","element","onOpenChange","ReactEditor","onCloseAutoFocus","e","preventDefault","aria-label","id","defaultMessage","map","label","SingleSelectOption","withCode","insertData","data","pastedText","getData","selection","codeBlockEntry","above","insertText","codeBlocks","renderElement","icon","CodeBlockIcon","matchNode","isInBlocksSelector","handleConvert","baseHandleConvert","handleEnterKey","pressEnterTwiceToExit","snippets","plugin"],"mappings":"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"}
@@ -172,6 +172,18 @@ const ImageDialog = ()=>{
172
172
  onSelectAssets: handleSelectAssets
173
173
  });
174
174
  };
175
+ /**
176
+ * Images are void elements. They handle the rendering of their children instead of Slate.
177
+ * See the Slate documentation for more information:
178
+ * - https://docs.slatejs.org/api/nodes/element#void-vs-not-void
179
+ * - https://docs.slatejs.org/api/nodes/element#rendering-void-elements
180
+ */ const withImages = (editor)=>{
181
+ const { isVoid } = editor;
182
+ editor.isVoid = (element)=>{
183
+ return element.type === 'image' ? true : isVoid(element);
184
+ };
185
+ return editor;
186
+ };
175
187
  const imageBlocks = {
176
188
  image: {
177
189
  renderElement: (props)=>/*#__PURE__*/ jsxRuntime.jsx(Image, {
@@ -222,7 +234,8 @@ const imageBlocks = {
222
234
  },
223
235
  snippets: [
224
236
  '!['
225
- ]
237
+ ],
238
+ plugin: withImages
226
239
  }
227
240
  };
228
241
 
@@ -1 +1 @@
1
- {"version":3,"file":"Image.js","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useStrapiApp } from '@strapi/admin/strapi-admin';\nimport { Box, Flex, FlexComponent } from '@strapi/design-system';\nimport { Image as Picture } from '@strapi/icons';\nimport { type Element, Transforms, Editor } from 'slate';\nimport { useFocused, type RenderElementProps, useSelected } from 'slate-react';\nimport { styled, css } from 'styled-components';\n\nimport { prefixFileUrlWithBackendUrl } from '../../../../../../utils/urls';\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { type Block } from '../utils/types';\n\nimport type { Schema } from '@strapi/types';\n\nconst ImageWrapper = styled<FlexComponent>(Flex)<{ $isFocused?: boolean }>`\n transition-property: box-shadow;\n transition-duration: 0.2s;\n ${(props) =>\n props.$isFocused &&\n css`\n box-shadow: ${props.theme.colors.primary600} 0px 0px 0px 3px;\n `}\n\n & > img {\n height: auto;\n // The max-height is decided with the design team, the 56px is the height of the toolbar\n max-height: calc(512px - 56px);\n max-width: 100%;\n object-fit: contain;\n }\n`;\n\nconst IMAGE_SCHEMA_FIELDS = [\n 'name',\n 'alternativeText',\n 'url',\n 'caption',\n 'width',\n 'height',\n 'formats',\n 'hash',\n 'ext',\n 'mime',\n 'size',\n 'previewUrl',\n 'provider',\n 'provider_metadata',\n 'createdAt',\n 'updatedAt',\n];\n\nconst pick = <T extends object, K extends keyof T>(object: T, keys: K[]): Pick<T, K> => {\n const entries = keys.map((key) => [key, object[key]]);\n return Object.fromEntries(entries);\n};\n\n// Type guard to force TypeScript to narrow the type of the element in Blocks component\nconst isImage = (element: Element): element is Block<'image'> => {\n return element.type === 'image';\n};\n\n// Added a background color to the image wrapper to make it easier to recognize the image block\nconst Image = ({ attributes, children, element }: RenderElementProps) => {\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n\n if (!isImage(element)) {\n return null;\n }\n const { url, alternativeText, width, height } = element.image;\n\n return (\n <Box {...attributes}>\n {children}\n <ImageWrapper\n background=\"neutral100\"\n contentEditable={false}\n justifyContent=\"center\"\n $isFocused={editorIsFocused && imageIsSelected}\n hasRadius\n >\n <img src={url} alt={alternativeText} width={width} height={height} />\n </ImageWrapper>\n </Box>\n );\n};\n\nconst ImageDialog = () => {\n const [isOpen, setIsOpen] = React.useState(true);\n const { editor } = useBlocksEditorContext('ImageDialog');\n const components = useStrapiApp('ImageDialog', (state) => state.components);\n\n if (!components || !isOpen) return null;\n\n const MediaLibraryDialog = components['media-library'] as React.ComponentType<{\n allowedTypes: Schema.Attribute.MediaKind[];\n onClose: () => void;\n onSelectAssets: (_images: Schema.Attribute.MediaValue<true>) => void;\n }>;\n\n const insertImages = (images: Block<'image'>['image'][]) => {\n // If the selection is inside a list, split the list so that the modified block is outside of it\n Transforms.unwrapNodes(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'list',\n split: true,\n });\n\n // Save the path of the node that is being replaced by an image to insert the images there later\n // It's the closest full block node above the selection\n const nodeEntryBeingReplaced = Editor.above(editor, {\n match(node) {\n if (Editor.isEditor(node)) return false;\n\n const isInlineNode = ['text', 'link'].includes(node.type);\n\n return !isInlineNode;\n },\n });\n\n if (!nodeEntryBeingReplaced) return;\n const [, pathToInsert] = nodeEntryBeingReplaced;\n\n // Remove the previous node that is being replaced by an image\n Transforms.removeNodes(editor);\n\n // Convert images to nodes and insert them\n const nodesToInsert = images.map((image) => {\n const imageNode: Block<'image'> = {\n type: 'image',\n image,\n children: [{ type: 'text', text: '' }],\n };\n return imageNode;\n });\n Transforms.insertNodes(editor, nodesToInsert, { at: pathToInsert });\n\n // Set the selection on the image since it was cleared by calling removeNodes\n Transforms.select(editor, pathToInsert);\n };\n\n const handleSelectAssets = (images: Schema.Attribute.MediaValue<true>) => {\n const formattedImages = images.map((image) => {\n // Create an object with imageSchema defined and exclude unnecessary props coming from media library config\n const expectedImage = pick(image, IMAGE_SCHEMA_FIELDS);\n\n const nodeImage: Block<'image'>['image'] = {\n ...expectedImage,\n alternativeText: expectedImage.alternativeText || expectedImage.name,\n url: prefixFileUrlWithBackendUrl(image.url),\n };\n\n return nodeImage;\n });\n\n insertImages(formattedImages);\n setIsOpen(false);\n };\n\n return (\n <MediaLibraryDialog\n allowedTypes={['images']}\n onClose={() => setIsOpen(false)}\n onSelectAssets={handleSelectAssets}\n />\n );\n};\n\nconst imageBlocks: Pick<BlocksStore, 'image'> = {\n image: {\n renderElement: (props) => <Image {...props} />,\n icon: Picture,\n label: {\n id: 'components.Blocks.blocks.image',\n defaultMessage: 'Image',\n },\n matchNode: (node) => node.type === 'image',\n isInBlocksSelector: true,\n handleBackspaceKey(editor) {\n // Prevent issue where the image remains when it's the only block in the document\n if (editor.children.length === 1) {\n Transforms.setNodes(editor, {\n type: 'paragraph',\n // @ts-expect-error we're only setting image as null so that Slate deletes it\n image: null,\n children: [{ type: 'text', text: '' }],\n });\n } else {\n Transforms.removeNodes(editor);\n }\n },\n handleEnterKey(editor) {\n Transforms.insertNodes(editor, {\n type: 'paragraph',\n children: [{ type: 'text', text: '' }],\n });\n },\n handleConvert: () => {\n /**\n * All the logic is managed inside the ImageDialog component,\n * because the blocks are only created when the user selects images in the modal and submits\n * and if he closes the modal, then no changes are made to the editor\n */\n return () => <ImageDialog />;\n },\n snippets: ['!['],\n },\n};\n\nexport { imageBlocks };\n"],"names":["ImageWrapper","styled","Flex","props","$isFocused","css","theme","colors","primary600","IMAGE_SCHEMA_FIELDS","pick","object","keys","entries","map","key","Object","fromEntries","isImage","element","type","Image","attributes","children","editorIsFocused","useFocused","imageIsSelected","useSelected","url","alternativeText","width","height","image","_jsxs","Box","_jsx","background","contentEditable","justifyContent","hasRadius","img","src","alt","ImageDialog","isOpen","setIsOpen","React","useState","editor","useBlocksEditorContext","components","useStrapiApp","state","MediaLibraryDialog","insertImages","images","Transforms","unwrapNodes","match","node","Editor","isEditor","split","nodeEntryBeingReplaced","above","isInlineNode","includes","pathToInsert","removeNodes","nodesToInsert","imageNode","text","insertNodes","at","select","handleSelectAssets","formattedImages","expectedImage","nodeImage","name","prefixFileUrlWithBackendUrl","allowedTypes","onClose","onSelectAssets","imageBlocks","renderElement","icon","Picture","label","id","defaultMessage","matchNode","isInBlocksSelector","handleBackspaceKey","length","setNodes","handleEnterKey","handleConvert","snippets"],"mappings":"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"}
1
+ {"version":3,"file":"Image.js","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useStrapiApp } from '@strapi/admin/strapi-admin';\nimport { Box, Flex, FlexComponent } from '@strapi/design-system';\nimport { Image as Picture } from '@strapi/icons';\nimport { type Element, Transforms, Editor } from 'slate';\nimport { useFocused, type RenderElementProps, useSelected } from 'slate-react';\nimport { styled, css } from 'styled-components';\n\nimport { prefixFileUrlWithBackendUrl } from '../../../../../../utils/urls';\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { type Block } from '../utils/types';\n\nimport type { Schema } from '@strapi/types';\n\nconst ImageWrapper = styled<FlexComponent>(Flex)<{ $isFocused?: boolean }>`\n transition-property: box-shadow;\n transition-duration: 0.2s;\n ${(props) =>\n props.$isFocused &&\n css`\n box-shadow: ${props.theme.colors.primary600} 0px 0px 0px 3px;\n `}\n\n & > img {\n height: auto;\n // The max-height is decided with the design team, the 56px is the height of the toolbar\n max-height: calc(512px - 56px);\n max-width: 100%;\n object-fit: contain;\n }\n`;\n\nconst IMAGE_SCHEMA_FIELDS = [\n 'name',\n 'alternativeText',\n 'url',\n 'caption',\n 'width',\n 'height',\n 'formats',\n 'hash',\n 'ext',\n 'mime',\n 'size',\n 'previewUrl',\n 'provider',\n 'provider_metadata',\n 'createdAt',\n 'updatedAt',\n];\n\nconst pick = <T extends object, K extends keyof T>(object: T, keys: K[]): Pick<T, K> => {\n const entries = keys.map((key) => [key, object[key]]);\n return Object.fromEntries(entries);\n};\n\n// Type guard to force TypeScript to narrow the type of the element in Blocks component\nconst isImage = (element: Element): element is Block<'image'> => {\n return element.type === 'image';\n};\n\n// Added a background color to the image wrapper to make it easier to recognize the image block\nconst Image = ({ attributes, children, element }: RenderElementProps) => {\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n\n if (!isImage(element)) {\n return null;\n }\n const { url, alternativeText, width, height } = element.image;\n\n return (\n <Box {...attributes}>\n {children}\n <ImageWrapper\n background=\"neutral100\"\n contentEditable={false}\n justifyContent=\"center\"\n $isFocused={editorIsFocused && imageIsSelected}\n hasRadius\n >\n <img src={url} alt={alternativeText} width={width} height={height} />\n </ImageWrapper>\n </Box>\n );\n};\n\nconst ImageDialog = () => {\n const [isOpen, setIsOpen] = React.useState(true);\n const { editor } = useBlocksEditorContext('ImageDialog');\n const components = useStrapiApp('ImageDialog', (state) => state.components);\n\n if (!components || !isOpen) return null;\n\n const MediaLibraryDialog = components['media-library'] as React.ComponentType<{\n allowedTypes: Schema.Attribute.MediaKind[];\n onClose: () => void;\n onSelectAssets: (_images: Schema.Attribute.MediaValue<true>) => void;\n }>;\n\n const insertImages = (images: Block<'image'>['image'][]) => {\n // If the selection is inside a list, split the list so that the modified block is outside of it\n Transforms.unwrapNodes(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'list',\n split: true,\n });\n\n // Save the path of the node that is being replaced by an image to insert the images there later\n // It's the closest full block node above the selection\n const nodeEntryBeingReplaced = Editor.above(editor, {\n match(node) {\n if (Editor.isEditor(node)) return false;\n\n const isInlineNode = ['text', 'link'].includes(node.type);\n\n return !isInlineNode;\n },\n });\n\n if (!nodeEntryBeingReplaced) return;\n const [, pathToInsert] = nodeEntryBeingReplaced;\n\n // Remove the previous node that is being replaced by an image\n Transforms.removeNodes(editor);\n\n // Convert images to nodes and insert them\n const nodesToInsert = images.map((image) => {\n const imageNode: Block<'image'> = {\n type: 'image',\n image,\n children: [{ type: 'text', text: '' }],\n };\n return imageNode;\n });\n Transforms.insertNodes(editor, nodesToInsert, { at: pathToInsert });\n\n // Set the selection on the image since it was cleared by calling removeNodes\n Transforms.select(editor, pathToInsert);\n };\n\n const handleSelectAssets = (images: Schema.Attribute.MediaValue<true>) => {\n const formattedImages = images.map((image) => {\n // Create an object with imageSchema defined and exclude unnecessary props coming from media library config\n const expectedImage = pick(image, IMAGE_SCHEMA_FIELDS);\n\n const nodeImage: Block<'image'>['image'] = {\n ...expectedImage,\n alternativeText: expectedImage.alternativeText || expectedImage.name,\n url: prefixFileUrlWithBackendUrl(image.url),\n };\n\n return nodeImage;\n });\n\n insertImages(formattedImages);\n setIsOpen(false);\n };\n\n return (\n <MediaLibraryDialog\n allowedTypes={['images']}\n onClose={() => setIsOpen(false)}\n onSelectAssets={handleSelectAssets}\n />\n );\n};\n\n/**\n * Images are void elements. They handle the rendering of their children instead of Slate.\n * See the Slate documentation for more information:\n * - https://docs.slatejs.org/api/nodes/element#void-vs-not-void\n * - https://docs.slatejs.org/api/nodes/element#rendering-void-elements\n */\nconst withImages = (editor: Editor) => {\n const { isVoid } = editor;\n\n editor.isVoid = (element) => {\n return element.type === 'image' ? true : isVoid(element);\n };\n\n return editor;\n};\n\nconst imageBlocks: Pick<BlocksStore, 'image'> = {\n image: {\n renderElement: (props) => <Image {...props} />,\n icon: Picture,\n label: {\n id: 'components.Blocks.blocks.image',\n defaultMessage: 'Image',\n },\n matchNode: (node) => node.type === 'image',\n isInBlocksSelector: true,\n handleBackspaceKey(editor) {\n // Prevent issue where the image remains when it's the only block in the document\n if (editor.children.length === 1) {\n Transforms.setNodes(editor, {\n type: 'paragraph',\n // @ts-expect-error we're only setting image as null so that Slate deletes it\n image: null,\n children: [{ type: 'text', text: '' }],\n });\n } else {\n Transforms.removeNodes(editor);\n }\n },\n handleEnterKey(editor) {\n Transforms.insertNodes(editor, {\n type: 'paragraph',\n children: [{ type: 'text', text: '' }],\n });\n },\n handleConvert: () => {\n /**\n * All the logic is managed inside the ImageDialog component,\n * because the blocks are only created when the user selects images in the modal and submits\n * and if he closes the modal, then no changes are made to the editor\n */\n return () => <ImageDialog />;\n },\n snippets: ['!['],\n plugin: withImages,\n },\n};\n\nexport { imageBlocks };\n"],"names":["ImageWrapper","styled","Flex","props","$isFocused","css","theme","colors","primary600","IMAGE_SCHEMA_FIELDS","pick","object","keys","entries","map","key","Object","fromEntries","isImage","element","type","Image","attributes","children","editorIsFocused","useFocused","imageIsSelected","useSelected","url","alternativeText","width","height","image","_jsxs","Box","_jsx","background","contentEditable","justifyContent","hasRadius","img","src","alt","ImageDialog","isOpen","setIsOpen","React","useState","editor","useBlocksEditorContext","components","useStrapiApp","state","MediaLibraryDialog","insertImages","images","Transforms","unwrapNodes","match","node","Editor","isEditor","split","nodeEntryBeingReplaced","above","isInlineNode","includes","pathToInsert","removeNodes","nodesToInsert","imageNode","text","insertNodes","at","select","handleSelectAssets","formattedImages","expectedImage","nodeImage","name","prefixFileUrlWithBackendUrl","allowedTypes","onClose","onSelectAssets","withImages","isVoid","imageBlocks","renderElement","icon","Picture","label","id","defaultMessage","matchNode","isInBlocksSelector","handleBackspaceKey","length","setNodes","handleEnterKey","handleConvert","snippets","plugin"],"mappings":"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"}
@@ -151,6 +151,18 @@ const ImageDialog = ()=>{
151
151
  onSelectAssets: handleSelectAssets
152
152
  });
153
153
  };
154
+ /**
155
+ * Images are void elements. They handle the rendering of their children instead of Slate.
156
+ * See the Slate documentation for more information:
157
+ * - https://docs.slatejs.org/api/nodes/element#void-vs-not-void
158
+ * - https://docs.slatejs.org/api/nodes/element#rendering-void-elements
159
+ */ const withImages = (editor)=>{
160
+ const { isVoid } = editor;
161
+ editor.isVoid = (element)=>{
162
+ return element.type === 'image' ? true : isVoid(element);
163
+ };
164
+ return editor;
165
+ };
154
166
  const imageBlocks = {
155
167
  image: {
156
168
  renderElement: (props)=>/*#__PURE__*/ jsx(Image, {
@@ -201,7 +213,8 @@ const imageBlocks = {
201
213
  },
202
214
  snippets: [
203
215
  '!['
204
- ]
216
+ ],
217
+ plugin: withImages
205
218
  }
206
219
  };
207
220
 
@@ -1 +1 @@
1
- {"version":3,"file":"Image.mjs","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useStrapiApp } from '@strapi/admin/strapi-admin';\nimport { Box, Flex, FlexComponent } from '@strapi/design-system';\nimport { Image as Picture } from '@strapi/icons';\nimport { type Element, Transforms, Editor } from 'slate';\nimport { useFocused, type RenderElementProps, useSelected } from 'slate-react';\nimport { styled, css } from 'styled-components';\n\nimport { prefixFileUrlWithBackendUrl } from '../../../../../../utils/urls';\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { type Block } from '../utils/types';\n\nimport type { Schema } from '@strapi/types';\n\nconst ImageWrapper = styled<FlexComponent>(Flex)<{ $isFocused?: boolean }>`\n transition-property: box-shadow;\n transition-duration: 0.2s;\n ${(props) =>\n props.$isFocused &&\n css`\n box-shadow: ${props.theme.colors.primary600} 0px 0px 0px 3px;\n `}\n\n & > img {\n height: auto;\n // The max-height is decided with the design team, the 56px is the height of the toolbar\n max-height: calc(512px - 56px);\n max-width: 100%;\n object-fit: contain;\n }\n`;\n\nconst IMAGE_SCHEMA_FIELDS = [\n 'name',\n 'alternativeText',\n 'url',\n 'caption',\n 'width',\n 'height',\n 'formats',\n 'hash',\n 'ext',\n 'mime',\n 'size',\n 'previewUrl',\n 'provider',\n 'provider_metadata',\n 'createdAt',\n 'updatedAt',\n];\n\nconst pick = <T extends object, K extends keyof T>(object: T, keys: K[]): Pick<T, K> => {\n const entries = keys.map((key) => [key, object[key]]);\n return Object.fromEntries(entries);\n};\n\n// Type guard to force TypeScript to narrow the type of the element in Blocks component\nconst isImage = (element: Element): element is Block<'image'> => {\n return element.type === 'image';\n};\n\n// Added a background color to the image wrapper to make it easier to recognize the image block\nconst Image = ({ attributes, children, element }: RenderElementProps) => {\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n\n if (!isImage(element)) {\n return null;\n }\n const { url, alternativeText, width, height } = element.image;\n\n return (\n <Box {...attributes}>\n {children}\n <ImageWrapper\n background=\"neutral100\"\n contentEditable={false}\n justifyContent=\"center\"\n $isFocused={editorIsFocused && imageIsSelected}\n hasRadius\n >\n <img src={url} alt={alternativeText} width={width} height={height} />\n </ImageWrapper>\n </Box>\n );\n};\n\nconst ImageDialog = () => {\n const [isOpen, setIsOpen] = React.useState(true);\n const { editor } = useBlocksEditorContext('ImageDialog');\n const components = useStrapiApp('ImageDialog', (state) => state.components);\n\n if (!components || !isOpen) return null;\n\n const MediaLibraryDialog = components['media-library'] as React.ComponentType<{\n allowedTypes: Schema.Attribute.MediaKind[];\n onClose: () => void;\n onSelectAssets: (_images: Schema.Attribute.MediaValue<true>) => void;\n }>;\n\n const insertImages = (images: Block<'image'>['image'][]) => {\n // If the selection is inside a list, split the list so that the modified block is outside of it\n Transforms.unwrapNodes(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'list',\n split: true,\n });\n\n // Save the path of the node that is being replaced by an image to insert the images there later\n // It's the closest full block node above the selection\n const nodeEntryBeingReplaced = Editor.above(editor, {\n match(node) {\n if (Editor.isEditor(node)) return false;\n\n const isInlineNode = ['text', 'link'].includes(node.type);\n\n return !isInlineNode;\n },\n });\n\n if (!nodeEntryBeingReplaced) return;\n const [, pathToInsert] = nodeEntryBeingReplaced;\n\n // Remove the previous node that is being replaced by an image\n Transforms.removeNodes(editor);\n\n // Convert images to nodes and insert them\n const nodesToInsert = images.map((image) => {\n const imageNode: Block<'image'> = {\n type: 'image',\n image,\n children: [{ type: 'text', text: '' }],\n };\n return imageNode;\n });\n Transforms.insertNodes(editor, nodesToInsert, { at: pathToInsert });\n\n // Set the selection on the image since it was cleared by calling removeNodes\n Transforms.select(editor, pathToInsert);\n };\n\n const handleSelectAssets = (images: Schema.Attribute.MediaValue<true>) => {\n const formattedImages = images.map((image) => {\n // Create an object with imageSchema defined and exclude unnecessary props coming from media library config\n const expectedImage = pick(image, IMAGE_SCHEMA_FIELDS);\n\n const nodeImage: Block<'image'>['image'] = {\n ...expectedImage,\n alternativeText: expectedImage.alternativeText || expectedImage.name,\n url: prefixFileUrlWithBackendUrl(image.url),\n };\n\n return nodeImage;\n });\n\n insertImages(formattedImages);\n setIsOpen(false);\n };\n\n return (\n <MediaLibraryDialog\n allowedTypes={['images']}\n onClose={() => setIsOpen(false)}\n onSelectAssets={handleSelectAssets}\n />\n );\n};\n\nconst imageBlocks: Pick<BlocksStore, 'image'> = {\n image: {\n renderElement: (props) => <Image {...props} />,\n icon: Picture,\n label: {\n id: 'components.Blocks.blocks.image',\n defaultMessage: 'Image',\n },\n matchNode: (node) => node.type === 'image',\n isInBlocksSelector: true,\n handleBackspaceKey(editor) {\n // Prevent issue where the image remains when it's the only block in the document\n if (editor.children.length === 1) {\n Transforms.setNodes(editor, {\n type: 'paragraph',\n // @ts-expect-error we're only setting image as null so that Slate deletes it\n image: null,\n children: [{ type: 'text', text: '' }],\n });\n } else {\n Transforms.removeNodes(editor);\n }\n },\n handleEnterKey(editor) {\n Transforms.insertNodes(editor, {\n type: 'paragraph',\n children: [{ type: 'text', text: '' }],\n });\n },\n handleConvert: () => {\n /**\n * All the logic is managed inside the ImageDialog component,\n * because the blocks are only created when the user selects images in the modal and submits\n * and if he closes the modal, then no changes are made to the editor\n */\n return () => <ImageDialog />;\n },\n snippets: ['!['],\n },\n};\n\nexport { imageBlocks };\n"],"names":["ImageWrapper","styled","Flex","props","$isFocused","css","theme","colors","primary600","IMAGE_SCHEMA_FIELDS","pick","object","keys","entries","map","key","Object","fromEntries","isImage","element","type","Image","attributes","children","editorIsFocused","useFocused","imageIsSelected","useSelected","url","alternativeText","width","height","image","_jsxs","Box","_jsx","background","contentEditable","justifyContent","hasRadius","img","src","alt","ImageDialog","isOpen","setIsOpen","React","useState","editor","useBlocksEditorContext","components","useStrapiApp","state","MediaLibraryDialog","insertImages","images","Transforms","unwrapNodes","match","node","Editor","isEditor","split","nodeEntryBeingReplaced","above","isInlineNode","includes","pathToInsert","removeNodes","nodesToInsert","imageNode","text","insertNodes","at","select","handleSelectAssets","formattedImages","expectedImage","nodeImage","name","prefixFileUrlWithBackendUrl","allowedTypes","onClose","onSelectAssets","imageBlocks","renderElement","icon","Picture","label","id","defaultMessage","matchNode","isInBlocksSelector","handleBackspaceKey","length","setNodes","handleEnterKey","handleConvert","snippets"],"mappings":"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"}
1
+ {"version":3,"file":"Image.mjs","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Image.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useStrapiApp } from '@strapi/admin/strapi-admin';\nimport { Box, Flex, FlexComponent } from '@strapi/design-system';\nimport { Image as Picture } from '@strapi/icons';\nimport { type Element, Transforms, Editor } from 'slate';\nimport { useFocused, type RenderElementProps, useSelected } from 'slate-react';\nimport { styled, css } from 'styled-components';\n\nimport { prefixFileUrlWithBackendUrl } from '../../../../../../utils/urls';\nimport { useBlocksEditorContext, type BlocksStore } from '../BlocksEditor';\nimport { type Block } from '../utils/types';\n\nimport type { Schema } from '@strapi/types';\n\nconst ImageWrapper = styled<FlexComponent>(Flex)<{ $isFocused?: boolean }>`\n transition-property: box-shadow;\n transition-duration: 0.2s;\n ${(props) =>\n props.$isFocused &&\n css`\n box-shadow: ${props.theme.colors.primary600} 0px 0px 0px 3px;\n `}\n\n & > img {\n height: auto;\n // The max-height is decided with the design team, the 56px is the height of the toolbar\n max-height: calc(512px - 56px);\n max-width: 100%;\n object-fit: contain;\n }\n`;\n\nconst IMAGE_SCHEMA_FIELDS = [\n 'name',\n 'alternativeText',\n 'url',\n 'caption',\n 'width',\n 'height',\n 'formats',\n 'hash',\n 'ext',\n 'mime',\n 'size',\n 'previewUrl',\n 'provider',\n 'provider_metadata',\n 'createdAt',\n 'updatedAt',\n];\n\nconst pick = <T extends object, K extends keyof T>(object: T, keys: K[]): Pick<T, K> => {\n const entries = keys.map((key) => [key, object[key]]);\n return Object.fromEntries(entries);\n};\n\n// Type guard to force TypeScript to narrow the type of the element in Blocks component\nconst isImage = (element: Element): element is Block<'image'> => {\n return element.type === 'image';\n};\n\n// Added a background color to the image wrapper to make it easier to recognize the image block\nconst Image = ({ attributes, children, element }: RenderElementProps) => {\n const editorIsFocused = useFocused();\n const imageIsSelected = useSelected();\n\n if (!isImage(element)) {\n return null;\n }\n const { url, alternativeText, width, height } = element.image;\n\n return (\n <Box {...attributes}>\n {children}\n <ImageWrapper\n background=\"neutral100\"\n contentEditable={false}\n justifyContent=\"center\"\n $isFocused={editorIsFocused && imageIsSelected}\n hasRadius\n >\n <img src={url} alt={alternativeText} width={width} height={height} />\n </ImageWrapper>\n </Box>\n );\n};\n\nconst ImageDialog = () => {\n const [isOpen, setIsOpen] = React.useState(true);\n const { editor } = useBlocksEditorContext('ImageDialog');\n const components = useStrapiApp('ImageDialog', (state) => state.components);\n\n if (!components || !isOpen) return null;\n\n const MediaLibraryDialog = components['media-library'] as React.ComponentType<{\n allowedTypes: Schema.Attribute.MediaKind[];\n onClose: () => void;\n onSelectAssets: (_images: Schema.Attribute.MediaValue<true>) => void;\n }>;\n\n const insertImages = (images: Block<'image'>['image'][]) => {\n // If the selection is inside a list, split the list so that the modified block is outside of it\n Transforms.unwrapNodes(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'list',\n split: true,\n });\n\n // Save the path of the node that is being replaced by an image to insert the images there later\n // It's the closest full block node above the selection\n const nodeEntryBeingReplaced = Editor.above(editor, {\n match(node) {\n if (Editor.isEditor(node)) return false;\n\n const isInlineNode = ['text', 'link'].includes(node.type);\n\n return !isInlineNode;\n },\n });\n\n if (!nodeEntryBeingReplaced) return;\n const [, pathToInsert] = nodeEntryBeingReplaced;\n\n // Remove the previous node that is being replaced by an image\n Transforms.removeNodes(editor);\n\n // Convert images to nodes and insert them\n const nodesToInsert = images.map((image) => {\n const imageNode: Block<'image'> = {\n type: 'image',\n image,\n children: [{ type: 'text', text: '' }],\n };\n return imageNode;\n });\n Transforms.insertNodes(editor, nodesToInsert, { at: pathToInsert });\n\n // Set the selection on the image since it was cleared by calling removeNodes\n Transforms.select(editor, pathToInsert);\n };\n\n const handleSelectAssets = (images: Schema.Attribute.MediaValue<true>) => {\n const formattedImages = images.map((image) => {\n // Create an object with imageSchema defined and exclude unnecessary props coming from media library config\n const expectedImage = pick(image, IMAGE_SCHEMA_FIELDS);\n\n const nodeImage: Block<'image'>['image'] = {\n ...expectedImage,\n alternativeText: expectedImage.alternativeText || expectedImage.name,\n url: prefixFileUrlWithBackendUrl(image.url),\n };\n\n return nodeImage;\n });\n\n insertImages(formattedImages);\n setIsOpen(false);\n };\n\n return (\n <MediaLibraryDialog\n allowedTypes={['images']}\n onClose={() => setIsOpen(false)}\n onSelectAssets={handleSelectAssets}\n />\n );\n};\n\n/**\n * Images are void elements. They handle the rendering of their children instead of Slate.\n * See the Slate documentation for more information:\n * - https://docs.slatejs.org/api/nodes/element#void-vs-not-void\n * - https://docs.slatejs.org/api/nodes/element#rendering-void-elements\n */\nconst withImages = (editor: Editor) => {\n const { isVoid } = editor;\n\n editor.isVoid = (element) => {\n return element.type === 'image' ? true : isVoid(element);\n };\n\n return editor;\n};\n\nconst imageBlocks: Pick<BlocksStore, 'image'> = {\n image: {\n renderElement: (props) => <Image {...props} />,\n icon: Picture,\n label: {\n id: 'components.Blocks.blocks.image',\n defaultMessage: 'Image',\n },\n matchNode: (node) => node.type === 'image',\n isInBlocksSelector: true,\n handleBackspaceKey(editor) {\n // Prevent issue where the image remains when it's the only block in the document\n if (editor.children.length === 1) {\n Transforms.setNodes(editor, {\n type: 'paragraph',\n // @ts-expect-error we're only setting image as null so that Slate deletes it\n image: null,\n children: [{ type: 'text', text: '' }],\n });\n } else {\n Transforms.removeNodes(editor);\n }\n },\n handleEnterKey(editor) {\n Transforms.insertNodes(editor, {\n type: 'paragraph',\n children: [{ type: 'text', text: '' }],\n });\n },\n handleConvert: () => {\n /**\n * All the logic is managed inside the ImageDialog component,\n * because the blocks are only created when the user selects images in the modal and submits\n * and if he closes the modal, then no changes are made to the editor\n */\n return () => <ImageDialog />;\n },\n snippets: ['!['],\n plugin: withImages,\n },\n};\n\nexport { imageBlocks };\n"],"names":["ImageWrapper","styled","Flex","props","$isFocused","css","theme","colors","primary600","IMAGE_SCHEMA_FIELDS","pick","object","keys","entries","map","key","Object","fromEntries","isImage","element","type","Image","attributes","children","editorIsFocused","useFocused","imageIsSelected","useSelected","url","alternativeText","width","height","image","_jsxs","Box","_jsx","background","contentEditable","justifyContent","hasRadius","img","src","alt","ImageDialog","isOpen","setIsOpen","React","useState","editor","useBlocksEditorContext","components","useStrapiApp","state","MediaLibraryDialog","insertImages","images","Transforms","unwrapNodes","match","node","Editor","isEditor","split","nodeEntryBeingReplaced","above","isInlineNode","includes","pathToInsert","removeNodes","nodesToInsert","imageNode","text","insertNodes","at","select","handleSelectAssets","formattedImages","expectedImage","nodeImage","name","prefixFileUrlWithBackendUrl","allowedTypes","onClose","onSelectAssets","withImages","isVoid","imageBlocks","renderElement","icon","Picture","label","id","defaultMessage","matchNode","isInBlocksSelector","handleBackspaceKey","length","setNodes","handleEnterKey","handleConvert","snippets","plugin"],"mappings":"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"}