@strapi/content-manager 5.23.4 → 5.23.6

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.
@@ -4,6 +4,7 @@ var jsxRuntime = require('react/jsx-runtime');
4
4
  var React = require('react');
5
5
  var strapiAdmin = require('@strapi/admin/strapi-admin');
6
6
  var designSystem = require('@strapi/design-system');
7
+ var reactIntl = require('react-intl');
7
8
  var InputRenderer = require('../../pages/EditView/components/InputRenderer.js');
8
9
  var Preview = require('../pages/Preview.js');
9
10
  var constants = require('../utils/constants.js');
@@ -44,6 +45,7 @@ function useHasInputPopoverParent() {
44
45
  const schema = Preview.usePreviewContext('InputPopover', (state)=>state.schema);
45
46
  const components = Preview.usePreviewContext('InputPopover', (state)=>state.components);
46
47
  const { toggleNotification } = strapiAdmin.useNotification();
48
+ const { formatMessage } = reactIntl.useIntl();
47
49
  React__namespace.useEffect(()=>{
48
50
  /**
49
51
  * We receive window events sent from the user's preview via the injected script.
@@ -58,11 +60,11 @@ function useHasInputPopoverParent() {
58
60
  }
59
61
  if (event.data?.type === constants.INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT) {
60
62
  const fieldMetaData = fieldUtils.parseFieldMetaData(event.data.payload.path);
61
- // TODO: check if notification better
62
63
  if (!fieldMetaData) {
64
+ const { type, message } = constants.PREVIEW_ERROR_MESSAGES.INCOMPLETE_STRAPI_SOURCE;
63
65
  toggleNotification({
64
- type: 'warning',
65
- message: 'Incomplete strapiSource attribute'
66
+ type,
67
+ message: formatMessage(message)
66
68
  });
67
69
  return;
68
70
  }
@@ -71,9 +73,10 @@ function useHasInputPopoverParent() {
71
73
  * current document. This doesn't do anything about fields that may come from relations to
72
74
  * the current document however.
73
75
  */ if (fieldMetaData.documentId !== document.documentId) {
76
+ const { type, message } = constants.PREVIEW_ERROR_MESSAGES.DIFFERENT_DOCUMENT;
74
77
  toggleNotification({
75
- type: 'warning',
76
- message: 'This field comes from a different document'
78
+ type,
79
+ message: formatMessage(message)
77
80
  });
78
81
  return;
79
82
  }
@@ -91,14 +94,29 @@ function useHasInputPopoverParent() {
91
94
  attribute
92
95
  });
93
96
  } catch (error) {
94
- if (error instanceof Error) {
97
+ if (error instanceof fieldUtils.PreviewFieldError) {
98
+ const { type, message } = constants.PREVIEW_ERROR_MESSAGES[error.messageKey];
95
99
  toggleNotification({
96
- type: 'warning',
100
+ type,
101
+ message: formatMessage(message)
102
+ });
103
+ } else if (error instanceof Error) {
104
+ toggleNotification({
105
+ type: 'danger',
97
106
  message: error.message
98
107
  });
99
108
  }
100
109
  }
101
110
  }
111
+ if (event.data?.type === constants.INTERNAL_EVENTS.STRAPI_FIELD_SINGLE_CLICK_HINT) {
112
+ toggleNotification({
113
+ type: 'info',
114
+ message: formatMessage({
115
+ id: 'content-manager.preview.info.single-click-hint',
116
+ defaultMessage: 'Double click to edit'
117
+ })
118
+ });
119
+ }
102
120
  };
103
121
  window.addEventListener('message', handleMessage);
104
122
  return ()=>{
@@ -110,7 +128,8 @@ function useHasInputPopoverParent() {
110
128
  iframeRef,
111
129
  schema,
112
130
  setPopoverField,
113
- toggleNotification
131
+ toggleNotification,
132
+ formatMessage
114
133
  ]);
115
134
  if (!popoverField || !iframeRef.current) {
116
135
  return null;
@@ -124,7 +143,8 @@ function useHasInputPopoverParent() {
124
143
  left: iframeRect.left + 'px',
125
144
  width: iframeRect.width + 'px',
126
145
  height: iframeRect.height + 'px',
127
- zIndex: 4
146
+ zIndex: 4,
147
+ onClick: ()=>iframeRef.current?.focus()
128
148
  }),
129
149
  /*#__PURE__*/ jsxRuntime.jsx(InputPopoverProvider, {
130
150
  children: /*#__PURE__*/ jsxRuntime.jsxs(designSystem.Popover.Root, {
@@ -1 +1 @@
1
- {"version":3,"file":"InputPopover.js","sources":["../../../../admin/src/preview/components/InputPopover.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { createContext, useNotification } from '@strapi/admin/strapi-admin';\nimport { Box, Popover } from '@strapi/design-system';\n\nimport { type UseDocument } from '../../hooks/useDocument';\nimport { InputRenderer } from '../../pages/EditView/components/InputRenderer';\nimport { usePreviewContext } from '../pages/Preview';\nimport { INTERNAL_EVENTS } from '../utils/constants';\nimport { parseFieldMetaData, getAttributeSchemaFromPath } from '../utils/fieldUtils';\n\n/* -------------------------------------------------------------------------------------------------\n * Context utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * No need for actual data in the context. It's just to let children check if they're rendered\n * inside of a preview InputPopover without relying on prop drilling.\n */\ninterface InputPopoverContextValue {}\n\nconst [InputPopoverProvider, useInputPopoverContext] =\n createContext<InputPopoverContextValue>('InputPopover');\n\nfunction useHasInputPopoverParent() {\n const context = useInputPopoverContext('useHasInputPopoverParent', () => true, false);\n\n // useContext will return undefined if the called is not wrapped in the provider\n return context !== undefined;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * InputPopover\n * -----------------------------------------------------------------------------------------------*/\n\nconst InputPopover = ({ documentResponse }: { documentResponse: ReturnType<UseDocument> }) => {\n const iframeRef = usePreviewContext('InputPopover', (state) => state.iframeRef);\n const popoverField = usePreviewContext('InputPopover', (state) => state.popoverField);\n const setPopoverField = usePreviewContext('InputPopover', (state) => state.setPopoverField);\n const document = usePreviewContext('InputPopover', (state) => state.document);\n const schema = usePreviewContext('InputPopover', (state) => state.schema);\n const components = usePreviewContext('InputPopover', (state) => state.components);\n const { toggleNotification } = useNotification();\n\n React.useEffect(() => {\n /**\n * We receive window events sent from the user's preview via the injected script.\n * We listen to the ones here that target a specific field.\n */\n const handleMessage = (event: MessageEvent) => {\n // Only listen to events from the preview iframe\n if (iframeRef.current) {\n const previewOrigin = new URL(iframeRef.current?.src).origin;\n if (event.origin !== previewOrigin) {\n return;\n }\n }\n\n if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT) {\n const fieldMetaData = parseFieldMetaData(event.data.payload.path);\n\n // TODO: check if notification better\n if (!fieldMetaData) {\n toggleNotification({\n type: 'warning',\n message: 'Incomplete strapiSource attribute',\n });\n return;\n }\n\n /**\n * Ignore (for now) content that comes from separate API requests than the one for the\n * current document. This doesn't do anything about fields that may come from relations to\n * the current document however.\n */\n if (fieldMetaData.documentId !== document.documentId) {\n toggleNotification({\n type: 'warning',\n message: 'This field comes from a different document',\n });\n return;\n }\n\n try {\n const attribute = getAttributeSchemaFromPath({\n path: fieldMetaData.path,\n components,\n schema,\n document,\n });\n\n // We're able to handle the field, set it in context so the popover can pick it up\n setPopoverField({ ...fieldMetaData, position: event.data.payload.position, attribute });\n } catch (error) {\n if (error instanceof Error) {\n toggleNotification({ type: 'warning', message: error.message });\n }\n }\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [components, document, iframeRef, schema, setPopoverField, toggleNotification]);\n if (!popoverField || !iframeRef.current) {\n return null;\n }\n\n const iframeRect = iframeRef.current.getBoundingClientRect();\n\n return (\n <>\n {/**\n * Overlay an empty div on top of the iframe while the popover is open so it can\n * intercept clicks. Without it, we wouldn't be able to close the popover by clicking outside,\n * because the click would be detected by the iframe window, not by the admin.\n **/}\n <Box\n position={'fixed'}\n top={iframeRect.top + 'px'}\n left={iframeRect.left + 'px'}\n width={iframeRect.width + 'px'}\n height={iframeRect.height + 'px'}\n zIndex={4}\n />\n <InputPopoverProvider>\n <Popover.Root open={true} onOpenChange={(open) => !open && setPopoverField(null)}>\n <Popover.Trigger>\n <Box\n position=\"fixed\"\n width={popoverField.position.width + 'px'}\n height={popoverField.position.height + 'px'}\n top={0}\n left={0}\n transform={`translate(${iframeRect.left + popoverField.position.left}px, ${iframeRect.top + popoverField.position.top}px)`}\n />\n </Popover.Trigger>\n <Popover.Content sideOffset={4}>\n <Box padding={4} width=\"400px\">\n {/* @ts-expect-error the types of `attribute` clash for some reason */}\n <InputRenderer\n document={documentResponse}\n attribute={popoverField.attribute}\n // TODO: retrieve the proper label from the layout\n label={popoverField.path}\n name={popoverField.path}\n type={popoverField.attribute.type}\n visible={true}\n />\n </Box>\n </Popover.Content>\n </Popover.Root>\n </InputPopoverProvider>\n </>\n );\n};\n\nexport { InputPopover, useHasInputPopoverParent };\n"],"names":["InputPopoverProvider","useInputPopoverContext","createContext","useHasInputPopoverParent","context","undefined","InputPopover","documentResponse","iframeRef","usePreviewContext","state","popoverField","setPopoverField","document","schema","components","toggleNotification","useNotification","React","useEffect","handleMessage","event","current","previewOrigin","URL","src","origin","data","type","INTERNAL_EVENTS","STRAPI_FIELD_FOCUS_INTENT","fieldMetaData","parseFieldMetaData","payload","path","message","documentId","attribute","getAttributeSchemaFromPath","position","error","Error","window","addEventListener","removeEventListener","iframeRect","getBoundingClientRect","_jsxs","_Fragment","_jsx","Box","top","left","width","height","zIndex","Popover","Root","open","onOpenChange","Trigger","transform","Content","sideOffset","padding","InputRenderer","label","name","visible"],"mappings":"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"}
1
+ {"version":3,"file":"InputPopover.js","sources":["../../../../admin/src/preview/components/InputPopover.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { createContext, useNotification } from '@strapi/admin/strapi-admin';\nimport { Box, Popover } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { type UseDocument } from '../../hooks/useDocument';\nimport { InputRenderer } from '../../pages/EditView/components/InputRenderer';\nimport { usePreviewContext } from '../pages/Preview';\nimport { INTERNAL_EVENTS, PREVIEW_ERROR_MESSAGES } from '../utils/constants';\nimport {\n parseFieldMetaData,\n getAttributeSchemaFromPath,\n PreviewFieldError,\n} from '../utils/fieldUtils';\n\n/* -------------------------------------------------------------------------------------------------\n * Context utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * No need for actual data in the context. It's just to let children check if they're rendered\n * inside of a preview InputPopover without relying on prop drilling.\n */\ninterface InputPopoverContextValue {}\n\nconst [InputPopoverProvider, useInputPopoverContext] =\n createContext<InputPopoverContextValue>('InputPopover');\n\nfunction useHasInputPopoverParent() {\n const context = useInputPopoverContext('useHasInputPopoverParent', () => true, false);\n\n // useContext will return undefined if the called is not wrapped in the provider\n return context !== undefined;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * InputPopover\n * -----------------------------------------------------------------------------------------------*/\n\nconst InputPopover = ({ documentResponse }: { documentResponse: ReturnType<UseDocument> }) => {\n const iframeRef = usePreviewContext('InputPopover', (state) => state.iframeRef);\n const popoverField = usePreviewContext('InputPopover', (state) => state.popoverField);\n const setPopoverField = usePreviewContext('InputPopover', (state) => state.setPopoverField);\n const document = usePreviewContext('InputPopover', (state) => state.document);\n const schema = usePreviewContext('InputPopover', (state) => state.schema);\n const components = usePreviewContext('InputPopover', (state) => state.components);\n\n const { toggleNotification } = useNotification();\n const { formatMessage } = useIntl();\n\n React.useEffect(() => {\n /**\n * We receive window events sent from the user's preview via the injected script.\n * We listen to the ones here that target a specific field.\n */\n const handleMessage = (event: MessageEvent) => {\n // Only listen to events from the preview iframe\n if (iframeRef.current) {\n const previewOrigin = new URL(iframeRef.current?.src).origin;\n if (event.origin !== previewOrigin) {\n return;\n }\n }\n\n if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT) {\n const fieldMetaData = parseFieldMetaData(event.data.payload.path);\n\n if (!fieldMetaData) {\n const { type, message } = PREVIEW_ERROR_MESSAGES.INCOMPLETE_STRAPI_SOURCE;\n toggleNotification({ type, message: formatMessage(message) });\n return;\n }\n\n /**\n * Ignore (for now) content that comes from separate API requests than the one for the\n * current document. This doesn't do anything about fields that may come from relations to\n * the current document however.\n */\n if (fieldMetaData.documentId !== document.documentId) {\n const { type, message } = PREVIEW_ERROR_MESSAGES.DIFFERENT_DOCUMENT;\n toggleNotification({ type, message: formatMessage(message) });\n return;\n }\n\n try {\n const attribute = getAttributeSchemaFromPath({\n path: fieldMetaData.path,\n components,\n schema,\n document,\n });\n\n // We're able to handle the field, set it in context so the popover can pick it up\n setPopoverField({ ...fieldMetaData, position: event.data.payload.position, attribute });\n } catch (error) {\n if (error instanceof PreviewFieldError) {\n const { type, message } = PREVIEW_ERROR_MESSAGES[error.messageKey];\n toggleNotification({ type, message: formatMessage(message) });\n } else if (error instanceof Error) {\n toggleNotification({ type: 'danger', message: error.message });\n }\n }\n }\n\n if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_SINGLE_CLICK_HINT) {\n toggleNotification({\n type: 'info',\n message: formatMessage({\n id: 'content-manager.preview.info.single-click-hint',\n defaultMessage: 'Double click to edit',\n }),\n });\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [components, document, iframeRef, schema, setPopoverField, toggleNotification, formatMessage]);\n if (!popoverField || !iframeRef.current) {\n return null;\n }\n\n const iframeRect = iframeRef.current.getBoundingClientRect();\n\n return (\n <>\n {/**\n * Overlay an empty div on top of the iframe while the popover is open so it can\n * intercept clicks. Without it, we wouldn't be able to close the popover by clicking outside,\n * because the click would be detected by the iframe window, not by the admin.\n **/}\n <Box\n position={'fixed'}\n top={iframeRect.top + 'px'}\n left={iframeRect.left + 'px'}\n width={iframeRect.width + 'px'}\n height={iframeRect.height + 'px'}\n zIndex={4}\n onClick={() => iframeRef.current?.focus()}\n />\n <InputPopoverProvider>\n <Popover.Root open={true} onOpenChange={(open) => !open && setPopoverField(null)}>\n <Popover.Trigger>\n <Box\n position=\"fixed\"\n width={popoverField.position.width + 'px'}\n height={popoverField.position.height + 'px'}\n top={0}\n left={0}\n transform={`translate(${iframeRect.left + popoverField.position.left}px, ${iframeRect.top + popoverField.position.top}px)`}\n />\n </Popover.Trigger>\n <Popover.Content sideOffset={4}>\n <Box padding={4} width=\"400px\">\n {/* @ts-expect-error the types of `attribute` clash for some reason */}\n <InputRenderer\n document={documentResponse}\n attribute={popoverField.attribute}\n // TODO: retrieve the proper label from the layout\n label={popoverField.path}\n name={popoverField.path}\n type={popoverField.attribute.type}\n visible={true}\n />\n </Box>\n </Popover.Content>\n </Popover.Root>\n </InputPopoverProvider>\n </>\n );\n};\n\nexport { InputPopover, useHasInputPopoverParent };\n"],"names":["InputPopoverProvider","useInputPopoverContext","createContext","useHasInputPopoverParent","context","undefined","InputPopover","documentResponse","iframeRef","usePreviewContext","state","popoverField","setPopoverField","document","schema","components","toggleNotification","useNotification","formatMessage","useIntl","React","useEffect","handleMessage","event","current","previewOrigin","URL","src","origin","data","type","INTERNAL_EVENTS","STRAPI_FIELD_FOCUS_INTENT","fieldMetaData","parseFieldMetaData","payload","path","message","PREVIEW_ERROR_MESSAGES","INCOMPLETE_STRAPI_SOURCE","documentId","DIFFERENT_DOCUMENT","attribute","getAttributeSchemaFromPath","position","error","PreviewFieldError","messageKey","Error","STRAPI_FIELD_SINGLE_CLICK_HINT","id","defaultMessage","window","addEventListener","removeEventListener","iframeRect","getBoundingClientRect","_jsxs","_Fragment","_jsx","Box","top","left","width","height","zIndex","onClick","focus","Popover","Root","open","onOpenChange","Trigger","transform","Content","sideOffset","padding","InputRenderer","label","name","visible"],"mappings":"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"}
@@ -2,10 +2,11 @@ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { createContext, useNotification } from '@strapi/admin/strapi-admin';
4
4
  import { Box, Popover } from '@strapi/design-system';
5
+ import { useIntl } from 'react-intl';
5
6
  import { InputRenderer as MemoizedInputRenderer } from '../../pages/EditView/components/InputRenderer.mjs';
6
7
  import { usePreviewContext } from '../pages/Preview.mjs';
7
- import { INTERNAL_EVENTS } from '../utils/constants.mjs';
8
- import { parseFieldMetaData, getAttributeSchemaFromPath } from '../utils/fieldUtils.mjs';
8
+ import { INTERNAL_EVENTS, PREVIEW_ERROR_MESSAGES } from '../utils/constants.mjs';
9
+ import { parseFieldMetaData, getAttributeSchemaFromPath, PreviewFieldError } from '../utils/fieldUtils.mjs';
9
10
 
10
11
  const [InputPopoverProvider, useInputPopoverContext] = createContext('InputPopover');
11
12
  function useHasInputPopoverParent() {
@@ -23,6 +24,7 @@ function useHasInputPopoverParent() {
23
24
  const schema = usePreviewContext('InputPopover', (state)=>state.schema);
24
25
  const components = usePreviewContext('InputPopover', (state)=>state.components);
25
26
  const { toggleNotification } = useNotification();
27
+ const { formatMessage } = useIntl();
26
28
  React.useEffect(()=>{
27
29
  /**
28
30
  * We receive window events sent from the user's preview via the injected script.
@@ -37,11 +39,11 @@ function useHasInputPopoverParent() {
37
39
  }
38
40
  if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT) {
39
41
  const fieldMetaData = parseFieldMetaData(event.data.payload.path);
40
- // TODO: check if notification better
41
42
  if (!fieldMetaData) {
43
+ const { type, message } = PREVIEW_ERROR_MESSAGES.INCOMPLETE_STRAPI_SOURCE;
42
44
  toggleNotification({
43
- type: 'warning',
44
- message: 'Incomplete strapiSource attribute'
45
+ type,
46
+ message: formatMessage(message)
45
47
  });
46
48
  return;
47
49
  }
@@ -50,9 +52,10 @@ function useHasInputPopoverParent() {
50
52
  * current document. This doesn't do anything about fields that may come from relations to
51
53
  * the current document however.
52
54
  */ if (fieldMetaData.documentId !== document.documentId) {
55
+ const { type, message } = PREVIEW_ERROR_MESSAGES.DIFFERENT_DOCUMENT;
53
56
  toggleNotification({
54
- type: 'warning',
55
- message: 'This field comes from a different document'
57
+ type,
58
+ message: formatMessage(message)
56
59
  });
57
60
  return;
58
61
  }
@@ -70,14 +73,29 @@ function useHasInputPopoverParent() {
70
73
  attribute
71
74
  });
72
75
  } catch (error) {
73
- if (error instanceof Error) {
76
+ if (error instanceof PreviewFieldError) {
77
+ const { type, message } = PREVIEW_ERROR_MESSAGES[error.messageKey];
74
78
  toggleNotification({
75
- type: 'warning',
79
+ type,
80
+ message: formatMessage(message)
81
+ });
82
+ } else if (error instanceof Error) {
83
+ toggleNotification({
84
+ type: 'danger',
76
85
  message: error.message
77
86
  });
78
87
  }
79
88
  }
80
89
  }
90
+ if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_SINGLE_CLICK_HINT) {
91
+ toggleNotification({
92
+ type: 'info',
93
+ message: formatMessage({
94
+ id: 'content-manager.preview.info.single-click-hint',
95
+ defaultMessage: 'Double click to edit'
96
+ })
97
+ });
98
+ }
81
99
  };
82
100
  window.addEventListener('message', handleMessage);
83
101
  return ()=>{
@@ -89,7 +107,8 @@ function useHasInputPopoverParent() {
89
107
  iframeRef,
90
108
  schema,
91
109
  setPopoverField,
92
- toggleNotification
110
+ toggleNotification,
111
+ formatMessage
93
112
  ]);
94
113
  if (!popoverField || !iframeRef.current) {
95
114
  return null;
@@ -103,7 +122,8 @@ function useHasInputPopoverParent() {
103
122
  left: iframeRect.left + 'px',
104
123
  width: iframeRect.width + 'px',
105
124
  height: iframeRect.height + 'px',
106
- zIndex: 4
125
+ zIndex: 4,
126
+ onClick: ()=>iframeRef.current?.focus()
107
127
  }),
108
128
  /*#__PURE__*/ jsx(InputPopoverProvider, {
109
129
  children: /*#__PURE__*/ jsxs(Popover.Root, {
@@ -1 +1 @@
1
- {"version":3,"file":"InputPopover.mjs","sources":["../../../../admin/src/preview/components/InputPopover.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { createContext, useNotification } from '@strapi/admin/strapi-admin';\nimport { Box, Popover } from '@strapi/design-system';\n\nimport { type UseDocument } from '../../hooks/useDocument';\nimport { InputRenderer } from '../../pages/EditView/components/InputRenderer';\nimport { usePreviewContext } from '../pages/Preview';\nimport { INTERNAL_EVENTS } from '../utils/constants';\nimport { parseFieldMetaData, getAttributeSchemaFromPath } from '../utils/fieldUtils';\n\n/* -------------------------------------------------------------------------------------------------\n * Context utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * No need for actual data in the context. It's just to let children check if they're rendered\n * inside of a preview InputPopover without relying on prop drilling.\n */\ninterface InputPopoverContextValue {}\n\nconst [InputPopoverProvider, useInputPopoverContext] =\n createContext<InputPopoverContextValue>('InputPopover');\n\nfunction useHasInputPopoverParent() {\n const context = useInputPopoverContext('useHasInputPopoverParent', () => true, false);\n\n // useContext will return undefined if the called is not wrapped in the provider\n return context !== undefined;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * InputPopover\n * -----------------------------------------------------------------------------------------------*/\n\nconst InputPopover = ({ documentResponse }: { documentResponse: ReturnType<UseDocument> }) => {\n const iframeRef = usePreviewContext('InputPopover', (state) => state.iframeRef);\n const popoverField = usePreviewContext('InputPopover', (state) => state.popoverField);\n const setPopoverField = usePreviewContext('InputPopover', (state) => state.setPopoverField);\n const document = usePreviewContext('InputPopover', (state) => state.document);\n const schema = usePreviewContext('InputPopover', (state) => state.schema);\n const components = usePreviewContext('InputPopover', (state) => state.components);\n const { toggleNotification } = useNotification();\n\n React.useEffect(() => {\n /**\n * We receive window events sent from the user's preview via the injected script.\n * We listen to the ones here that target a specific field.\n */\n const handleMessage = (event: MessageEvent) => {\n // Only listen to events from the preview iframe\n if (iframeRef.current) {\n const previewOrigin = new URL(iframeRef.current?.src).origin;\n if (event.origin !== previewOrigin) {\n return;\n }\n }\n\n if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT) {\n const fieldMetaData = parseFieldMetaData(event.data.payload.path);\n\n // TODO: check if notification better\n if (!fieldMetaData) {\n toggleNotification({\n type: 'warning',\n message: 'Incomplete strapiSource attribute',\n });\n return;\n }\n\n /**\n * Ignore (for now) content that comes from separate API requests than the one for the\n * current document. This doesn't do anything about fields that may come from relations to\n * the current document however.\n */\n if (fieldMetaData.documentId !== document.documentId) {\n toggleNotification({\n type: 'warning',\n message: 'This field comes from a different document',\n });\n return;\n }\n\n try {\n const attribute = getAttributeSchemaFromPath({\n path: fieldMetaData.path,\n components,\n schema,\n document,\n });\n\n // We're able to handle the field, set it in context so the popover can pick it up\n setPopoverField({ ...fieldMetaData, position: event.data.payload.position, attribute });\n } catch (error) {\n if (error instanceof Error) {\n toggleNotification({ type: 'warning', message: error.message });\n }\n }\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [components, document, iframeRef, schema, setPopoverField, toggleNotification]);\n if (!popoverField || !iframeRef.current) {\n return null;\n }\n\n const iframeRect = iframeRef.current.getBoundingClientRect();\n\n return (\n <>\n {/**\n * Overlay an empty div on top of the iframe while the popover is open so it can\n * intercept clicks. Without it, we wouldn't be able to close the popover by clicking outside,\n * because the click would be detected by the iframe window, not by the admin.\n **/}\n <Box\n position={'fixed'}\n top={iframeRect.top + 'px'}\n left={iframeRect.left + 'px'}\n width={iframeRect.width + 'px'}\n height={iframeRect.height + 'px'}\n zIndex={4}\n />\n <InputPopoverProvider>\n <Popover.Root open={true} onOpenChange={(open) => !open && setPopoverField(null)}>\n <Popover.Trigger>\n <Box\n position=\"fixed\"\n width={popoverField.position.width + 'px'}\n height={popoverField.position.height + 'px'}\n top={0}\n left={0}\n transform={`translate(${iframeRect.left + popoverField.position.left}px, ${iframeRect.top + popoverField.position.top}px)`}\n />\n </Popover.Trigger>\n <Popover.Content sideOffset={4}>\n <Box padding={4} width=\"400px\">\n {/* @ts-expect-error the types of `attribute` clash for some reason */}\n <InputRenderer\n document={documentResponse}\n attribute={popoverField.attribute}\n // TODO: retrieve the proper label from the layout\n label={popoverField.path}\n name={popoverField.path}\n type={popoverField.attribute.type}\n visible={true}\n />\n </Box>\n </Popover.Content>\n </Popover.Root>\n </InputPopoverProvider>\n </>\n );\n};\n\nexport { InputPopover, useHasInputPopoverParent };\n"],"names":["InputPopoverProvider","useInputPopoverContext","createContext","useHasInputPopoverParent","context","undefined","InputPopover","documentResponse","iframeRef","usePreviewContext","state","popoverField","setPopoverField","document","schema","components","toggleNotification","useNotification","React","useEffect","handleMessage","event","current","previewOrigin","URL","src","origin","data","type","INTERNAL_EVENTS","STRAPI_FIELD_FOCUS_INTENT","fieldMetaData","parseFieldMetaData","payload","path","message","documentId","attribute","getAttributeSchemaFromPath","position","error","Error","window","addEventListener","removeEventListener","iframeRect","getBoundingClientRect","_jsxs","_Fragment","_jsx","Box","top","left","width","height","zIndex","Popover","Root","open","onOpenChange","Trigger","transform","Content","sideOffset","padding","InputRenderer","label","name","visible"],"mappings":"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"}
1
+ {"version":3,"file":"InputPopover.mjs","sources":["../../../../admin/src/preview/components/InputPopover.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { createContext, useNotification } from '@strapi/admin/strapi-admin';\nimport { Box, Popover } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { type UseDocument } from '../../hooks/useDocument';\nimport { InputRenderer } from '../../pages/EditView/components/InputRenderer';\nimport { usePreviewContext } from '../pages/Preview';\nimport { INTERNAL_EVENTS, PREVIEW_ERROR_MESSAGES } from '../utils/constants';\nimport {\n parseFieldMetaData,\n getAttributeSchemaFromPath,\n PreviewFieldError,\n} from '../utils/fieldUtils';\n\n/* -------------------------------------------------------------------------------------------------\n * Context utils\n * -----------------------------------------------------------------------------------------------*/\n\n/**\n * No need for actual data in the context. It's just to let children check if they're rendered\n * inside of a preview InputPopover without relying on prop drilling.\n */\ninterface InputPopoverContextValue {}\n\nconst [InputPopoverProvider, useInputPopoverContext] =\n createContext<InputPopoverContextValue>('InputPopover');\n\nfunction useHasInputPopoverParent() {\n const context = useInputPopoverContext('useHasInputPopoverParent', () => true, false);\n\n // useContext will return undefined if the called is not wrapped in the provider\n return context !== undefined;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * InputPopover\n * -----------------------------------------------------------------------------------------------*/\n\nconst InputPopover = ({ documentResponse }: { documentResponse: ReturnType<UseDocument> }) => {\n const iframeRef = usePreviewContext('InputPopover', (state) => state.iframeRef);\n const popoverField = usePreviewContext('InputPopover', (state) => state.popoverField);\n const setPopoverField = usePreviewContext('InputPopover', (state) => state.setPopoverField);\n const document = usePreviewContext('InputPopover', (state) => state.document);\n const schema = usePreviewContext('InputPopover', (state) => state.schema);\n const components = usePreviewContext('InputPopover', (state) => state.components);\n\n const { toggleNotification } = useNotification();\n const { formatMessage } = useIntl();\n\n React.useEffect(() => {\n /**\n * We receive window events sent from the user's preview via the injected script.\n * We listen to the ones here that target a specific field.\n */\n const handleMessage = (event: MessageEvent) => {\n // Only listen to events from the preview iframe\n if (iframeRef.current) {\n const previewOrigin = new URL(iframeRef.current?.src).origin;\n if (event.origin !== previewOrigin) {\n return;\n }\n }\n\n if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT) {\n const fieldMetaData = parseFieldMetaData(event.data.payload.path);\n\n if (!fieldMetaData) {\n const { type, message } = PREVIEW_ERROR_MESSAGES.INCOMPLETE_STRAPI_SOURCE;\n toggleNotification({ type, message: formatMessage(message) });\n return;\n }\n\n /**\n * Ignore (for now) content that comes from separate API requests than the one for the\n * current document. This doesn't do anything about fields that may come from relations to\n * the current document however.\n */\n if (fieldMetaData.documentId !== document.documentId) {\n const { type, message } = PREVIEW_ERROR_MESSAGES.DIFFERENT_DOCUMENT;\n toggleNotification({ type, message: formatMessage(message) });\n return;\n }\n\n try {\n const attribute = getAttributeSchemaFromPath({\n path: fieldMetaData.path,\n components,\n schema,\n document,\n });\n\n // We're able to handle the field, set it in context so the popover can pick it up\n setPopoverField({ ...fieldMetaData, position: event.data.payload.position, attribute });\n } catch (error) {\n if (error instanceof PreviewFieldError) {\n const { type, message } = PREVIEW_ERROR_MESSAGES[error.messageKey];\n toggleNotification({ type, message: formatMessage(message) });\n } else if (error instanceof Error) {\n toggleNotification({ type: 'danger', message: error.message });\n }\n }\n }\n\n if (event.data?.type === INTERNAL_EVENTS.STRAPI_FIELD_SINGLE_CLICK_HINT) {\n toggleNotification({\n type: 'info',\n message: formatMessage({\n id: 'content-manager.preview.info.single-click-hint',\n defaultMessage: 'Double click to edit',\n }),\n });\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n return () => {\n window.removeEventListener('message', handleMessage);\n };\n }, [components, document, iframeRef, schema, setPopoverField, toggleNotification, formatMessage]);\n if (!popoverField || !iframeRef.current) {\n return null;\n }\n\n const iframeRect = iframeRef.current.getBoundingClientRect();\n\n return (\n <>\n {/**\n * Overlay an empty div on top of the iframe while the popover is open so it can\n * intercept clicks. Without it, we wouldn't be able to close the popover by clicking outside,\n * because the click would be detected by the iframe window, not by the admin.\n **/}\n <Box\n position={'fixed'}\n top={iframeRect.top + 'px'}\n left={iframeRect.left + 'px'}\n width={iframeRect.width + 'px'}\n height={iframeRect.height + 'px'}\n zIndex={4}\n onClick={() => iframeRef.current?.focus()}\n />\n <InputPopoverProvider>\n <Popover.Root open={true} onOpenChange={(open) => !open && setPopoverField(null)}>\n <Popover.Trigger>\n <Box\n position=\"fixed\"\n width={popoverField.position.width + 'px'}\n height={popoverField.position.height + 'px'}\n top={0}\n left={0}\n transform={`translate(${iframeRect.left + popoverField.position.left}px, ${iframeRect.top + popoverField.position.top}px)`}\n />\n </Popover.Trigger>\n <Popover.Content sideOffset={4}>\n <Box padding={4} width=\"400px\">\n {/* @ts-expect-error the types of `attribute` clash for some reason */}\n <InputRenderer\n document={documentResponse}\n attribute={popoverField.attribute}\n // TODO: retrieve the proper label from the layout\n label={popoverField.path}\n name={popoverField.path}\n type={popoverField.attribute.type}\n visible={true}\n />\n </Box>\n </Popover.Content>\n </Popover.Root>\n </InputPopoverProvider>\n </>\n );\n};\n\nexport { InputPopover, useHasInputPopoverParent };\n"],"names":["InputPopoverProvider","useInputPopoverContext","createContext","useHasInputPopoverParent","context","undefined","InputPopover","documentResponse","iframeRef","usePreviewContext","state","popoverField","setPopoverField","document","schema","components","toggleNotification","useNotification","formatMessage","useIntl","React","useEffect","handleMessage","event","current","previewOrigin","URL","src","origin","data","type","INTERNAL_EVENTS","STRAPI_FIELD_FOCUS_INTENT","fieldMetaData","parseFieldMetaData","payload","path","message","PREVIEW_ERROR_MESSAGES","INCOMPLETE_STRAPI_SOURCE","documentId","DIFFERENT_DOCUMENT","attribute","getAttributeSchemaFromPath","position","error","PreviewFieldError","messageKey","Error","STRAPI_FIELD_SINGLE_CLICK_HINT","id","defaultMessage","window","addEventListener","removeEventListener","iframeRect","getBoundingClientRect","_jsxs","_Fragment","_jsx","Box","top","left","width","height","zIndex","onClick","focus","Popover","Root","open","onOpenChange","Trigger","transform","Content","sideOffset","padding","InputRenderer","label","name","visible"],"mappings":"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"}
@@ -16,7 +16,41 @@ const scriptResponse = previewScript.previewScript(false);
16
16
  STRAPI_UPDATE: 'strapiUpdate',
17
17
  STRAPI_SCRIPT: 'strapiScript'
18
18
  };
19
+ /**
20
+ * Error messages for preview field operations.
21
+ * This information is used to trigger notifications.
22
+ */ const PREVIEW_ERROR_MESSAGES = {
23
+ INVALID_FIELD_PATH: {
24
+ type: 'danger',
25
+ message: {
26
+ id: 'content-manager.preview.error.invalid-field-path',
27
+ defaultMessage: 'Could not locate this field in the current document'
28
+ }
29
+ },
30
+ RELATIONS_NOT_HANDLED: {
31
+ type: 'info',
32
+ message: {
33
+ id: 'content-manager.preview.error.relations-not-handled',
34
+ defaultMessage: 'Inline editing for relations is not currently supported.'
35
+ }
36
+ },
37
+ INCOMPLETE_STRAPI_SOURCE: {
38
+ type: 'danger',
39
+ message: {
40
+ id: 'content-manager.preview.error.incomplete-strapi-source',
41
+ defaultMessage: 'This field is missing some required preview information'
42
+ }
43
+ },
44
+ DIFFERENT_DOCUMENT: {
45
+ type: 'info',
46
+ message: {
47
+ id: 'content-manager.preview.error.different-document',
48
+ defaultMessage: 'This field comes from a different document'
49
+ }
50
+ }
51
+ };
19
52
 
20
53
  exports.INTERNAL_EVENTS = INTERNAL_EVENTS;
54
+ exports.PREVIEW_ERROR_MESSAGES = PREVIEW_ERROR_MESSAGES;
21
55
  exports.PUBLIC_EVENTS = PUBLIC_EVENTS;
22
56
  //# sourceMappingURL=constants.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.js","sources":["../../../../admin/src/preview/utils/constants.ts"],"sourcesContent":["import { previewScript } from './previewScript';\n\nconst scriptResponse = previewScript(false);\n\n/**\n * These events can be changed safely. They're used by the content manager admin on one side, and by\n * the preview script on the other. We own both ends, and they're not documented to users, so we can\n * do what we want with them.\n */\nexport const INTERNAL_EVENTS = scriptResponse!.INTERNAL_EVENTS;\n\n/**\n * These events are documented to users, and will be hardcoded in their frontends.\n * Changing any of these would be a breaking change.\n */\nexport const PUBLIC_EVENTS = {\n PREVIEW_READY: 'previewReady',\n STRAPI_UPDATE: 'strapiUpdate',\n STRAPI_SCRIPT: 'strapiScript',\n} as const;\n"],"names":["scriptResponse","previewScript","INTERNAL_EVENTS","PUBLIC_EVENTS","PREVIEW_READY","STRAPI_UPDATE","STRAPI_SCRIPT"],"mappings":";;;;AAEA,MAAMA,iBAAiBC,2BAAc,CAAA,KAAA,CAAA;AAErC;;;;AAIC,IACM,MAAMC,eAAkBF,GAAAA,cAAAA,CAAgBE;AAE/C;;;UAIaC,aAAgB,GAAA;IAC3BC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA;AACjB;;;;;"}
1
+ {"version":3,"file":"constants.js","sources":["../../../../admin/src/preview/utils/constants.ts"],"sourcesContent":["import { NotificationConfig } from '@strapi/admin/strapi-admin';\nimport { MessageDescriptor } from 'react-intl';\n\nimport { previewScript } from './previewScript';\n\nconst scriptResponse = previewScript(false);\n\n/**\n * These events can be changed safely. They're used by the content manager admin on one side, and by\n * the preview script on the other. We own both ends, and they're not documented to users, so we can\n * do what we want with them.\n */\nexport const INTERNAL_EVENTS = scriptResponse!.INTERNAL_EVENTS;\n\n/**\n * These events are documented to users, and will be hardcoded in their frontends.\n * Changing any of these would be a breaking change.\n */\nexport const PUBLIC_EVENTS = {\n PREVIEW_READY: 'previewReady',\n STRAPI_UPDATE: 'strapiUpdate',\n STRAPI_SCRIPT: 'strapiScript',\n} as const;\n\n/**\n * Error messages for preview field operations.\n * This information is used to trigger notifications.\n */\nexport const PREVIEW_ERROR_MESSAGES = {\n INVALID_FIELD_PATH: {\n type: 'danger',\n message: {\n id: 'content-manager.preview.error.invalid-field-path',\n defaultMessage: 'Could not locate this field in the current document',\n },\n },\n RELATIONS_NOT_HANDLED: {\n type: 'info',\n message: {\n id: 'content-manager.preview.error.relations-not-handled',\n defaultMessage: 'Inline editing for relations is not currently supported.',\n },\n },\n INCOMPLETE_STRAPI_SOURCE: {\n type: 'danger',\n message: {\n id: 'content-manager.preview.error.incomplete-strapi-source',\n defaultMessage: 'This field is missing some required preview information',\n },\n },\n DIFFERENT_DOCUMENT: {\n type: 'info',\n message: {\n id: 'content-manager.preview.error.different-document',\n defaultMessage: 'This field comes from a different document',\n },\n },\n} as const satisfies Record<\n string,\n { message: MessageDescriptor; type: NonNullable<NotificationConfig['type']> }\n>;\n"],"names":["scriptResponse","previewScript","INTERNAL_EVENTS","PUBLIC_EVENTS","PREVIEW_READY","STRAPI_UPDATE","STRAPI_SCRIPT","PREVIEW_ERROR_MESSAGES","INVALID_FIELD_PATH","type","message","id","defaultMessage","RELATIONS_NOT_HANDLED","INCOMPLETE_STRAPI_SOURCE","DIFFERENT_DOCUMENT"],"mappings":";;;;AAKA,MAAMA,iBAAiBC,2BAAc,CAAA,KAAA,CAAA;AAErC;;;;AAIC,IACM,MAAMC,eAAkBF,GAAAA,cAAAA,CAAgBE;AAE/C;;;UAIaC,aAAgB,GAAA;IAC3BC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA;AACjB;AAEA;;;UAIaC,sBAAyB,GAAA;IACpCC,kBAAoB,EAAA;QAClBC,IAAM,EAAA,QAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,kDAAA;YACJC,cAAgB,EAAA;AAClB;AACF,KAAA;IACAC,qBAAuB,EAAA;QACrBJ,IAAM,EAAA,MAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,qDAAA;YACJC,cAAgB,EAAA;AAClB;AACF,KAAA;IACAE,wBAA0B,EAAA;QACxBL,IAAM,EAAA,QAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,wDAAA;YACJC,cAAgB,EAAA;AAClB;AACF,KAAA;IACAG,kBAAoB,EAAA;QAClBN,IAAM,EAAA,MAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,kDAAA;YACJC,cAAgB,EAAA;AAClB;AACF;AACF;;;;;;"}
@@ -14,6 +14,39 @@ const scriptResponse = previewScript(false);
14
14
  STRAPI_UPDATE: 'strapiUpdate',
15
15
  STRAPI_SCRIPT: 'strapiScript'
16
16
  };
17
+ /**
18
+ * Error messages for preview field operations.
19
+ * This information is used to trigger notifications.
20
+ */ const PREVIEW_ERROR_MESSAGES = {
21
+ INVALID_FIELD_PATH: {
22
+ type: 'danger',
23
+ message: {
24
+ id: 'content-manager.preview.error.invalid-field-path',
25
+ defaultMessage: 'Could not locate this field in the current document'
26
+ }
27
+ },
28
+ RELATIONS_NOT_HANDLED: {
29
+ type: 'info',
30
+ message: {
31
+ id: 'content-manager.preview.error.relations-not-handled',
32
+ defaultMessage: 'Inline editing for relations is not currently supported.'
33
+ }
34
+ },
35
+ INCOMPLETE_STRAPI_SOURCE: {
36
+ type: 'danger',
37
+ message: {
38
+ id: 'content-manager.preview.error.incomplete-strapi-source',
39
+ defaultMessage: 'This field is missing some required preview information'
40
+ }
41
+ },
42
+ DIFFERENT_DOCUMENT: {
43
+ type: 'info',
44
+ message: {
45
+ id: 'content-manager.preview.error.different-document',
46
+ defaultMessage: 'This field comes from a different document'
47
+ }
48
+ }
49
+ };
17
50
 
18
- export { INTERNAL_EVENTS, PUBLIC_EVENTS };
51
+ export { INTERNAL_EVENTS, PREVIEW_ERROR_MESSAGES, PUBLIC_EVENTS };
19
52
  //# sourceMappingURL=constants.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"constants.mjs","sources":["../../../../admin/src/preview/utils/constants.ts"],"sourcesContent":["import { previewScript } from './previewScript';\n\nconst scriptResponse = previewScript(false);\n\n/**\n * These events can be changed safely. They're used by the content manager admin on one side, and by\n * the preview script on the other. We own both ends, and they're not documented to users, so we can\n * do what we want with them.\n */\nexport const INTERNAL_EVENTS = scriptResponse!.INTERNAL_EVENTS;\n\n/**\n * These events are documented to users, and will be hardcoded in their frontends.\n * Changing any of these would be a breaking change.\n */\nexport const PUBLIC_EVENTS = {\n PREVIEW_READY: 'previewReady',\n STRAPI_UPDATE: 'strapiUpdate',\n STRAPI_SCRIPT: 'strapiScript',\n} as const;\n"],"names":["scriptResponse","previewScript","INTERNAL_EVENTS","PUBLIC_EVENTS","PREVIEW_READY","STRAPI_UPDATE","STRAPI_SCRIPT"],"mappings":";;AAEA,MAAMA,iBAAiBC,aAAc,CAAA,KAAA,CAAA;AAErC;;;;AAIC,IACM,MAAMC,eAAkBF,GAAAA,cAAAA,CAAgBE;AAE/C;;;UAIaC,aAAgB,GAAA;IAC3BC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA;AACjB;;;;"}
1
+ {"version":3,"file":"constants.mjs","sources":["../../../../admin/src/preview/utils/constants.ts"],"sourcesContent":["import { NotificationConfig } from '@strapi/admin/strapi-admin';\nimport { MessageDescriptor } from 'react-intl';\n\nimport { previewScript } from './previewScript';\n\nconst scriptResponse = previewScript(false);\n\n/**\n * These events can be changed safely. They're used by the content manager admin on one side, and by\n * the preview script on the other. We own both ends, and they're not documented to users, so we can\n * do what we want with them.\n */\nexport const INTERNAL_EVENTS = scriptResponse!.INTERNAL_EVENTS;\n\n/**\n * These events are documented to users, and will be hardcoded in their frontends.\n * Changing any of these would be a breaking change.\n */\nexport const PUBLIC_EVENTS = {\n PREVIEW_READY: 'previewReady',\n STRAPI_UPDATE: 'strapiUpdate',\n STRAPI_SCRIPT: 'strapiScript',\n} as const;\n\n/**\n * Error messages for preview field operations.\n * This information is used to trigger notifications.\n */\nexport const PREVIEW_ERROR_MESSAGES = {\n INVALID_FIELD_PATH: {\n type: 'danger',\n message: {\n id: 'content-manager.preview.error.invalid-field-path',\n defaultMessage: 'Could not locate this field in the current document',\n },\n },\n RELATIONS_NOT_HANDLED: {\n type: 'info',\n message: {\n id: 'content-manager.preview.error.relations-not-handled',\n defaultMessage: 'Inline editing for relations is not currently supported.',\n },\n },\n INCOMPLETE_STRAPI_SOURCE: {\n type: 'danger',\n message: {\n id: 'content-manager.preview.error.incomplete-strapi-source',\n defaultMessage: 'This field is missing some required preview information',\n },\n },\n DIFFERENT_DOCUMENT: {\n type: 'info',\n message: {\n id: 'content-manager.preview.error.different-document',\n defaultMessage: 'This field comes from a different document',\n },\n },\n} as const satisfies Record<\n string,\n { message: MessageDescriptor; type: NonNullable<NotificationConfig['type']> }\n>;\n"],"names":["scriptResponse","previewScript","INTERNAL_EVENTS","PUBLIC_EVENTS","PREVIEW_READY","STRAPI_UPDATE","STRAPI_SCRIPT","PREVIEW_ERROR_MESSAGES","INVALID_FIELD_PATH","type","message","id","defaultMessage","RELATIONS_NOT_HANDLED","INCOMPLETE_STRAPI_SOURCE","DIFFERENT_DOCUMENT"],"mappings":";;AAKA,MAAMA,iBAAiBC,aAAc,CAAA,KAAA,CAAA;AAErC;;;;AAIC,IACM,MAAMC,eAAkBF,GAAAA,cAAAA,CAAgBE;AAE/C;;;UAIaC,aAAgB,GAAA;IAC3BC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA,cAAA;IACfC,aAAe,EAAA;AACjB;AAEA;;;UAIaC,sBAAyB,GAAA;IACpCC,kBAAoB,EAAA;QAClBC,IAAM,EAAA,QAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,kDAAA;YACJC,cAAgB,EAAA;AAClB;AACF,KAAA;IACAC,qBAAuB,EAAA;QACrBJ,IAAM,EAAA,MAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,qDAAA;YACJC,cAAgB,EAAA;AAClB;AACF,KAAA;IACAE,wBAA0B,EAAA;QACxBL,IAAM,EAAA,QAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,wDAAA;YACJC,cAAgB,EAAA;AAClB;AACF,KAAA;IACAG,kBAAoB,EAAA;QAClBN,IAAM,EAAA,MAAA;QACNC,OAAS,EAAA;YACPC,EAAI,EAAA,kDAAA;YACJC,cAAgB,EAAA;AAClB;AACF;AACF;;;;"}
@@ -1,5 +1,13 @@
1
1
  'use strict';
2
2
 
3
+ // Generic error class for preview field operations
4
+ class PreviewFieldError extends Error {
5
+ constructor(messageKey){
6
+ super(messageKey);
7
+ this.name = 'PreviewFieldError';
8
+ this.messageKey = messageKey;
9
+ }
10
+ }
3
11
  // Helper function to parse path with array indices and return clean attribute names
4
12
  const parsePathWithIndices = (path)=>{
5
13
  // Split by dots, then parse array indices from each part. For example:
@@ -40,17 +48,17 @@ function getAttributeSchemaFromPath({ path, schema, components, document }) {
40
48
  // Get the data and schema for the current path
41
49
  const currentAttribute = currentAttributes[currentPart.name];
42
50
  if (!currentAttribute) {
43
- throw new Error('Invalid field path');
51
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
44
52
  }
45
53
  if (currentAttribute.type === 'relation') {
46
- throw new Error('Relations not handled');
54
+ throw new PreviewFieldError('RELATIONS_NOT_HANDLED');
47
55
  }
48
56
  if (currentAttribute.type === 'component') {
49
57
  const componentAttributes = components[currentAttribute.component].attributes;
50
58
  if (currentAttribute.repeatable) {
51
59
  // We must have the index, otherwise we don't know what data to use
52
60
  if (currentPart.index === undefined) {
53
- throw new Error('Invalid field path');
61
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
54
62
  }
55
63
  return visitor(remainingParts, componentAttributes, currentData[currentPart.name][currentPart.index]);
56
64
  }
@@ -60,7 +68,7 @@ function getAttributeSchemaFromPath({ path, schema, components, document }) {
60
68
  if (currentAttribute.type === 'dynamiczone') {
61
69
  // We must have the index, otherwise we don't know what component we're dealing with
62
70
  if (currentPart.index === undefined) {
63
- throw new Error('Invalid field path');
71
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
64
72
  }
65
73
  const componentData = currentData[currentPart.name][currentPart.index];
66
74
  const componentAttributes = components[componentData.__component].attributes;
@@ -92,6 +100,7 @@ function parseFieldMetaData(strapiSource) {
92
100
  };
93
101
  }
94
102
 
103
+ exports.PreviewFieldError = PreviewFieldError;
95
104
  exports.getAttributeSchemaFromPath = getAttributeSchemaFromPath;
96
105
  exports.parseFieldMetaData = parseFieldMetaData;
97
106
  exports.parsePathWithIndices = parsePathWithIndices;
@@ -1 +1 @@
1
- {"version":3,"file":"fieldUtils.js","sources":["../../../../admin/src/preview/utils/fieldUtils.ts"],"sourcesContent":["import { type FieldContentSourceMap } from '@strapi/admin/strapi-admin';\n\nimport type { PreviewContextValue } from '../pages/Preview';\nimport type { Modules, Schema, Struct, UID } from '@strapi/types';\n\ntype PathPart = { name: string; index?: number };\n\n// Helper function to parse path with array indices and return clean attribute names\nexport const parsePathWithIndices = (path: string): PathPart[] => {\n // Split by dots, then parse array indices from each part. For example:\n // input \"components.4.field.relations.2.name\"\n // output [{name: \"components\", index: 4}, {name: \"field\"}, {name: \"relations\", index: 2}, {name: \"name\"}]\n return path\n .split('.')\n .map((part) => {\n const numericIndex = parseInt(part, 10);\n if (!isNaN(numericIndex) && part === numericIndex.toString()) {\n // This part is a pure numeric index, return it as an index for the previous part\n return { name: '', index: numericIndex };\n }\n return { name: part };\n })\n .reduce((acc: PathPart[], part) => {\n if (part.name === '' && part.index !== undefined) {\n // This is an index, attach it to the previous part\n if (acc.length > 0) {\n acc[acc.length - 1].index = part.index;\n }\n } else {\n acc.push(part);\n }\n return acc;\n }, []);\n};\n\nexport function getAttributeSchemaFromPath({\n path,\n schema,\n components,\n document,\n}: {\n path: string;\n schema: PreviewContextValue['schema'] | PreviewContextValue['components'][string];\n components: PreviewContextValue['components'];\n document: Modules.Documents.AnyDocument;\n}): Schema.Attribute.AnyAttribute {\n /**\n * Create the function that will be recursively called.\n * We don't do recursion on getAttributeSchemaFromPath itself because:\n * - it takes a path string, not the parsed array that's better for recursion\n * - even when several levels deep, we still need access to the root schema and components\n */\n const visitor = (\n currentPathParts: PathPart[],\n currentAttributes: Schema.Attributes,\n currentData: any\n ): Schema.Attribute.AnyAttribute => {\n const [currentPart, ...remainingParts] = currentPathParts;\n\n // Get the data and schema for the current path\n const currentAttribute = currentAttributes[currentPart.name];\n\n if (!currentAttribute) {\n throw new Error('Invalid field path');\n }\n\n if (currentAttribute.type === 'relation') {\n throw new Error('Relations not handled');\n }\n\n if (currentAttribute.type === 'component') {\n const componentAttributes = components[currentAttribute.component].attributes;\n if (currentAttribute.repeatable) {\n // We must have the index, otherwise we don't know what data to use\n if (currentPart.index === undefined) {\n throw new Error('Invalid field path');\n }\n return visitor(\n remainingParts,\n componentAttributes,\n currentData[currentPart.name][currentPart.index]\n );\n }\n\n // Non repeatable component\n return visitor(remainingParts, componentAttributes, currentData[currentPart.name]);\n }\n\n if (currentAttribute.type === 'dynamiczone') {\n // We must have the index, otherwise we don't know what component we're dealing with\n if (currentPart.index === undefined) {\n throw new Error('Invalid field path');\n }\n\n const componentData = currentData[currentPart.name][currentPart.index];\n const componentAttributes = components[componentData.__component].attributes;\n return visitor(remainingParts, componentAttributes, componentData);\n }\n\n // Plain regular field. It ends the recursion\n return currentAttributes[currentPart.name];\n };\n\n return visitor(parsePathWithIndices(path), schema.attributes, document);\n}\n\nexport function parseFieldMetaData(strapiSource: string): FieldContentSourceMap | null {\n const searchParams = new URLSearchParams(strapiSource);\n const path = searchParams.get('path');\n const type = searchParams.get('type');\n const documentId = searchParams.get('documentId');\n const locale = searchParams.get('locale');\n const model = searchParams.get('model');\n const kind = searchParams.get('kind');\n\n if (!path || !type || !documentId || !model) {\n return null;\n }\n\n return {\n path,\n type: type as Schema.Attribute.AnyAttribute['type'],\n documentId,\n locale: locale ?? null,\n model: model as UID.Schema | undefined,\n kind: kind ? (kind as Struct.ContentTypeKind) : undefined,\n };\n}\n"],"names":["parsePathWithIndices","path","split","map","part","numericIndex","parseInt","isNaN","toString","name","index","reduce","acc","undefined","length","push","getAttributeSchemaFromPath","schema","components","document","visitor","currentPathParts","currentAttributes","currentData","currentPart","remainingParts","currentAttribute","Error","type","componentAttributes","component","attributes","repeatable","componentData","__component","parseFieldMetaData","strapiSource","searchParams","URLSearchParams","get","documentId","locale","model","kind"],"mappings":"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"}
1
+ {"version":3,"file":"fieldUtils.js","sources":["../../../../admin/src/preview/utils/fieldUtils.ts"],"sourcesContent":["import { type FieldContentSourceMap } from '@strapi/admin/strapi-admin';\n\nimport type { PREVIEW_ERROR_MESSAGES } from './constants';\nimport type { PreviewContextValue } from '../pages/Preview';\nimport type { Modules, Schema, Struct, UID } from '@strapi/types';\n\ntype PreviewErrorMessage = keyof typeof PREVIEW_ERROR_MESSAGES;\n\n// Generic error class for preview field operations\nexport class PreviewFieldError extends Error {\n public readonly messageKey: PreviewErrorMessage;\n\n constructor(messageKey: PreviewErrorMessage) {\n super(messageKey);\n this.name = 'PreviewFieldError';\n this.messageKey = messageKey;\n }\n}\n\ntype PathPart = { name: string; index?: number };\n\n// Helper function to parse path with array indices and return clean attribute names\nexport const parsePathWithIndices = (path: string): PathPart[] => {\n // Split by dots, then parse array indices from each part. For example:\n // input \"components.4.field.relations.2.name\"\n // output [{name: \"components\", index: 4}, {name: \"field\"}, {name: \"relations\", index: 2}, {name: \"name\"}]\n return path\n .split('.')\n .map((part) => {\n const numericIndex = parseInt(part, 10);\n if (!isNaN(numericIndex) && part === numericIndex.toString()) {\n // This part is a pure numeric index, return it as an index for the previous part\n return { name: '', index: numericIndex };\n }\n return { name: part };\n })\n .reduce((acc: PathPart[], part) => {\n if (part.name === '' && part.index !== undefined) {\n // This is an index, attach it to the previous part\n if (acc.length > 0) {\n acc[acc.length - 1].index = part.index;\n }\n } else {\n acc.push(part);\n }\n return acc;\n }, []);\n};\n\nexport function getAttributeSchemaFromPath({\n path,\n schema,\n components,\n document,\n}: {\n path: string;\n schema: PreviewContextValue['schema'] | PreviewContextValue['components'][string];\n components: PreviewContextValue['components'];\n document: Modules.Documents.AnyDocument;\n}): Schema.Attribute.AnyAttribute {\n /**\n * Create the function that will be recursively called.\n * We don't do recursion on getAttributeSchemaFromPath itself because:\n * - it takes a path string, not the parsed array that's better for recursion\n * - even when several levels deep, we still need access to the root schema and components\n */\n const visitor = (\n currentPathParts: PathPart[],\n currentAttributes: Schema.Attributes,\n currentData: any\n ): Schema.Attribute.AnyAttribute => {\n const [currentPart, ...remainingParts] = currentPathParts;\n\n // Get the data and schema for the current path\n const currentAttribute = currentAttributes[currentPart.name];\n\n if (!currentAttribute) {\n throw new PreviewFieldError('INVALID_FIELD_PATH');\n }\n\n if (currentAttribute.type === 'relation') {\n throw new PreviewFieldError('RELATIONS_NOT_HANDLED');\n }\n\n if (currentAttribute.type === 'component') {\n const componentAttributes = components[currentAttribute.component].attributes;\n if (currentAttribute.repeatable) {\n // We must have the index, otherwise we don't know what data to use\n if (currentPart.index === undefined) {\n throw new PreviewFieldError('INVALID_FIELD_PATH');\n }\n return visitor(\n remainingParts,\n componentAttributes,\n currentData[currentPart.name][currentPart.index]\n );\n }\n\n // Non repeatable component\n return visitor(remainingParts, componentAttributes, currentData[currentPart.name]);\n }\n\n if (currentAttribute.type === 'dynamiczone') {\n // We must have the index, otherwise we don't know what component we're dealing with\n if (currentPart.index === undefined) {\n throw new PreviewFieldError('INVALID_FIELD_PATH');\n }\n\n const componentData = currentData[currentPart.name][currentPart.index];\n const componentAttributes = components[componentData.__component].attributes;\n return visitor(remainingParts, componentAttributes, componentData);\n }\n\n // Plain regular field. It ends the recursion\n return currentAttributes[currentPart.name];\n };\n\n return visitor(parsePathWithIndices(path), schema.attributes, document);\n}\n\nexport function parseFieldMetaData(strapiSource: string): FieldContentSourceMap | null {\n const searchParams = new URLSearchParams(strapiSource);\n const path = searchParams.get('path');\n const type = searchParams.get('type');\n const documentId = searchParams.get('documentId');\n const locale = searchParams.get('locale');\n const model = searchParams.get('model');\n const kind = searchParams.get('kind');\n\n if (!path || !type || !documentId || !model) {\n return null;\n }\n\n return {\n path,\n type: type as Schema.Attribute.AnyAttribute['type'],\n documentId,\n locale: locale ?? null,\n model: model as UID.Schema | undefined,\n kind: kind ? (kind as Struct.ContentTypeKind) : undefined,\n };\n}\n"],"names":["PreviewFieldError","Error","constructor","messageKey","name","parsePathWithIndices","path","split","map","part","numericIndex","parseInt","isNaN","toString","index","reduce","acc","undefined","length","push","getAttributeSchemaFromPath","schema","components","document","visitor","currentPathParts","currentAttributes","currentData","currentPart","remainingParts","currentAttribute","type","componentAttributes","component","attributes","repeatable","componentData","__component","parseFieldMetaData","strapiSource","searchParams","URLSearchParams","get","documentId","locale","model","kind"],"mappings":"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"}
@@ -1,3 +1,11 @@
1
+ // Generic error class for preview field operations
2
+ class PreviewFieldError extends Error {
3
+ constructor(messageKey){
4
+ super(messageKey);
5
+ this.name = 'PreviewFieldError';
6
+ this.messageKey = messageKey;
7
+ }
8
+ }
1
9
  // Helper function to parse path with array indices and return clean attribute names
2
10
  const parsePathWithIndices = (path)=>{
3
11
  // Split by dots, then parse array indices from each part. For example:
@@ -38,17 +46,17 @@ function getAttributeSchemaFromPath({ path, schema, components, document }) {
38
46
  // Get the data and schema for the current path
39
47
  const currentAttribute = currentAttributes[currentPart.name];
40
48
  if (!currentAttribute) {
41
- throw new Error('Invalid field path');
49
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
42
50
  }
43
51
  if (currentAttribute.type === 'relation') {
44
- throw new Error('Relations not handled');
52
+ throw new PreviewFieldError('RELATIONS_NOT_HANDLED');
45
53
  }
46
54
  if (currentAttribute.type === 'component') {
47
55
  const componentAttributes = components[currentAttribute.component].attributes;
48
56
  if (currentAttribute.repeatable) {
49
57
  // We must have the index, otherwise we don't know what data to use
50
58
  if (currentPart.index === undefined) {
51
- throw new Error('Invalid field path');
59
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
52
60
  }
53
61
  return visitor(remainingParts, componentAttributes, currentData[currentPart.name][currentPart.index]);
54
62
  }
@@ -58,7 +66,7 @@ function getAttributeSchemaFromPath({ path, schema, components, document }) {
58
66
  if (currentAttribute.type === 'dynamiczone') {
59
67
  // We must have the index, otherwise we don't know what component we're dealing with
60
68
  if (currentPart.index === undefined) {
61
- throw new Error('Invalid field path');
69
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
62
70
  }
63
71
  const componentData = currentData[currentPart.name][currentPart.index];
64
72
  const componentAttributes = components[componentData.__component].attributes;
@@ -90,5 +98,5 @@ function parseFieldMetaData(strapiSource) {
90
98
  };
91
99
  }
92
100
 
93
- export { getAttributeSchemaFromPath, parseFieldMetaData, parsePathWithIndices };
101
+ export { PreviewFieldError, getAttributeSchemaFromPath, parseFieldMetaData, parsePathWithIndices };
94
102
  //# sourceMappingURL=fieldUtils.mjs.map