@strapi/content-manager 5.31.3 → 5.32.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.
@@ -112,6 +112,13 @@ function useBlocksEditorContext(consumerName) {
112
112
  };
113
113
  }
114
114
  const pipe = (...fns)=>(value)=>fns.reduce((prev, fn)=>fn(prev), value);
115
+ /**
116
+ * Normalize the blocks state to null if the editor state is considered empty,
117
+ * otherwise return the state
118
+ */ const normalizeBlocksState = (editor, value)=>{
119
+ const isEmpty = value.length === 1 && slate.Editor.isEmpty(editor, value[0]);
120
+ return isEmpty ? null : value;
121
+ };
115
122
  const BlocksEditor = /*#__PURE__*/ React__namespace.forwardRef(({ disabled = false, name, onChange, value, error, ...contentProps }, forwardedRef)=>{
116
123
  const { formatMessage } = reactIntl.useIntl();
117
124
  const [editor] = React__namespace.useState(()=>pipe(slateHistory.withHistory, withImages.withImages, withStrapiSchema.withStrapiSchema, slateReact.withReact, withLinks.withLinks)(slate.createEditor()));
@@ -145,12 +152,13 @@ const BlocksEditor = /*#__PURE__*/ React__namespace.forwardRef(({ disabled = fal
145
152
  // Set a new debounce timeout
146
153
  debounceTimeout.current = setTimeout(()=>{
147
154
  incrementSlateUpdatesCount();
148
- onChange(name, state);
155
+ // Normalize the state (empty editor becomes null)
156
+ onChange(name, normalizeBlocksState(editor, state));
149
157
  debounceTimeout.current = null;
150
158
  }, 300);
151
159
  }
152
160
  }, [
153
- editor.operations,
161
+ editor,
154
162
  incrementSlateUpdatesCount,
155
163
  name,
156
164
  onChange
@@ -165,8 +173,11 @@ const BlocksEditor = /*#__PURE__*/ React__namespace.forwardRef(({ disabled = fal
165
173
  }, []);
166
174
  // Ensure the editor is in sync after discard
167
175
  React__namespace.useEffect(()=>{
176
+ // Normalize empty states for comparison to avoid losing focus on the editor when content is deleted
177
+ const normalizedValue = value?.length ? value : null;
178
+ const normalizedEditorState = normalizeBlocksState(editor, editor.children);
168
179
  // Compare the field value with the editor state to check for a stale selection
169
- if (value && JSON.stringify(editor.children) !== JSON.stringify(value)) {
180
+ if (normalizedValue && normalizedEditorState && JSON.stringify(normalizedEditorState) !== JSON.stringify(normalizedValue)) {
170
181
  // When there is a diff, unset selection to avoid an invalid state
171
182
  slate.Transforms.deselect(editor);
172
183
  }
@@ -198,7 +209,7 @@ const BlocksEditor = /*#__PURE__*/ React__namespace.forwardRef(({ disabled = fal
198
209
  }),
199
210
  /*#__PURE__*/ jsxRuntime.jsx(slateReact.Slate, {
200
211
  editor: editor,
201
- initialValue: value || [
212
+ initialValue: value?.length ? value : [
202
213
  {
203
214
  type: 'paragraph',
204
215
  children: [
@@ -253,5 +264,6 @@ const BlocksEditor = /*#__PURE__*/ React__namespace.forwardRef(({ disabled = fal
253
264
  exports.BlocksEditor = BlocksEditor;
254
265
  exports.BlocksEditorProvider = BlocksEditorProvider;
255
266
  exports.isSelectorBlockKey = isSelectorBlockKey;
267
+ exports.normalizeBlocksState = normalizeBlocksState;
256
268
  exports.useBlocksEditorContext = useBlocksEditorContext;
257
269
  //# sourceMappingURL=BlocksEditor.js.map
@@ -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 } from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms } 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 { withImages } from './plugins/withImages';\nimport { withLinks } from './plugins/withLinks';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\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 snippets?: string[];\n dragHandleTopMargin?: CSSProperties['marginTop'];\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}\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\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 [editor] = React.useState(() =>\n pipe(withHistory, withImages, withStrapiSchema, withReact, withLinks)(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 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 onChange(name, state as Schema.Attribute.BlocksValue);\n debounceTimeout.current = null;\n }, 300);\n }\n },\n [editor.operations, 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 // Compare the field value with the editor state to check for a stale selection\n if (value && JSON.stringify(editor.children) !== JSON.stringify(value)) {\n // When there is a diff, unset selection to avoid an invalid state\n Transforms.deselect(editor);\n }\n }, [editor, value]);\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 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={value || [{ type: 'paragraph', children: [{ type: 'text', text: '' }] }]}\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 >\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 && (\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};\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","BlocksEditor","forwardRef","disabled","name","onChange","error","contentProps","forwardedRef","formatMessage","useIntl","withHistory","withImages","withStrapiSchema","withReact","withLinks","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","handleSlateChange","isAstChange","operations","some","op","type","clearTimeout","setTimeout","JSON","stringify","children","Transforms","deselect","blocks","useMemo","paragraphBlocks","headingBlocks","listBlocks","linkBlocks","imageBlocks","quoteBlocks","codeBlocks","_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 { createContext, type FieldValue } from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms } 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 { withImages } from './plugins/withImages';\nimport { withLinks } from './plugins/withLinks';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\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 snippets?: string[];\n dragHandleTopMargin?: CSSProperties['marginTop'];\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}\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 [editor] = React.useState(() =>\n pipe(withHistory, withImages, withStrapiSchema, withReact, withLinks)(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 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 // 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 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 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 >\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 && (\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","withHistory","withImages","withStrapiSchema","withReact","withLinks","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","handleSlateChange","isAstChange","operations","some","op","type","clearTimeout","setTimeout","normalizedValue","normalizedEditorState","children","JSON","stringify","Transforms","deselect","blocks","useMemo","paragraphBlocks","headingBlocks","listBlocks","linkBlocks","imageBlocks","quoteBlocks","codeBlocks","_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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"}
@@ -4,7 +4,7 @@ import { createContext } 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 { useIntl } from 'react-intl';
7
- import { createEditor, Transforms } from 'slate';
7
+ import { createEditor, Transforms, Editor } from 'slate';
8
8
  import { withHistory } from 'slate-history';
9
9
  import { ReactEditor, Slate, useSlate, withReact } from 'slate-react';
10
10
  import { styled } from 'styled-components';
@@ -91,6 +91,13 @@ function useBlocksEditorContext(consumerName) {
91
91
  };
92
92
  }
93
93
  const pipe = (...fns)=>(value)=>fns.reduce((prev, fn)=>fn(prev), value);
94
+ /**
95
+ * Normalize the blocks state to null if the editor state is considered empty,
96
+ * otherwise return the state
97
+ */ const normalizeBlocksState = (editor, value)=>{
98
+ const isEmpty = value.length === 1 && Editor.isEmpty(editor, value[0]);
99
+ return isEmpty ? null : value;
100
+ };
94
101
  const BlocksEditor = /*#__PURE__*/ React.forwardRef(({ disabled = false, name, onChange, value, error, ...contentProps }, forwardedRef)=>{
95
102
  const { formatMessage } = useIntl();
96
103
  const [editor] = React.useState(()=>pipe(withHistory, withImages, withStrapiSchema, withReact, withLinks)(createEditor()));
@@ -124,12 +131,13 @@ const BlocksEditor = /*#__PURE__*/ React.forwardRef(({ disabled = false, name, o
124
131
  // Set a new debounce timeout
125
132
  debounceTimeout.current = setTimeout(()=>{
126
133
  incrementSlateUpdatesCount();
127
- onChange(name, state);
134
+ // Normalize the state (empty editor becomes null)
135
+ onChange(name, normalizeBlocksState(editor, state));
128
136
  debounceTimeout.current = null;
129
137
  }, 300);
130
138
  }
131
139
  }, [
132
- editor.operations,
140
+ editor,
133
141
  incrementSlateUpdatesCount,
134
142
  name,
135
143
  onChange
@@ -144,8 +152,11 @@ const BlocksEditor = /*#__PURE__*/ React.forwardRef(({ disabled = false, name, o
144
152
  }, []);
145
153
  // Ensure the editor is in sync after discard
146
154
  React.useEffect(()=>{
155
+ // Normalize empty states for comparison to avoid losing focus on the editor when content is deleted
156
+ const normalizedValue = value?.length ? value : null;
157
+ const normalizedEditorState = normalizeBlocksState(editor, editor.children);
147
158
  // Compare the field value with the editor state to check for a stale selection
148
- if (value && JSON.stringify(editor.children) !== JSON.stringify(value)) {
159
+ if (normalizedValue && normalizedEditorState && JSON.stringify(normalizedEditorState) !== JSON.stringify(normalizedValue)) {
149
160
  // When there is a diff, unset selection to avoid an invalid state
150
161
  Transforms.deselect(editor);
151
162
  }
@@ -177,7 +188,7 @@ const BlocksEditor = /*#__PURE__*/ React.forwardRef(({ disabled = false, name, o
177
188
  }),
178
189
  /*#__PURE__*/ jsx(Slate, {
179
190
  editor: editor,
180
- initialValue: value || [
191
+ initialValue: value?.length ? value : [
181
192
  {
182
193
  type: 'paragraph',
183
194
  children: [
@@ -229,5 +240,5 @@ const BlocksEditor = /*#__PURE__*/ React.forwardRef(({ disabled = false, name, o
229
240
  });
230
241
  });
231
242
 
232
- export { BlocksEditor, BlocksEditorProvider, isSelectorBlockKey, useBlocksEditorContext };
243
+ export { BlocksEditor, BlocksEditorProvider, isSelectorBlockKey, normalizeBlocksState, useBlocksEditorContext };
233
244
  //# 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 } from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms } 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 { withImages } from './plugins/withImages';\nimport { withLinks } from './plugins/withLinks';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\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 snippets?: string[];\n dragHandleTopMargin?: CSSProperties['marginTop'];\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}\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\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 [editor] = React.useState(() =>\n pipe(withHistory, withImages, withStrapiSchema, withReact, withLinks)(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 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 onChange(name, state as Schema.Attribute.BlocksValue);\n debounceTimeout.current = null;\n }, 300);\n }\n },\n [editor.operations, 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 // Compare the field value with the editor state to check for a stale selection\n if (value && JSON.stringify(editor.children) !== JSON.stringify(value)) {\n // When there is a diff, unset selection to avoid an invalid state\n Transforms.deselect(editor);\n }\n }, [editor, value]);\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 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={value || [{ type: 'paragraph', children: [{ type: 'text', text: '' }] }]}\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 >\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 && (\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};\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","BlocksEditor","forwardRef","disabled","name","onChange","error","contentProps","forwardedRef","formatMessage","useIntl","withHistory","withImages","withStrapiSchema","withReact","withLinks","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","handleSlateChange","isAstChange","operations","some","op","type","clearTimeout","setTimeout","JSON","stringify","children","Transforms","deselect","blocks","useMemo","paragraphBlocks","headingBlocks","listBlocks","linkBlocks","imageBlocks","quoteBlocks","codeBlocks","_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 { createContext, type FieldValue } from '@strapi/admin/strapi-admin';\nimport { IconButton, Divider, VisuallyHidden } from '@strapi/design-system';\nimport { Expand } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { Editor, type Descendant, createEditor, Transforms } 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 { withImages } from './plugins/withImages';\nimport { withLinks } from './plugins/withLinks';\nimport { withStrapiSchema } from './plugins/withStrapiSchema';\n\nimport type { Schema } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * BlocksEditorProvider\n * -----------------------------------------------------------------------------------------------*/\n\ninterface BaseBlock {\n renderElement: (props: RenderElementProps) => React.JSX.Element;\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 snippets?: string[];\n dragHandleTopMargin?: CSSProperties['marginTop'];\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}\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 [editor] = React.useState(() =>\n pipe(withHistory, withImages, withStrapiSchema, withReact, withLinks)(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 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 // 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 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 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 >\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 && (\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","withHistory","withImages","withStrapiSchema","withReact","withLinks","createEditor","liveText","setLiveText","ariaDescriptionId","useId","isExpandedMode","handleToggleExpand","useReducer","useImperativeHandle","focus","ReactEditor","debounceTimeout","handleSlateChange","isAstChange","operations","some","op","type","clearTimeout","setTimeout","normalizedValue","normalizedEditorState","children","JSON","stringify","Transforms","deselect","blocks","useMemo","paragraphBlocks","headingBlocks","listBlocks","linkBlocks","imageBlocks","quoteBlocks","codeBlocks","_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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"}
@@ -104,16 +104,8 @@ const BLOCK_LIST_ATTRIBUTE_KEYS = [
104
104
  * @internal
105
105
  * @description We need to remove null fields from the data-structure because it will pass it
106
106
  * to the specific inputs breaking them as most would prefer empty strings or `undefined` if
107
- * they're controlled / uncontrolled.
108
- */ const removeNullValues = (data)=>{
109
- return Object.entries(data).reduce((acc, [key, value])=>{
110
- if (value === null) {
111
- return acc;
112
- }
113
- acc[key] = value;
114
- return acc;
115
- }, {});
116
- };
107
+ * they're controlled / uncontrolled. However, Boolean fields should preserve null values.
108
+ */ const removeNullValues = (schema, components = {})=>traverseData((attribute, value)=>value === null && attribute.type !== 'boolean', ()=>undefined)(schema, components);
117
109
  /* -------------------------------------------------------------------------------------------------
118
110
  * transformDocuments
119
111
  * -----------------------------------------------------------------------------------------------*/ /**
@@ -124,7 +116,7 @@ const BLOCK_LIST_ATTRIBUTE_KEYS = [
124
116
  */ const transformDocument = (schema, components = {})=>(document)=>{
125
117
  const transformations = pipe(removeFieldsThatDontExistOnSchema(schema), removeProhibitedFields([
126
118
  'password'
127
- ])(schema, components), removeNullValues, prepareRelations(schema, components), prepareTempKeys(schema, components));
119
+ ])(schema, components), removeNullValues(schema, components), prepareRelations(schema, components), prepareTempKeys(schema, components));
128
120
  return transformations(document);
129
121
  };
130
122
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","sources":["../../../../../admin/src/pages/EditView/utils/data.ts"],"sourcesContent":["import { createRulesEngine } from '@strapi/admin/strapi-admin';\nimport { generateNKeysBetween } from 'fractional-indexing';\nimport pipe from 'lodash/fp/pipe';\n\nimport { DOCUMENT_META_FIELDS } from '../../../constants/attributes';\n\nimport type { ComponentsDictionary, Document } from '../../../hooks/useDocument';\nimport type { Schema, UID } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * traverseData\n * -----------------------------------------------------------------------------------------------*/\n\n// Make only attributes required since it's the only one Content History has\ntype PartialSchema = Partial<Schema.Schema> & Pick<Schema.Schema, 'attributes'>;\n\ntype Predicate = <TAttribute extends Schema.Attribute.AnyAttribute>(\n attribute: TAttribute,\n value: Schema.Attribute.Value<TAttribute>\n) => boolean;\ntype Transform = <TAttribute extends Schema.Attribute.AnyAttribute>(\n value: any,\n attribute: TAttribute\n) => any;\ntype AnyData = Omit<Document, 'id'>;\n\nconst BLOCK_LIST_ATTRIBUTE_KEYS = ['__component', '__temp_key__'];\n\n/**\n * @internal This function is used to traverse the data and transform the values.\n * Given a predicate function, it will transform the value (using the given transform function)\n * if the predicate returns true. If it finds that the attribute is a component or dynamiczone,\n * it will recursively traverse those data structures as well.\n *\n * It is possible to break the ContentManager by using this function incorrectly, for example,\n * if you transform a number into a string but the attribute type is a number, the ContentManager\n * will not be able to save the data and the Form will likely crash because the component it's\n * passing the data too won't succesfully be able to handle the value.\n */\nconst traverseData =\n (predicate: Predicate, transform: Transform) =>\n (schema: PartialSchema, components: ComponentsDictionary = {}) =>\n (data: AnyData = {}) => {\n const traverse = (datum: AnyData, attributes: Schema.Schema['attributes']) => {\n return Object.entries(datum).reduce<AnyData>((acc, [key, value]) => {\n const attribute = attributes[key];\n\n /**\n * If the attribute is a block list attribute, we don't want to transform it.\n * We also don't want to transform null or undefined values.\n */\n if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === undefined) {\n acc[key] = value;\n return acc;\n }\n\n if (attribute.type === 'component') {\n if (attribute.repeatable) {\n const componentValue = (\n predicate(attribute, value) ? transform(value, attribute) : value\n ) as Schema.Attribute.Value<Schema.Attribute.Component<UID.Component, true>>;\n acc[key] = componentValue.map((componentData) =>\n traverse(componentData, components[attribute.component]?.attributes ?? {})\n );\n } else {\n const componentValue = (\n predicate(attribute, value) ? transform(value, attribute) : value\n ) as Schema.Attribute.Value<Schema.Attribute.Component<UID.Component, false>>;\n\n acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});\n }\n } else if (attribute.type === 'dynamiczone') {\n const dynamicZoneValue = (\n predicate(attribute, value) ? transform(value, attribute) : value\n ) as Schema.Attribute.Value<Schema.Attribute.DynamicZone>;\n\n acc[key] = dynamicZoneValue.map((componentData) =>\n traverse(componentData, components[componentData.__component]?.attributes ?? {})\n );\n } else if (predicate(attribute, value)) {\n acc[key] = transform(value, attribute);\n } else {\n acc[key] = value;\n }\n\n return acc;\n }, {});\n };\n\n return traverse(data, schema.attributes);\n };\n\n/* -------------------------------------------------------------------------------------------------\n * removeProhibitedFields\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal Removes all the fields that are not allowed.\n */\nconst removeProhibitedFields = (prohibitedFields: Schema.Attribute.Kind[]) =>\n traverseData(\n (attribute) => prohibitedFields.includes(attribute.type),\n () => ''\n );\n\n/* -------------------------------------------------------------------------------------------------\n * prepareRelations\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Sets all relation values to an empty array.\n */\nconst prepareRelations = traverseData(\n (attribute) => attribute.type === 'relation',\n () => ({\n connect: [],\n disconnect: [],\n })\n);\n\n/* -------------------------------------------------------------------------------------------------\n * prepareTempKeys\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Adds a `__temp_key__` to each component and dynamiczone item. This gives us\n * a stable identifier regardless of its ids etc. that we can then use for drag and drop.\n */\nconst prepareTempKeys = traverseData(\n (attribute) =>\n (attribute.type === 'component' && attribute.repeatable) || attribute.type === 'dynamiczone',\n (data) => {\n if (Array.isArray(data) && data.length > 0) {\n const keys = generateNKeysBetween(undefined, undefined, data.length);\n\n return data.map((datum, index) => ({\n ...datum,\n __temp_key__: keys[index],\n }));\n }\n\n return data;\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * removeFieldsThatDontExistOnSchema\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Fields that don't exist in the schema like createdAt etc. are only on the first level (not nested),\n * as such we don't need to traverse the components to remove them.\n */\nconst removeFieldsThatDontExistOnSchema = (schema: PartialSchema) => (data: AnyData) => {\n const schemaKeys = Object.keys(schema.attributes);\n const dataKeys = Object.keys(data);\n\n const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));\n\n const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {\n delete acc[key];\n\n return acc;\n }, structuredClone(data));\n\n return revisedData;\n};\n\n/**\n * @internal\n * @description We need to remove null fields from the data-structure because it will pass it\n * to the specific inputs breaking them as most would prefer empty strings or `undefined` if\n * they're controlled / uncontrolled.\n */\nconst removeNullValues = (data: AnyData) => {\n return Object.entries(data).reduce<AnyData>((acc, [key, value]) => {\n if (value === null) {\n return acc;\n }\n\n acc[key] = value;\n\n return acc;\n }, {});\n};\n\n/* -------------------------------------------------------------------------------------------------\n * transformDocuments\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Takes a document data structure (this could be from the API or a default form structure)\n * and applies consistent data transformations to it. This is also used when we add new components to the\n * form to ensure the data is correctly prepared from their default state e.g. relations are set to an empty array.\n */\nconst transformDocument =\n (schema: PartialSchema, components: ComponentsDictionary = {}) =>\n (document: AnyData) => {\n const transformations = pipe(\n removeFieldsThatDontExistOnSchema(schema),\n removeProhibitedFields(['password'])(schema, components),\n removeNullValues,\n prepareRelations(schema, components),\n prepareTempKeys(schema, components)\n );\n\n return transformations(document);\n };\n\ntype HandleOptions = {\n schema?: Schema.ContentType | Schema.Component;\n initialValues?: AnyData;\n components?: Record<string, Schema.Component>;\n};\n\ntype RemovedFieldPath = string;\n\n/**\n * @internal\n * @description Finds the initial value for a component or dynamic zone item (based on its __temp_key__ and not its index).\n * @param initialValue - The initial values object.\n * @param item - The item to find the initial value for.\n * @returns The initial value for the item.\n */\nconst getItemInitialValue = (initialValue: AnyData, item: AnyData) => {\n if (initialValue && Array.isArray(initialValue)) {\n const matchingInitialItem = initialValue.find(\n (initialItem) => initialItem.__temp_key__ === item.__temp_key__\n );\n if (matchingInitialItem) {\n return matchingInitialItem;\n }\n }\n return {};\n};\n\n/**\n * @internal\n * @description Collects paths of attributes that should be removed based on visibility conditions.\n * This function only evaluates conditions.visible (JSON Logic), not the visible boolean property.\n *\n * @param data - The data object to evaluate\n * @param schema - The content type schema\n * @param components - Dictionary of component schemas\n * @param path - Current path in the data structure (for nested components/dynamiczones)\n * @returns Array of field paths that should be removed\n */\nconst collectInvisibleAttributes = (\n data: AnyData,\n schema: Schema.ContentType | Schema.Component | undefined,\n components: Record<string, Schema.Component>,\n path: string[] = []\n): RemovedFieldPath[] => {\n if (!schema?.attributes) return [];\n\n const rulesEngine = createRulesEngine();\n const removedPaths: RemovedFieldPath[] = [];\n const evaluatedData: AnyData = {};\n\n for (const [attrName, attrDef] of Object.entries(schema.attributes)) {\n const fullPath = [...path, attrName].join('.');\n\n // Skip fields with visible: false - they're managed by backend\n if ('visible' in attrDef && attrDef.visible === false) {\n continue;\n }\n\n const condition = attrDef?.conditions?.visible;\n const isVisible = condition\n ? rulesEngine.evaluate(condition, { ...data, ...evaluatedData })\n : true;\n\n if (!isVisible) {\n removedPaths.push(fullPath);\n continue;\n }\n\n // Track this field for future condition evaluations\n if (attrName in data) {\n evaluatedData[attrName] = data[attrName];\n }\n\n // Recursively process components\n if (attrDef.type === 'component') {\n const compSchema = components[attrDef.component];\n const value = data[attrName];\n\n if (attrDef.repeatable && Array.isArray(value)) {\n value.forEach((item) => {\n const nestedPaths = collectInvisibleAttributes(item, compSchema, components, [\n ...path,\n `${attrName}[${item.__temp_key__}]`,\n ]);\n removedPaths.push(...nestedPaths);\n });\n } else if (value && typeof value === 'object') {\n const nestedPaths = collectInvisibleAttributes(value, compSchema, components, [\n ...path,\n attrName,\n ]);\n removedPaths.push(...nestedPaths);\n }\n }\n\n // Recursively process dynamic zones\n if (attrDef.type === 'dynamiczone' && Array.isArray(data[attrName])) {\n data[attrName].forEach((dzItem: AnyData) => {\n const compUID = dzItem?.__component;\n const compSchema = components[compUID];\n const nestedPaths = collectInvisibleAttributes(dzItem, compSchema, components, [\n ...path,\n `${attrName}[${dzItem.__temp_key__}]`,\n ]);\n removedPaths.push(...nestedPaths);\n });\n }\n }\n\n return removedPaths;\n};\n\n/**\n * @internal\n * @description Removes attributes from data based on the list of paths to remove.\n * Preserves fields with visible: false from data or initialValues.\n *\n * @param data - The data object to filter\n * @param initialValues - Initial values to fall back to\n * @param schema - The content type schema\n * @param components - Dictionary of component schemas\n * @param removedPaths - Array of field paths to remove\n * @param currentPath - Current path in the data structure\n * @returns Filtered data object\n */\nconst filterDataByRemovedPaths = (\n data: AnyData,\n initialValues: AnyData,\n schema: Schema.ContentType | Schema.Component | undefined,\n components: Record<string, Schema.Component>,\n removedPaths: RemovedFieldPath[],\n currentPath: string[] = []\n): AnyData => {\n if (!schema?.attributes) return data;\n\n const result: AnyData = {};\n\n for (const [attrName, attrDef] of Object.entries(schema.attributes)) {\n const fullPath = [...currentPath, attrName].join('.');\n\n // Check if this field should be removed\n if (removedPaths.includes(fullPath)) {\n continue;\n }\n\n // Handle fields with visible: false - preserve from data or initialValues\n if ('visible' in attrDef && attrDef.visible === false) {\n const userProvided = Object.hasOwn(data, attrName);\n if (userProvided) {\n result[attrName] = data[attrName];\n } else if (attrName in initialValues) {\n result[attrName] = initialValues[attrName];\n }\n continue;\n }\n\n const userProvided = Object.hasOwn(data, attrName);\n const currentValue = userProvided ? data[attrName] : undefined;\n const initialValue = initialValues?.[attrName];\n\n // Handle components\n if (attrDef.type === 'component') {\n const compSchema = components[attrDef.component];\n const value = currentValue === undefined ? initialValue : currentValue;\n\n if (!value) {\n result[attrName] = attrDef.repeatable ? [] : null;\n continue;\n }\n\n if (attrDef.repeatable && Array.isArray(value)) {\n result[attrName] = value.map((item) => {\n const componentInitialValue = getItemInitialValue(initialValue, item);\n return filterDataByRemovedPaths(\n item,\n componentInitialValue,\n compSchema,\n components,\n removedPaths,\n [...currentPath, `${attrName}[${item.__temp_key__}]`]\n );\n });\n } else {\n result[attrName] = filterDataByRemovedPaths(\n value,\n initialValue ?? {},\n compSchema,\n components,\n removedPaths,\n [...currentPath, attrName]\n );\n }\n\n continue;\n }\n\n // Handle dynamic zones\n if (attrDef.type === 'dynamiczone') {\n if (!Array.isArray(currentValue)) {\n result[attrName] = [];\n continue;\n }\n\n result[attrName] = currentValue.map((dzItem) => {\n const compUID = dzItem?.__component;\n const compSchema = components[compUID];\n const componentInitialValue = getItemInitialValue(initialValue, dzItem);\n\n const cleaned = filterDataByRemovedPaths(\n dzItem,\n componentInitialValue,\n compSchema,\n components,\n removedPaths,\n [...currentPath, `${attrName}[${dzItem.__temp_key__}]`]\n );\n\n // For newly created components, ensure id is undefined (in case of reordering)\n const processedItem =\n dzItem.id === undefined || dzItem.id === null\n ? { __component: compUID, ...cleaned, id: undefined }\n : { __component: compUID, ...cleaned };\n\n return processedItem;\n });\n\n continue;\n }\n\n // Regular fields - preserve from data or initialValues\n if (currentValue !== undefined) {\n result[attrName] = currentValue;\n } else if (initialValue !== undefined) {\n result[attrName] = initialValue;\n }\n }\n\n // Pass through any fields from data that aren't in the schema\n for (const [key, value] of Object.entries(data)) {\n if (!(key in result) && !(key in (schema?.attributes || {}))) {\n result[key] = value;\n }\n }\n\n return result;\n};\n\n/**\n * Removes values from the data object if their corresponding attribute has a\n * visibility condition that evaluates to false.\n *\n * @param data - The data object to filter based on visibility\n * @param options - Schema, initialValues, and components\n * @returns Object with filtered data and list of removed attribute paths\n */\nconst handleInvisibleAttributes = (\n data: AnyData,\n { schema, initialValues = {}, components = {} }: HandleOptions\n): {\n data: AnyData;\n removedAttributes: RemovedFieldPath[];\n} => {\n if (!schema?.attributes) return { data, removedAttributes: [] };\n\n const removedAttributes = collectInvisibleAttributes(data, schema, components);\n\n const filteredData = filterDataByRemovedPaths(\n data,\n initialValues,\n schema,\n components,\n removedAttributes\n );\n\n return {\n data: filteredData,\n removedAttributes,\n };\n};\n\nexport {\n removeProhibitedFields,\n prepareRelations,\n prepareTempKeys,\n removeFieldsThatDontExistOnSchema,\n transformDocument,\n handleInvisibleAttributes,\n};\nexport type { AnyData };\n"],"names":["BLOCK_LIST_ATTRIBUTE_KEYS","traverseData","predicate","transform","schema","components","data","traverse","datum","attributes","Object","entries","reduce","acc","key","value","attribute","includes","undefined","type","repeatable","componentValue","map","componentData","component","dynamicZoneValue","__component","removeProhibitedFields","prohibitedFields","prepareRelations","connect","disconnect","prepareTempKeys","Array","isArray","length","keys","generateNKeysBetween","index","__temp_key__","removeFieldsThatDontExistOnSchema","schemaKeys","dataKeys","keysToRemove","filter","revisedData","DOCUMENT_META_FIELDS","structuredClone","removeNullValues","transformDocument","document","transformations","pipe","getItemInitialValue","initialValue","item","matchingInitialItem","find","initialItem","collectInvisibleAttributes","path","rulesEngine","createRulesEngine","removedPaths","evaluatedData","attrName","attrDef","fullPath","join","visible","condition","conditions","isVisible","evaluate","push","compSchema","forEach","nestedPaths","dzItem","compUID","filterDataByRemovedPaths","initialValues","currentPath","result","userProvided","hasOwn","currentValue","componentInitialValue","cleaned","processedItem","id","handleInvisibleAttributes","removedAttributes","filteredData"],"mappings":"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"}
1
+ {"version":3,"file":"data.js","sources":["../../../../../admin/src/pages/EditView/utils/data.ts"],"sourcesContent":["import { createRulesEngine } from '@strapi/admin/strapi-admin';\nimport { generateNKeysBetween } from 'fractional-indexing';\nimport pipe from 'lodash/fp/pipe';\n\nimport { DOCUMENT_META_FIELDS } from '../../../constants/attributes';\n\nimport type { ComponentsDictionary, Document } from '../../../hooks/useDocument';\nimport type { Schema, UID } from '@strapi/types';\n\n/* -------------------------------------------------------------------------------------------------\n * traverseData\n * -----------------------------------------------------------------------------------------------*/\n\n// Make only attributes required since it's the only one Content History has\ntype PartialSchema = Partial<Schema.Schema> & Pick<Schema.Schema, 'attributes'>;\n\ntype Predicate = <TAttribute extends Schema.Attribute.AnyAttribute>(\n attribute: TAttribute,\n value: Schema.Attribute.Value<TAttribute>\n) => boolean;\ntype Transform = <TAttribute extends Schema.Attribute.AnyAttribute>(\n value: any,\n attribute: TAttribute\n) => any;\ntype AnyData = Omit<Document, 'id'>;\n\nconst BLOCK_LIST_ATTRIBUTE_KEYS = ['__component', '__temp_key__'];\n\n/**\n * @internal This function is used to traverse the data and transform the values.\n * Given a predicate function, it will transform the value (using the given transform function)\n * if the predicate returns true. If it finds that the attribute is a component or dynamiczone,\n * it will recursively traverse those data structures as well.\n *\n * It is possible to break the ContentManager by using this function incorrectly, for example,\n * if you transform a number into a string but the attribute type is a number, the ContentManager\n * will not be able to save the data and the Form will likely crash because the component it's\n * passing the data too won't succesfully be able to handle the value.\n */\nconst traverseData =\n (predicate: Predicate, transform: Transform) =>\n (schema: PartialSchema, components: ComponentsDictionary = {}) =>\n (data: AnyData = {}) => {\n const traverse = (datum: AnyData, attributes: Schema.Schema['attributes']) => {\n return Object.entries(datum).reduce<AnyData>((acc, [key, value]) => {\n const attribute = attributes[key];\n\n /**\n * If the attribute is a block list attribute, we don't want to transform it.\n * We also don't want to transform null or undefined values.\n */\n if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === undefined) {\n acc[key] = value;\n return acc;\n }\n\n if (attribute.type === 'component') {\n if (attribute.repeatable) {\n const componentValue = (\n predicate(attribute, value) ? transform(value, attribute) : value\n ) as Schema.Attribute.Value<Schema.Attribute.Component<UID.Component, true>>;\n acc[key] = componentValue.map((componentData) =>\n traverse(componentData, components[attribute.component]?.attributes ?? {})\n );\n } else {\n const componentValue = (\n predicate(attribute, value) ? transform(value, attribute) : value\n ) as Schema.Attribute.Value<Schema.Attribute.Component<UID.Component, false>>;\n\n acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});\n }\n } else if (attribute.type === 'dynamiczone') {\n const dynamicZoneValue = (\n predicate(attribute, value) ? transform(value, attribute) : value\n ) as Schema.Attribute.Value<Schema.Attribute.DynamicZone>;\n\n acc[key] = dynamicZoneValue.map((componentData) =>\n traverse(componentData, components[componentData.__component]?.attributes ?? {})\n );\n } else if (predicate(attribute, value)) {\n acc[key] = transform(value, attribute);\n } else {\n acc[key] = value;\n }\n\n return acc;\n }, {});\n };\n\n return traverse(data, schema.attributes);\n };\n\n/* -------------------------------------------------------------------------------------------------\n * removeProhibitedFields\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal Removes all the fields that are not allowed.\n */\nconst removeProhibitedFields = (prohibitedFields: Schema.Attribute.Kind[]) =>\n traverseData(\n (attribute) => prohibitedFields.includes(attribute.type),\n () => ''\n );\n\n/* -------------------------------------------------------------------------------------------------\n * prepareRelations\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Sets all relation values to an empty array.\n */\nconst prepareRelations = traverseData(\n (attribute) => attribute.type === 'relation',\n () => ({\n connect: [],\n disconnect: [],\n })\n);\n\n/* -------------------------------------------------------------------------------------------------\n * prepareTempKeys\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Adds a `__temp_key__` to each component and dynamiczone item. This gives us\n * a stable identifier regardless of its ids etc. that we can then use for drag and drop.\n */\nconst prepareTempKeys = traverseData(\n (attribute) =>\n (attribute.type === 'component' && attribute.repeatable) || attribute.type === 'dynamiczone',\n (data) => {\n if (Array.isArray(data) && data.length > 0) {\n const keys = generateNKeysBetween(undefined, undefined, data.length);\n\n return data.map((datum, index) => ({\n ...datum,\n __temp_key__: keys[index],\n }));\n }\n\n return data;\n }\n);\n\n/* -------------------------------------------------------------------------------------------------\n * removeFieldsThatDontExistOnSchema\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Fields that don't exist in the schema like createdAt etc. are only on the first level (not nested),\n * as such we don't need to traverse the components to remove them.\n */\nconst removeFieldsThatDontExistOnSchema = (schema: PartialSchema) => (data: AnyData) => {\n const schemaKeys = Object.keys(schema.attributes);\n const dataKeys = Object.keys(data);\n\n const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));\n\n const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {\n delete acc[key];\n\n return acc;\n }, structuredClone(data));\n\n return revisedData;\n};\n\n/**\n * @internal\n * @description We need to remove null fields from the data-structure because it will pass it\n * to the specific inputs breaking them as most would prefer empty strings or `undefined` if\n * they're controlled / uncontrolled. However, Boolean fields should preserve null values.\n */\nconst removeNullValues = (schema: PartialSchema, components: ComponentsDictionary = {}) =>\n traverseData(\n (attribute, value) => value === null && attribute.type !== 'boolean',\n () => undefined\n )(schema, components);\n\n/* -------------------------------------------------------------------------------------------------\n * transformDocuments\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * @internal\n * @description Takes a document data structure (this could be from the API or a default form structure)\n * and applies consistent data transformations to it. This is also used when we add new components to the\n * form to ensure the data is correctly prepared from their default state e.g. relations are set to an empty array.\n */\nconst transformDocument =\n (schema: PartialSchema, components: ComponentsDictionary = {}) =>\n (document: AnyData) => {\n const transformations = pipe(\n removeFieldsThatDontExistOnSchema(schema),\n removeProhibitedFields(['password'])(schema, components),\n removeNullValues(schema, components),\n prepareRelations(schema, components),\n prepareTempKeys(schema, components)\n );\n\n return transformations(document);\n };\n\ntype HandleOptions = {\n schema?: Schema.ContentType | Schema.Component;\n initialValues?: AnyData;\n components?: Record<string, Schema.Component>;\n};\n\ntype RemovedFieldPath = string;\n\n/**\n * @internal\n * @description Finds the initial value for a component or dynamic zone item (based on its __temp_key__ and not its index).\n * @param initialValue - The initial values object.\n * @param item - The item to find the initial value for.\n * @returns The initial value for the item.\n */\nconst getItemInitialValue = (initialValue: AnyData, item: AnyData) => {\n if (initialValue && Array.isArray(initialValue)) {\n const matchingInitialItem = initialValue.find(\n (initialItem) => initialItem.__temp_key__ === item.__temp_key__\n );\n if (matchingInitialItem) {\n return matchingInitialItem;\n }\n }\n return {};\n};\n\n/**\n * @internal\n * @description Collects paths of attributes that should be removed based on visibility conditions.\n * This function only evaluates conditions.visible (JSON Logic), not the visible boolean property.\n *\n * @param data - The data object to evaluate\n * @param schema - The content type schema\n * @param components - Dictionary of component schemas\n * @param path - Current path in the data structure (for nested components/dynamiczones)\n * @returns Array of field paths that should be removed\n */\nconst collectInvisibleAttributes = (\n data: AnyData,\n schema: Schema.ContentType | Schema.Component | undefined,\n components: Record<string, Schema.Component>,\n path: string[] = []\n): RemovedFieldPath[] => {\n if (!schema?.attributes) return [];\n\n const rulesEngine = createRulesEngine();\n const removedPaths: RemovedFieldPath[] = [];\n const evaluatedData: AnyData = {};\n\n for (const [attrName, attrDef] of Object.entries(schema.attributes)) {\n const fullPath = [...path, attrName].join('.');\n\n // Skip fields with visible: false - they're managed by backend\n if ('visible' in attrDef && attrDef.visible === false) {\n continue;\n }\n\n const condition = attrDef?.conditions?.visible;\n const isVisible = condition\n ? rulesEngine.evaluate(condition, { ...data, ...evaluatedData })\n : true;\n\n if (!isVisible) {\n removedPaths.push(fullPath);\n continue;\n }\n\n // Track this field for future condition evaluations\n if (attrName in data) {\n evaluatedData[attrName] = data[attrName];\n }\n\n // Recursively process components\n if (attrDef.type === 'component') {\n const compSchema = components[attrDef.component];\n const value = data[attrName];\n\n if (attrDef.repeatable && Array.isArray(value)) {\n value.forEach((item) => {\n const nestedPaths = collectInvisibleAttributes(item, compSchema, components, [\n ...path,\n `${attrName}[${item.__temp_key__}]`,\n ]);\n removedPaths.push(...nestedPaths);\n });\n } else if (value && typeof value === 'object') {\n const nestedPaths = collectInvisibleAttributes(value, compSchema, components, [\n ...path,\n attrName,\n ]);\n removedPaths.push(...nestedPaths);\n }\n }\n\n // Recursively process dynamic zones\n if (attrDef.type === 'dynamiczone' && Array.isArray(data[attrName])) {\n data[attrName].forEach((dzItem: AnyData) => {\n const compUID = dzItem?.__component;\n const compSchema = components[compUID];\n const nestedPaths = collectInvisibleAttributes(dzItem, compSchema, components, [\n ...path,\n `${attrName}[${dzItem.__temp_key__}]`,\n ]);\n removedPaths.push(...nestedPaths);\n });\n }\n }\n\n return removedPaths;\n};\n\n/**\n * @internal\n * @description Removes attributes from data based on the list of paths to remove.\n * Preserves fields with visible: false from data or initialValues.\n *\n * @param data - The data object to filter\n * @param initialValues - Initial values to fall back to\n * @param schema - The content type schema\n * @param components - Dictionary of component schemas\n * @param removedPaths - Array of field paths to remove\n * @param currentPath - Current path in the data structure\n * @returns Filtered data object\n */\nconst filterDataByRemovedPaths = (\n data: AnyData,\n initialValues: AnyData,\n schema: Schema.ContentType | Schema.Component | undefined,\n components: Record<string, Schema.Component>,\n removedPaths: RemovedFieldPath[],\n currentPath: string[] = []\n): AnyData => {\n if (!schema?.attributes) return data;\n\n const result: AnyData = {};\n\n for (const [attrName, attrDef] of Object.entries(schema.attributes)) {\n const fullPath = [...currentPath, attrName].join('.');\n\n // Check if this field should be removed\n if (removedPaths.includes(fullPath)) {\n continue;\n }\n\n // Handle fields with visible: false - preserve from data or initialValues\n if ('visible' in attrDef && attrDef.visible === false) {\n const userProvided = Object.hasOwn(data, attrName);\n if (userProvided) {\n result[attrName] = data[attrName];\n } else if (attrName in initialValues) {\n result[attrName] = initialValues[attrName];\n }\n continue;\n }\n\n const userProvided = Object.hasOwn(data, attrName);\n const currentValue = userProvided ? data[attrName] : undefined;\n const initialValue = initialValues?.[attrName];\n\n // Handle components\n if (attrDef.type === 'component') {\n const compSchema = components[attrDef.component];\n const value = currentValue === undefined ? initialValue : currentValue;\n\n if (!value) {\n result[attrName] = attrDef.repeatable ? [] : null;\n continue;\n }\n\n if (attrDef.repeatable && Array.isArray(value)) {\n result[attrName] = value.map((item) => {\n const componentInitialValue = getItemInitialValue(initialValue, item);\n return filterDataByRemovedPaths(\n item,\n componentInitialValue,\n compSchema,\n components,\n removedPaths,\n [...currentPath, `${attrName}[${item.__temp_key__}]`]\n );\n });\n } else {\n result[attrName] = filterDataByRemovedPaths(\n value,\n initialValue ?? {},\n compSchema,\n components,\n removedPaths,\n [...currentPath, attrName]\n );\n }\n\n continue;\n }\n\n // Handle dynamic zones\n if (attrDef.type === 'dynamiczone') {\n if (!Array.isArray(currentValue)) {\n result[attrName] = [];\n continue;\n }\n\n result[attrName] = currentValue.map((dzItem) => {\n const compUID = dzItem?.__component;\n const compSchema = components[compUID];\n const componentInitialValue = getItemInitialValue(initialValue, dzItem);\n\n const cleaned = filterDataByRemovedPaths(\n dzItem,\n componentInitialValue,\n compSchema,\n components,\n removedPaths,\n [...currentPath, `${attrName}[${dzItem.__temp_key__}]`]\n );\n\n // For newly created components, ensure id is undefined (in case of reordering)\n const processedItem =\n dzItem.id === undefined || dzItem.id === null\n ? { __component: compUID, ...cleaned, id: undefined }\n : { __component: compUID, ...cleaned };\n\n return processedItem;\n });\n\n continue;\n }\n\n // Regular fields - preserve from data or initialValues\n if (currentValue !== undefined) {\n result[attrName] = currentValue;\n } else if (initialValue !== undefined) {\n result[attrName] = initialValue;\n }\n }\n\n // Pass through any fields from data that aren't in the schema\n for (const [key, value] of Object.entries(data)) {\n if (!(key in result) && !(key in (schema?.attributes || {}))) {\n result[key] = value;\n }\n }\n\n return result;\n};\n\n/**\n * Removes values from the data object if their corresponding attribute has a\n * visibility condition that evaluates to false.\n *\n * @param data - The data object to filter based on visibility\n * @param options - Schema, initialValues, and components\n * @returns Object with filtered data and list of removed attribute paths\n */\nconst handleInvisibleAttributes = (\n data: AnyData,\n { schema, initialValues = {}, components = {} }: HandleOptions\n): {\n data: AnyData;\n removedAttributes: RemovedFieldPath[];\n} => {\n if (!schema?.attributes) return { data, removedAttributes: [] };\n\n const removedAttributes = collectInvisibleAttributes(data, schema, components);\n\n const filteredData = filterDataByRemovedPaths(\n data,\n initialValues,\n schema,\n components,\n removedAttributes\n );\n\n return {\n data: filteredData,\n removedAttributes,\n };\n};\n\nexport {\n removeProhibitedFields,\n prepareRelations,\n prepareTempKeys,\n removeFieldsThatDontExistOnSchema,\n transformDocument,\n handleInvisibleAttributes,\n};\nexport type { AnyData };\n"],"names":["BLOCK_LIST_ATTRIBUTE_KEYS","traverseData","predicate","transform","schema","components","data","traverse","datum","attributes","Object","entries","reduce","acc","key","value","attribute","includes","undefined","type","repeatable","componentValue","map","componentData","component","dynamicZoneValue","__component","removeProhibitedFields","prohibitedFields","prepareRelations","connect","disconnect","prepareTempKeys","Array","isArray","length","keys","generateNKeysBetween","index","__temp_key__","removeFieldsThatDontExistOnSchema","schemaKeys","dataKeys","keysToRemove","filter","revisedData","DOCUMENT_META_FIELDS","structuredClone","removeNullValues","transformDocument","document","transformations","pipe","getItemInitialValue","initialValue","item","matchingInitialItem","find","initialItem","collectInvisibleAttributes","path","rulesEngine","createRulesEngine","removedPaths","evaluatedData","attrName","attrDef","fullPath","join","visible","condition","conditions","isVisible","evaluate","push","compSchema","forEach","nestedPaths","dzItem","compUID","filterDataByRemovedPaths","initialValues","currentPath","result","userProvided","hasOwn","currentValue","componentInitialValue","cleaned","processedItem","id","handleInvisibleAttributes","removedAttributes","filteredData"],"mappings":"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"}
@@ -102,16 +102,8 @@ const BLOCK_LIST_ATTRIBUTE_KEYS = [
102
102
  * @internal
103
103
  * @description We need to remove null fields from the data-structure because it will pass it
104
104
  * to the specific inputs breaking them as most would prefer empty strings or `undefined` if
105
- * they're controlled / uncontrolled.
106
- */ const removeNullValues = (data)=>{
107
- return Object.entries(data).reduce((acc, [key, value])=>{
108
- if (value === null) {
109
- return acc;
110
- }
111
- acc[key] = value;
112
- return acc;
113
- }, {});
114
- };
105
+ * they're controlled / uncontrolled. However, Boolean fields should preserve null values.
106
+ */ const removeNullValues = (schema, components = {})=>traverseData((attribute, value)=>value === null && attribute.type !== 'boolean', ()=>undefined)(schema, components);
115
107
  /* -------------------------------------------------------------------------------------------------
116
108
  * transformDocuments
117
109
  * -----------------------------------------------------------------------------------------------*/ /**
@@ -122,7 +114,7 @@ const BLOCK_LIST_ATTRIBUTE_KEYS = [
122
114
  */ const transformDocument = (schema, components = {})=>(document)=>{
123
115
  const transformations = pipe(removeFieldsThatDontExistOnSchema(schema), removeProhibitedFields([
124
116
  'password'
125
- ])(schema, components), removeNullValues, prepareRelations(schema, components), prepareTempKeys(schema, components));
117
+ ])(schema, components), removeNullValues(schema, components), prepareRelations(schema, components), prepareTempKeys(schema, components));
126
118
  return transformations(document);
127
119
  };
128
120
  /**