@strapi/content-manager 0.0.0-next.965570e6e12a33ad098ddb3174a9750fddb03be2 → 0.0.0-next.96a532b33a712f19b498ed0a82a84752247cd899

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. package/dist/admin/components/ConfigurationForm/EditFieldForm.js +1 -1
  2. package/dist/admin/components/ConfigurationForm/EditFieldForm.js.map +1 -1
  3. package/dist/admin/components/ConfigurationForm/EditFieldForm.mjs +1 -1
  4. package/dist/admin/components/ConfigurationForm/EditFieldForm.mjs.map +1 -1
  5. package/dist/admin/components/ConfigurationForm/Fields.js +4 -1
  6. package/dist/admin/components/ConfigurationForm/Fields.js.map +1 -1
  7. package/dist/admin/components/ConfigurationForm/Fields.mjs +5 -2
  8. package/dist/admin/components/ConfigurationForm/Fields.mjs.map +1 -1
  9. package/dist/admin/components/ConfigurationForm/Form.js +1 -1
  10. package/dist/admin/components/ConfigurationForm/Form.js.map +1 -1
  11. package/dist/admin/components/ConfigurationForm/Form.mjs +3 -3
  12. package/dist/admin/components/ConfigurationForm/Form.mjs.map +1 -1
  13. package/dist/admin/components/DragPreviews/CardDragPreview.js +3 -1
  14. package/dist/admin/components/DragPreviews/CardDragPreview.js.map +1 -1
  15. package/dist/admin/components/DragPreviews/CardDragPreview.mjs +3 -1
  16. package/dist/admin/components/DragPreviews/CardDragPreview.mjs.map +1 -1
  17. package/dist/admin/components/DragPreviews/ComponentDragPreview.js +3 -1
  18. package/dist/admin/components/DragPreviews/ComponentDragPreview.js.map +1 -1
  19. package/dist/admin/components/DragPreviews/ComponentDragPreview.mjs +3 -1
  20. package/dist/admin/components/DragPreviews/ComponentDragPreview.mjs.map +1 -1
  21. package/dist/admin/components/DragPreviews/RelationDragPreview.js +3 -1
  22. package/dist/admin/components/DragPreviews/RelationDragPreview.js.map +1 -1
  23. package/dist/admin/components/DragPreviews/RelationDragPreview.mjs +3 -1
  24. package/dist/admin/components/DragPreviews/RelationDragPreview.mjs.map +1 -1
  25. package/dist/admin/components/LeftMenu.js +90 -48
  26. package/dist/admin/components/LeftMenu.js.map +1 -1
  27. package/dist/admin/components/LeftMenu.mjs +92 -50
  28. package/dist/admin/components/LeftMenu.mjs.map +1 -1
  29. package/dist/admin/components/Widgets.js +22 -6
  30. package/dist/admin/components/Widgets.js.map +1 -1
  31. package/dist/admin/components/Widgets.mjs +22 -6
  32. package/dist/admin/components/Widgets.mjs.map +1 -1
  33. package/dist/admin/history/components/VersionHeader.js +1 -0
  34. package/dist/admin/history/components/VersionHeader.js.map +1 -1
  35. package/dist/admin/history/components/VersionHeader.mjs +1 -0
  36. package/dist/admin/history/components/VersionHeader.mjs.map +1 -1
  37. package/dist/admin/history/components/VersionsList.js +1 -1
  38. package/dist/admin/history/components/VersionsList.js.map +1 -1
  39. package/dist/admin/history/components/VersionsList.mjs +1 -1
  40. package/dist/admin/history/components/VersionsList.mjs.map +1 -1
  41. package/dist/admin/history/pages/History.js +7 -7
  42. package/dist/admin/history/pages/History.js.map +1 -1
  43. package/dist/admin/history/pages/History.mjs +7 -7
  44. package/dist/admin/history/pages/History.mjs.map +1 -1
  45. package/dist/admin/layout.js +27 -6
  46. package/dist/admin/layout.js.map +1 -1
  47. package/dist/admin/layout.mjs +28 -7
  48. package/dist/admin/layout.mjs.map +1 -1
  49. package/dist/admin/pages/EditView/EditViewPage.js +7 -3
  50. package/dist/admin/pages/EditView/EditViewPage.js.map +1 -1
  51. package/dist/admin/pages/EditView/EditViewPage.mjs +8 -4
  52. package/dist/admin/pages/EditView/EditViewPage.mjs.map +1 -1
  53. package/dist/admin/pages/EditView/components/DocumentActions.js +6 -0
  54. package/dist/admin/pages/EditView/components/DocumentActions.js.map +1 -1
  55. package/dist/admin/pages/EditView/components/DocumentActions.mjs +6 -0
  56. package/dist/admin/pages/EditView/components/DocumentActions.mjs.map +1 -1
  57. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.js +66 -2
  58. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.js.map +1 -1
  59. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.mjs +66 -2
  60. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.mjs.map +1 -1
  61. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js +2 -2
  62. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js.map +1 -1
  63. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs +2 -2
  64. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs.map +1 -1
  65. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.js +7 -3
  66. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.js.map +1 -1
  67. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.mjs +7 -3
  68. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/utils/links.mjs.map +1 -1
  69. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js +2 -1
  70. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.js.map +1 -1
  71. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs +3 -2
  72. package/dist/admin/pages/EditView/components/FormInputs/Component/Repeatable.mjs.map +1 -1
  73. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js +1 -2
  74. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.js.map +1 -1
  75. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs +1 -2
  76. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.mjs.map +1 -1
  77. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js +4 -3
  78. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.js.map +1 -1
  79. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs +5 -4
  80. package/dist/admin/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.mjs.map +1 -1
  81. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js +2 -1
  82. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.js.map +1 -1
  83. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs +3 -2
  84. package/dist/admin/pages/EditView/components/FormInputs/Relations/Relations.mjs.map +1 -1
  85. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.js +2 -2
  86. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.js.map +1 -1
  87. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.mjs +2 -2
  88. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.mjs.map +1 -1
  89. package/dist/admin/pages/EditView/components/FormLayout.js +13 -8
  90. package/dist/admin/pages/EditView/components/FormLayout.js.map +1 -1
  91. package/dist/admin/pages/EditView/components/FormLayout.mjs +14 -8
  92. package/dist/admin/pages/EditView/components/FormLayout.mjs.map +1 -1
  93. package/dist/admin/pages/EditView/components/Header.js +85 -25
  94. package/dist/admin/pages/EditView/components/Header.js.map +1 -1
  95. package/dist/admin/pages/EditView/components/Header.mjs +87 -27
  96. package/dist/admin/pages/EditView/components/Header.mjs.map +1 -1
  97. package/dist/admin/pages/EditView/components/InputRenderer.js +6 -3
  98. package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
  99. package/dist/admin/pages/EditView/components/InputRenderer.mjs +6 -3
  100. package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
  101. package/dist/admin/pages/EditView/utils/data.js +1 -1
  102. package/dist/admin/pages/EditView/utils/data.js.map +1 -1
  103. package/dist/admin/pages/EditView/utils/data.mjs +1 -1
  104. package/dist/admin/pages/EditView/utils/data.mjs.map +1 -1
  105. package/dist/admin/pages/ListConfiguration/ListConfigurationPage.js +1 -0
  106. package/dist/admin/pages/ListConfiguration/ListConfigurationPage.js.map +1 -1
  107. package/dist/admin/pages/ListConfiguration/ListConfigurationPage.mjs +1 -0
  108. package/dist/admin/pages/ListConfiguration/ListConfigurationPage.mjs.map +1 -1
  109. package/dist/admin/pages/ListView/components/Filters.js +4 -1
  110. package/dist/admin/pages/ListView/components/Filters.js.map +1 -1
  111. package/dist/admin/pages/ListView/components/Filters.mjs +4 -1
  112. package/dist/admin/pages/ListView/components/Filters.mjs.map +1 -1
  113. package/dist/admin/pages/ListView/components/ViewSettingsMenu.js +5 -2
  114. package/dist/admin/pages/ListView/components/ViewSettingsMenu.js.map +1 -1
  115. package/dist/admin/pages/ListView/components/ViewSettingsMenu.mjs +5 -2
  116. package/dist/admin/pages/ListView/components/ViewSettingsMenu.mjs.map +1 -1
  117. package/dist/admin/preview/components/InputPopover.js +130 -14
  118. package/dist/admin/preview/components/InputPopover.js.map +1 -1
  119. package/dist/admin/preview/components/InputPopover.mjs +112 -15
  120. package/dist/admin/preview/components/InputPopover.mjs.map +1 -1
  121. package/dist/admin/preview/components/PreviewHeader.js +0 -1
  122. package/dist/admin/preview/components/PreviewHeader.js.map +1 -1
  123. package/dist/admin/preview/components/PreviewHeader.mjs +0 -1
  124. package/dist/admin/preview/components/PreviewHeader.mjs.map +1 -1
  125. package/dist/admin/preview/hooks/usePreviewInputManager.js +18 -8
  126. package/dist/admin/preview/hooks/usePreviewInputManager.js.map +1 -1
  127. package/dist/admin/preview/hooks/usePreviewInputManager.mjs +18 -8
  128. package/dist/admin/preview/hooks/usePreviewInputManager.mjs.map +1 -1
  129. package/dist/admin/preview/pages/Preview.js +12 -10
  130. package/dist/admin/preview/pages/Preview.js.map +1 -1
  131. package/dist/admin/preview/pages/Preview.mjs +14 -12
  132. package/dist/admin/preview/pages/Preview.mjs.map +1 -1
  133. package/dist/admin/preview/utils/constants.js +34 -0
  134. package/dist/admin/preview/utils/constants.js.map +1 -1
  135. package/dist/admin/preview/utils/constants.mjs +34 -1
  136. package/dist/admin/preview/utils/constants.mjs.map +1 -1
  137. package/dist/admin/preview/utils/fieldUtils.js +107 -0
  138. package/dist/admin/preview/utils/fieldUtils.js.map +1 -0
  139. package/dist/admin/preview/utils/fieldUtils.mjs +102 -0
  140. package/dist/admin/preview/utils/fieldUtils.mjs.map +1 -0
  141. package/dist/admin/preview/utils/previewScript.js +134 -50
  142. package/dist/admin/preview/utils/previewScript.js.map +1 -1
  143. package/dist/admin/preview/utils/previewScript.mjs +134 -50
  144. package/dist/admin/preview/utils/previewScript.mjs.map +1 -1
  145. package/dist/admin/services/documents.js +9 -1
  146. package/dist/admin/services/documents.js.map +1 -1
  147. package/dist/admin/services/documents.mjs +9 -1
  148. package/dist/admin/services/documents.mjs.map +1 -1
  149. package/dist/admin/src/components/LeftMenu.d.ts +3 -1
  150. package/dist/admin/src/components/Widgets.d.ts +6 -2
  151. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  152. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/links.d.ts +2 -0
  153. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +0 -3
  154. package/dist/admin/src/pages/EditView/components/Header.d.ts +4 -0
  155. package/dist/admin/src/preview/components/InputPopover.d.ts +1 -1
  156. package/dist/admin/src/preview/hooks/usePreviewInputManager.d.ts +2 -1
  157. package/dist/admin/src/preview/pages/Preview.d.ts +6 -2
  158. package/dist/admin/src/preview/services/preview.d.ts +1 -1
  159. package/dist/admin/src/preview/utils/constants.d.ts +35 -0
  160. package/dist/admin/src/preview/utils/fieldUtils.d.ts +22 -0
  161. package/dist/admin/src/preview/utils/previewScript.d.ts +1 -0
  162. package/dist/admin/src/services/api.d.ts +1 -1
  163. package/dist/admin/src/services/components.d.ts +2 -2
  164. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  165. package/dist/admin/src/services/documents.d.ts +16 -16
  166. package/dist/admin/src/services/homepage.d.ts +1 -1
  167. package/dist/admin/src/services/init.d.ts +1 -1
  168. package/dist/admin/src/services/relations.d.ts +2 -2
  169. package/dist/admin/src/services/uid.d.ts +3 -3
  170. package/dist/admin/translations/en.json.js +5 -0
  171. package/dist/admin/translations/en.json.js.map +1 -1
  172. package/dist/admin/translations/en.json.mjs +5 -0
  173. package/dist/admin/translations/en.json.mjs.map +1 -1
  174. package/dist/server/controllers/collection-types.js +22 -2
  175. package/dist/server/controllers/collection-types.js.map +1 -1
  176. package/dist/server/controllers/collection-types.mjs +22 -2
  177. package/dist/server/controllers/collection-types.mjs.map +1 -1
  178. package/dist/server/controllers/relations.js +6 -4
  179. package/dist/server/controllers/relations.js.map +1 -1
  180. package/dist/server/controllers/relations.mjs +6 -4
  181. package/dist/server/controllers/relations.mjs.map +1 -1
  182. package/dist/server/controllers/single-types.js +9 -0
  183. package/dist/server/controllers/single-types.js.map +1 -1
  184. package/dist/server/controllers/single-types.mjs +9 -0
  185. package/dist/server/controllers/single-types.mjs.map +1 -1
  186. package/dist/server/preview/services/preview-config.js +8 -33
  187. package/dist/server/preview/services/preview-config.js.map +1 -1
  188. package/dist/server/preview/services/preview-config.mjs +9 -34
  189. package/dist/server/preview/services/preview-config.mjs.map +1 -1
  190. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  191. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  192. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  193. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -1
  194. package/package.json +7 -7
@@ -0,0 +1,107 @@
1
+ 'use strict';
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
+ }
11
+ // Helper function to parse path with array indices and return clean attribute names
12
+ const parsePathWithIndices = (path)=>{
13
+ // Split by dots, then parse array indices from each part. For example:
14
+ // input "components.4.field.relations.2.name"
15
+ // output [{name: "components", index: 4}, {name: "field"}, {name: "relations", index: 2}, {name: "name"}]
16
+ return path.split('.').map((part)=>{
17
+ const numericIndex = parseInt(part, 10);
18
+ if (!isNaN(numericIndex) && part === numericIndex.toString()) {
19
+ // This part is a pure numeric index, return it as an index for the previous part
20
+ return {
21
+ name: '',
22
+ index: numericIndex
23
+ };
24
+ }
25
+ return {
26
+ name: part
27
+ };
28
+ }).reduce((acc, part)=>{
29
+ if (part.name === '' && part.index !== undefined) {
30
+ // This is an index, attach it to the previous part
31
+ if (acc.length > 0) {
32
+ acc[acc.length - 1].index = part.index;
33
+ }
34
+ } else {
35
+ acc.push(part);
36
+ }
37
+ return acc;
38
+ }, []);
39
+ };
40
+ function getAttributeSchemaFromPath({ path, schema, components, document }) {
41
+ /**
42
+ * Create the function that will be recursively called.
43
+ * We don't do recursion on getAttributeSchemaFromPath itself because:
44
+ * - it takes a path string, not the parsed array that's better for recursion
45
+ * - even when several levels deep, we still need access to the root schema and components
46
+ */ const visitor = (currentPathParts, currentAttributes, currentData)=>{
47
+ const [currentPart, ...remainingParts] = currentPathParts;
48
+ // Get the data and schema for the current path
49
+ const currentAttribute = currentAttributes[currentPart.name];
50
+ if (!currentAttribute) {
51
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
52
+ }
53
+ if (currentAttribute.type === 'relation') {
54
+ throw new PreviewFieldError('RELATIONS_NOT_HANDLED');
55
+ }
56
+ if (currentAttribute.type === 'component') {
57
+ const componentAttributes = components[currentAttribute.component].attributes;
58
+ if (currentAttribute.repeatable) {
59
+ // We must have the index, otherwise we don't know what data to use
60
+ if (currentPart.index === undefined) {
61
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
62
+ }
63
+ return visitor(remainingParts, componentAttributes, currentData[currentPart.name][currentPart.index]);
64
+ }
65
+ // Non repeatable component
66
+ return visitor(remainingParts, componentAttributes, currentData[currentPart.name]);
67
+ }
68
+ if (currentAttribute.type === 'dynamiczone') {
69
+ // We must have the index, otherwise we don't know what component we're dealing with
70
+ if (currentPart.index === undefined) {
71
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
72
+ }
73
+ const componentData = currentData[currentPart.name][currentPart.index];
74
+ const componentAttributes = components[componentData.__component].attributes;
75
+ return visitor(remainingParts, componentAttributes, componentData);
76
+ }
77
+ // Plain regular field. It ends the recursion
78
+ return currentAttributes[currentPart.name];
79
+ };
80
+ return visitor(parsePathWithIndices(path), schema.attributes, document);
81
+ }
82
+ function parseFieldMetaData(strapiSource) {
83
+ const searchParams = new URLSearchParams(strapiSource);
84
+ const path = searchParams.get('path');
85
+ const type = searchParams.get('type');
86
+ const documentId = searchParams.get('documentId');
87
+ const locale = searchParams.get('locale');
88
+ const model = searchParams.get('model');
89
+ const kind = searchParams.get('kind');
90
+ if (!path || !type || !documentId || !model) {
91
+ return null;
92
+ }
93
+ return {
94
+ path,
95
+ type: type,
96
+ documentId,
97
+ locale: locale ?? null,
98
+ model: model,
99
+ kind: kind ? kind : undefined
100
+ };
101
+ }
102
+
103
+ exports.PreviewFieldError = PreviewFieldError;
104
+ exports.getAttributeSchemaFromPath = getAttributeSchemaFromPath;
105
+ exports.parseFieldMetaData = parseFieldMetaData;
106
+ exports.parsePathWithIndices = parsePathWithIndices;
107
+ //# sourceMappingURL=fieldUtils.js.map
@@ -0,0 +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 { 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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"}
@@ -0,0 +1,102 @@
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
+ }
9
+ // Helper function to parse path with array indices and return clean attribute names
10
+ const parsePathWithIndices = (path)=>{
11
+ // Split by dots, then parse array indices from each part. For example:
12
+ // input "components.4.field.relations.2.name"
13
+ // output [{name: "components", index: 4}, {name: "field"}, {name: "relations", index: 2}, {name: "name"}]
14
+ return path.split('.').map((part)=>{
15
+ const numericIndex = parseInt(part, 10);
16
+ if (!isNaN(numericIndex) && part === numericIndex.toString()) {
17
+ // This part is a pure numeric index, return it as an index for the previous part
18
+ return {
19
+ name: '',
20
+ index: numericIndex
21
+ };
22
+ }
23
+ return {
24
+ name: part
25
+ };
26
+ }).reduce((acc, part)=>{
27
+ if (part.name === '' && part.index !== undefined) {
28
+ // This is an index, attach it to the previous part
29
+ if (acc.length > 0) {
30
+ acc[acc.length - 1].index = part.index;
31
+ }
32
+ } else {
33
+ acc.push(part);
34
+ }
35
+ return acc;
36
+ }, []);
37
+ };
38
+ function getAttributeSchemaFromPath({ path, schema, components, document }) {
39
+ /**
40
+ * Create the function that will be recursively called.
41
+ * We don't do recursion on getAttributeSchemaFromPath itself because:
42
+ * - it takes a path string, not the parsed array that's better for recursion
43
+ * - even when several levels deep, we still need access to the root schema and components
44
+ */ const visitor = (currentPathParts, currentAttributes, currentData)=>{
45
+ const [currentPart, ...remainingParts] = currentPathParts;
46
+ // Get the data and schema for the current path
47
+ const currentAttribute = currentAttributes[currentPart.name];
48
+ if (!currentAttribute) {
49
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
50
+ }
51
+ if (currentAttribute.type === 'relation') {
52
+ throw new PreviewFieldError('RELATIONS_NOT_HANDLED');
53
+ }
54
+ if (currentAttribute.type === 'component') {
55
+ const componentAttributes = components[currentAttribute.component].attributes;
56
+ if (currentAttribute.repeatable) {
57
+ // We must have the index, otherwise we don't know what data to use
58
+ if (currentPart.index === undefined) {
59
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
60
+ }
61
+ return visitor(remainingParts, componentAttributes, currentData[currentPart.name][currentPart.index]);
62
+ }
63
+ // Non repeatable component
64
+ return visitor(remainingParts, componentAttributes, currentData[currentPart.name]);
65
+ }
66
+ if (currentAttribute.type === 'dynamiczone') {
67
+ // We must have the index, otherwise we don't know what component we're dealing with
68
+ if (currentPart.index === undefined) {
69
+ throw new PreviewFieldError('INVALID_FIELD_PATH');
70
+ }
71
+ const componentData = currentData[currentPart.name][currentPart.index];
72
+ const componentAttributes = components[componentData.__component].attributes;
73
+ return visitor(remainingParts, componentAttributes, componentData);
74
+ }
75
+ // Plain regular field. It ends the recursion
76
+ return currentAttributes[currentPart.name];
77
+ };
78
+ return visitor(parsePathWithIndices(path), schema.attributes, document);
79
+ }
80
+ function parseFieldMetaData(strapiSource) {
81
+ const searchParams = new URLSearchParams(strapiSource);
82
+ const path = searchParams.get('path');
83
+ const type = searchParams.get('type');
84
+ const documentId = searchParams.get('documentId');
85
+ const locale = searchParams.get('locale');
86
+ const model = searchParams.get('model');
87
+ const kind = searchParams.get('kind');
88
+ if (!path || !type || !documentId || !model) {
89
+ return null;
90
+ }
91
+ return {
92
+ path,
93
+ type: type,
94
+ documentId,
95
+ locale: locale ?? null,
96
+ model: model,
97
+ kind: kind ? kind : undefined
98
+ };
99
+ }
100
+
101
+ export { PreviewFieldError, getAttributeSchemaFromPath, parseFieldMetaData, parsePathWithIndices };
102
+ //# sourceMappingURL=fieldUtils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fieldUtils.mjs","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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"}
@@ -12,6 +12,8 @@
12
12
  * ---------------------------------------------------------------------------------------------*/ const HIGHLIGHT_PADDING = 2; // in pixels
13
13
  const HIGHLIGHT_HOVER_COLOR = window.STRAPI_HIGHLIGHT_HOVER_COLOR ?? '#4945ff'; // dark primary500
14
14
  const HIGHLIGHT_ACTIVE_COLOR = window.STRAPI_HIGHLIGHT_ACTIVE_COLOR ?? '#7b79ff'; // dark primary600
15
+ const HIGHLIGHT_STYLES_ID = 'strapi-preview-highlight-styles';
16
+ const DOUBLE_CLICK_TIMEOUT = 300; // milliseconds to wait for potential double-click
15
17
  const DISABLE_STEGA_DECODING = window.STRAPI_DISABLE_STEGA_DECODING ?? false;
16
18
  const SOURCE_ATTRIBUTE = 'data-strapi-source';
17
19
  const OVERLAY_ID = 'strapi-preview-overlay';
@@ -19,7 +21,8 @@
19
21
  STRAPI_FIELD_FOCUS: 'strapiFieldFocus',
20
22
  STRAPI_FIELD_BLUR: 'strapiFieldBlur',
21
23
  STRAPI_FIELD_CHANGE: 'strapiFieldChange',
22
- STRAPI_FIELD_FOCUS_INTENT: 'strapiFieldFocusIntent'
24
+ STRAPI_FIELD_FOCUS_INTENT: 'strapiFieldFocusIntent',
25
+ STRAPI_FIELD_SINGLE_CLICK_HINT: 'strapiFieldSingleClickHint'
23
26
  };
24
27
  /**
25
28
  * Calling the function in no-run mode lets us retrieve the constants from other files and keep
@@ -38,6 +41,9 @@
38
41
  payload
39
42
  }, '*');
40
43
  };
44
+ const getElementsByPath = (path)=>{
45
+ return document.querySelectorAll(`[${SOURCE_ATTRIBUTE}*="path=${path}"]`);
46
+ };
41
47
  /* -----------------------------------------------------------------------------------------------
42
48
  * Functionality pieces
43
49
  * ---------------------------------------------------------------------------------------------*/ const setupStegaDOMObserver = async ()=>{
@@ -52,9 +58,10 @@
52
58
  const directTextContent = directTextNodes.map((node)=>node.textContent || '').join('');
53
59
  if (directTextContent) {
54
60
  try {
61
+ // TODO: check if we can call split instead of decode+clean
55
62
  const result = stegaDecode(directTextContent);
56
- if (result) {
57
- element.setAttribute(SOURCE_ATTRIBUTE, result.key);
63
+ if (result && 'strapiSource' in result) {
64
+ element.setAttribute(SOURCE_ATTRIBUTE, result.strapiSource);
58
65
  // Remove encoded part from DOM text content (to avoid breaking links for example)
59
66
  directTextNodes.forEach((node)=>{
60
67
  if (node.textContent) {
@@ -100,6 +107,37 @@
100
107
  });
101
108
  return observer;
102
109
  };
110
+ const createHighlightStyles = ()=>{
111
+ const existingStyles = document.getElementById(HIGHLIGHT_STYLES_ID);
112
+ // Remove existing styles to avoid duplicates
113
+ if (existingStyles) {
114
+ existingStyles.remove();
115
+ }
116
+ const styleElement = document.createElement('style');
117
+ styleElement.id = HIGHLIGHT_STYLES_ID;
118
+ styleElement.textContent = `
119
+ .strapi-highlight {
120
+ position: absolute;
121
+ outline: 2px solid transparent;
122
+ pointer-events: auto;
123
+ border-radius: 2px;
124
+ background-color: transparent;
125
+ will-change: transform;
126
+ transition: outline-color 0.1s ease-in-out;
127
+ }
128
+
129
+ .strapi-highlight:hover {
130
+ outline-color: ${HIGHLIGHT_HOVER_COLOR} !important;
131
+ }
132
+
133
+ .strapi-highlight.strapi-highlight-focused {
134
+ outline-color: ${HIGHLIGHT_ACTIVE_COLOR} !important;
135
+ outline-width: 3px !important;
136
+ }
137
+ `;
138
+ document.head.appendChild(styleElement);
139
+ return styleElement;
140
+ };
103
141
  const createOverlaySystem = ()=>{
104
142
  // Clean up before creating a new overlay so we can safely call previewScript multiple times
105
143
  window.__strapi_previewCleanup?.();
@@ -122,6 +160,7 @@
122
160
  const elementsToHighlight = new Map();
123
161
  const eventListeners = [];
124
162
  const focusedHighlights = [];
163
+ const pendingClicks = new Map(); // number is timeout id
125
164
  let focusedField = null;
126
165
  const drawHighlight = (target, highlight)=>{
127
166
  if (!highlight) return;
@@ -141,27 +180,57 @@
141
180
  return;
142
181
  }
143
182
  const highlight = document.createElement('div');
144
- highlight.style.cssText = `
145
- position: absolute;
146
- outline: 2px solid transparent;
147
- pointer-events: none;
148
- border-radius: 2px;
149
- background-color: transparent;
150
- will-change: transform;
151
- transition: outline-color 0.1s ease-in-out;
152
- `;
153
- // Move hover detection to the underlying element
154
- const mouseEnterHandler = ()=>{
155
- if (!focusedHighlights.includes(highlight)) {
156
- highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;
183
+ highlight.className = 'strapi-highlight';
184
+ const clickHandler = (event)=>{
185
+ // Skip if this is a re-dispatched event from our delayed handler to avoid infinite loops
186
+ if (event.__strapi_redispatched) {
187
+ return;
157
188
  }
158
- };
159
- const mouseLeaveHandler = ()=>{
160
- if (!focusedHighlights.includes(highlight)) {
161
- highlight.style.outlineColor = 'transparent';
189
+ // Prevent the immediate action for interactive elements
190
+ event.preventDefault();
191
+ event.stopPropagation();
192
+ // Clear any existing timeout for this element
193
+ const existingTimeout = pendingClicks.get(element);
194
+ if (existingTimeout) {
195
+ window.clearTimeout(existingTimeout);
196
+ pendingClicks.delete(element);
162
197
  }
198
+ // Set up a delayed single-click handler
199
+ const timeout = window.setTimeout(()=>{
200
+ pendingClicks.delete(element);
201
+ // Send single-click hint notification
202
+ sendMessage(INTERNAL_EVENTS.STRAPI_FIELD_SINGLE_CLICK_HINT, null);
203
+ // Re-trigger the click on the underlying element after the double-click timeout
204
+ // Create a new event to dispatch with a marker to prevent re-handling
205
+ const newEvent = new MouseEvent('click', {
206
+ bubbles: true,
207
+ cancelable: true,
208
+ view: window,
209
+ detail: 1,
210
+ button: event.button,
211
+ buttons: event.buttons,
212
+ clientX: event.clientX,
213
+ clientY: event.clientY,
214
+ ctrlKey: event.ctrlKey,
215
+ altKey: event.altKey,
216
+ shiftKey: event.shiftKey,
217
+ metaKey: event.metaKey
218
+ });
219
+ newEvent.__strapi_redispatched = true;
220
+ element.dispatchEvent(newEvent);
221
+ }, DOUBLE_CLICK_TIMEOUT);
222
+ pendingClicks.set(element, timeout);
163
223
  };
164
- const doubleClickHandler = ()=>{
224
+ const doubleClickHandler = (event)=>{
225
+ // Prevent the default behavior on double-click
226
+ event.preventDefault();
227
+ event.stopPropagation();
228
+ // Clear any pending single-click action
229
+ const existingTimeout = pendingClicks.get(element);
230
+ if (existingTimeout) {
231
+ clearTimeout(existingTimeout);
232
+ pendingClicks.delete(element);
233
+ }
165
234
  const sourceAttribute = element.getAttribute(SOURCE_ATTRIBUTE);
166
235
  if (sourceAttribute) {
167
236
  const rect = element.getBoundingClientRect();
@@ -184,25 +253,20 @@
184
253
  event.preventDefault();
185
254
  }
186
255
  };
187
- element.addEventListener('mouseenter', mouseEnterHandler);
188
- element.addEventListener('mouseleave', mouseLeaveHandler);
189
- element.addEventListener('dblclick', doubleClickHandler);
190
- element.addEventListener('mousedown', mouseDownHandler);
256
+ highlight.addEventListener('click', clickHandler);
257
+ highlight.addEventListener('dblclick', doubleClickHandler);
258
+ highlight.addEventListener('mousedown', mouseDownHandler);
191
259
  // Store event listeners for cleanup
192
260
  eventListeners.push({
193
- element,
194
- type: 'mouseenter',
195
- handler: mouseEnterHandler
261
+ element: highlight,
262
+ type: 'click',
263
+ handler: clickHandler
196
264
  }, {
197
- element,
198
- type: 'mouseleave',
199
- handler: mouseLeaveHandler
200
- }, {
201
- element,
265
+ element: highlight,
202
266
  type: 'dblclick',
203
267
  handler: doubleClickHandler
204
268
  }, {
205
- element,
269
+ element: highlight,
206
270
  type: 'mousedown',
207
271
  handler: mouseDownHandler
208
272
  });
@@ -213,15 +277,21 @@
213
277
  const removeHighlightForElement = (element)=>{
214
278
  const highlight = elementsToHighlight.get(element);
215
279
  if (!highlight) return;
280
+ // Clear any pending click timeout for this element
281
+ const pendingTimeout = pendingClicks.get(element);
282
+ if (pendingTimeout) {
283
+ window.clearTimeout(pendingTimeout);
284
+ pendingClicks.delete(element);
285
+ }
216
286
  highlight.remove();
217
287
  elementsToHighlight.delete(element);
218
- // Remove event listeners for this element
219
- const listenersToRemove = eventListeners.filter((listener)=>listener.element === element);
288
+ // Remove event listeners for this highlight
289
+ const listenersToRemove = eventListeners.filter((listener)=>listener.element === highlight);
220
290
  listenersToRemove.forEach(({ element, type, handler })=>{
221
291
  element.removeEventListener(type, handler);
222
292
  });
223
- // Mutate eventListeners to remove listeners for this element
224
- eventListeners.splice(0, eventListeners.length, ...eventListeners.filter((listener)=>listener.element !== element));
293
+ // Mutate eventListeners to remove listeners for this highlight
294
+ eventListeners.splice(0, eventListeners.length, ...eventListeners.filter((listener)=>listener.element !== highlight));
225
295
  };
226
296
  // Process all existing elements with source attributes
227
297
  const initialElements = window.document.querySelectorAll(`[${SOURCE_ATTRIBUTE}]`);
@@ -245,7 +315,11 @@
245
315
  setFocusedField: (field)=>{
246
316
  focusedField = field;
247
317
  },
248
- getFocusedField: ()=>focusedField
318
+ getFocusedField: ()=>focusedField,
319
+ clearAllPendingClicks: ()=>{
320
+ pendingClicks.forEach((timeout)=>clearTimeout(timeout));
321
+ pendingClicks.clear();
322
+ }
249
323
  };
250
324
  };
251
325
  /**
@@ -364,8 +438,7 @@
364
438
  if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_CHANGE) {
365
439
  const { field, value } = event.data.payload;
366
440
  if (!field) return;
367
- const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}="${field}"]`);
368
- matchingElements.forEach((element)=>{
441
+ getElementsByPath(field).forEach((element)=>{
369
442
  if (element instanceof HTMLElement) {
370
443
  element.textContent = value || '';
371
444
  }
@@ -380,17 +453,21 @@
380
453
  if (!field) return;
381
454
  // Clear existing focused highlights
382
455
  highlightManager.focusedHighlights.forEach((highlight)=>{
383
- highlight.style.outlineColor = 'transparent';
456
+ highlight.classList.remove('strapi-highlight-focused');
384
457
  });
385
458
  highlightManager.focusedHighlights.length = 0;
386
459
  // Set new focused field and highlight matching elements
387
460
  highlightManager.setFocusedField(field);
388
- const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}="${field}"]`);
389
- matchingElements.forEach((element)=>{
461
+ getElementsByPath(field).forEach((element, index)=>{
462
+ if (index === 0) {
463
+ element.scrollIntoView({
464
+ behavior: 'smooth',
465
+ block: 'center'
466
+ });
467
+ }
390
468
  const highlight = highlightManager.highlights[Array.from(highlightManager.elements).indexOf(element)];
391
469
  if (highlight) {
392
- highlight.style.outlineColor = HIGHLIGHT_ACTIVE_COLOR;
393
- highlight.style.outlineWidth = '3px';
470
+ highlight.classList.add('strapi-highlight-focused');
394
471
  highlightManager.focusedHighlights.push(highlight);
395
472
  }
396
473
  });
@@ -401,8 +478,7 @@
401
478
  const { field } = event.data.payload;
402
479
  if (field !== highlightManager.getFocusedField()) return;
403
480
  highlightManager.focusedHighlights.forEach((highlight)=>{
404
- highlight.style.outlineColor = 'transparent';
405
- highlight.style.outlineWidth = '2px';
481
+ highlight.classList.remove('strapi-highlight-focused');
406
482
  });
407
483
  highlightManager.focusedHighlights.length = 0;
408
484
  highlightManager.setFocusedField(null);
@@ -420,29 +496,37 @@
420
496
  messageEventListener
421
497
  ];
422
498
  };
423
- const createCleanupSystem = (overlay, observers, scrollManager, eventHandlers)=>{
499
+ const createCleanupSystem = (overlay, observers, scrollManager, eventHandlers, highlightManager)=>{
424
500
  window.__strapi_previewCleanup = ()=>{
425
501
  observers.resizeObserver.disconnect();
426
502
  observers.highlightObserver.disconnect();
427
503
  observers.stegaObserver?.disconnect();
428
504
  // Clean up scroll listeners
429
505
  scrollManager.cleanup();
506
+ // Clear all pending click timeouts
507
+ highlightManager.clearAllPendingClicks();
430
508
  // Remove highlight event listeners
431
509
  eventHandlers.forEach(({ element, type, handler })=>{
432
510
  element.removeEventListener(type, handler);
433
511
  });
512
+ // Clean up CSS styles
513
+ const existingStyles = document.getElementById(HIGHLIGHT_STYLES_ID);
514
+ if (existingStyles) {
515
+ existingStyles.remove();
516
+ }
434
517
  overlay.remove();
435
518
  };
436
519
  };
437
520
  /* -----------------------------------------------------------------------------------------------
438
521
  * Orchestration
439
522
  * ---------------------------------------------------------------------------------------------*/ setupStegaDOMObserver().then((stegaObserver)=>{
523
+ createHighlightStyles();
440
524
  const overlay = createOverlaySystem();
441
525
  const highlightManager = createHighlightManager(overlay);
442
526
  const observers = setupObservers(highlightManager, stegaObserver);
443
527
  const scrollManager = setupScrollManagement(highlightManager);
444
528
  const eventHandlers = setupEventHandlers(highlightManager);
445
- createCleanupSystem(overlay, observers, scrollManager, eventHandlers);
529
+ createCleanupSystem(overlay, observers, scrollManager, eventHandlers, highlightManager);
446
530
  });
447
531
  };
448
532