@strapi/content-manager 5.23.0 → 5.23.1

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 (74) hide show
  1. package/dist/admin/components/LeftMenu.js +13 -15
  2. package/dist/admin/components/LeftMenu.js.map +1 -1
  3. package/dist/admin/components/LeftMenu.mjs +14 -16
  4. package/dist/admin/components/LeftMenu.mjs.map +1 -1
  5. package/dist/admin/components/Widgets.js +4 -2
  6. package/dist/admin/components/Widgets.js.map +1 -1
  7. package/dist/admin/components/Widgets.mjs +4 -2
  8. package/dist/admin/components/Widgets.mjs.map +1 -1
  9. package/dist/admin/pages/EditView/EditViewPage.js +3 -11
  10. package/dist/admin/pages/EditView/EditViewPage.js.map +1 -1
  11. package/dist/admin/pages/EditView/EditViewPage.mjs +4 -12
  12. package/dist/admin/pages/EditView/EditViewPage.mjs.map +1 -1
  13. package/dist/admin/pages/EditView/components/Blocker.js +18 -0
  14. package/dist/admin/pages/EditView/components/Blocker.js.map +1 -0
  15. package/dist/admin/pages/EditView/components/Blocker.mjs +16 -0
  16. package/dist/admin/pages/EditView/components/Blocker.mjs.map +1 -0
  17. package/dist/admin/pages/EditView/components/InputRenderer.js +15 -5
  18. package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
  19. package/dist/admin/pages/EditView/components/InputRenderer.mjs +15 -5
  20. package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
  21. package/dist/admin/pages/EditView/utils/data.js +26 -7
  22. package/dist/admin/pages/EditView/utils/data.js.map +1 -1
  23. package/dist/admin/pages/EditView/utils/data.mjs +26 -7
  24. package/dist/admin/pages/EditView/utils/data.mjs.map +1 -1
  25. package/dist/admin/preview/components/InputPopover.js +73 -0
  26. package/dist/admin/preview/components/InputPopover.js.map +1 -0
  27. package/dist/admin/preview/components/InputPopover.mjs +70 -0
  28. package/dist/admin/preview/components/InputPopover.mjs.map +1 -0
  29. package/dist/admin/preview/hooks/usePreviewInputManager.js +67 -0
  30. package/dist/admin/preview/hooks/usePreviewInputManager.js.map +1 -0
  31. package/dist/admin/preview/hooks/usePreviewInputManager.mjs +46 -0
  32. package/dist/admin/preview/hooks/usePreviewInputManager.mjs.map +1 -0
  33. package/dist/admin/preview/pages/Preview.js +119 -118
  34. package/dist/admin/preview/pages/Preview.js.map +1 -1
  35. package/dist/admin/preview/pages/Preview.mjs +120 -119
  36. package/dist/admin/preview/pages/Preview.mjs.map +1 -1
  37. package/dist/admin/preview/utils/constants.js +2 -1
  38. package/dist/admin/preview/utils/constants.js.map +1 -1
  39. package/dist/admin/preview/utils/constants.mjs +2 -2
  40. package/dist/admin/preview/utils/constants.mjs.map +1 -1
  41. package/dist/admin/preview/utils/getSendMessage.js +22 -0
  42. package/dist/admin/preview/utils/getSendMessage.js.map +1 -0
  43. package/dist/admin/preview/utils/getSendMessage.mjs +20 -0
  44. package/dist/admin/preview/utils/getSendMessage.mjs.map +1 -0
  45. package/dist/admin/preview/utils/previewScript.js +103 -10
  46. package/dist/admin/preview/utils/previewScript.js.map +1 -1
  47. package/dist/admin/preview/utils/previewScript.mjs +103 -10
  48. package/dist/admin/preview/utils/previewScript.mjs.map +1 -1
  49. package/dist/admin/src/pages/EditView/components/Blocker.d.ts +5 -0
  50. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +1 -1
  51. package/dist/admin/src/preview/components/InputPopover.d.ts +6 -0
  52. package/dist/admin/src/preview/hooks/usePreviewInputManager.d.ts +4 -0
  53. package/dist/admin/src/preview/pages/Preview.d.ts +8 -0
  54. package/dist/admin/src/preview/utils/constants.d.ts +4 -1
  55. package/dist/admin/src/preview/utils/getSendMessage.d.ts +11 -0
  56. package/dist/admin/src/preview/utils/previewScript.d.ts +5 -1
  57. package/dist/admin/translations/en.json.js +1 -0
  58. package/dist/admin/translations/en.json.js.map +1 -1
  59. package/dist/admin/translations/en.json.mjs +1 -0
  60. package/dist/admin/translations/en.json.mjs.map +1 -1
  61. package/dist/admin/translations/es.json.js +1 -0
  62. package/dist/admin/translations/es.json.js.map +1 -1
  63. package/dist/admin/translations/es.json.mjs +1 -0
  64. package/dist/admin/translations/es.json.mjs.map +1 -1
  65. package/dist/admin/translations/fr.json.js +1 -0
  66. package/dist/admin/translations/fr.json.js.map +1 -1
  67. package/dist/admin/translations/fr.json.mjs +1 -0
  68. package/dist/admin/translations/fr.json.mjs.map +1 -1
  69. package/dist/server/homepage/services/homepage.js +1 -1
  70. package/dist/server/homepage/services/homepage.js.map +1 -1
  71. package/dist/server/homepage/services/homepage.mjs +1 -1
  72. package/dist/server/homepage/services/homepage.mjs.map +1 -1
  73. package/dist/server/src/homepage/services/homepage.d.ts.map +1 -1
  74. package/package.json +5 -5
@@ -11,10 +11,14 @@
11
11
  * Params
12
12
  * ---------------------------------------------------------------------------------------------*/ const HIGHLIGHT_PADDING = 2; // in pixels
13
13
  const HIGHLIGHT_HOVER_COLOR = window.STRAPI_HIGHLIGHT_HOVER_COLOR ?? '#4945ff'; // dark primary500
14
+ const HIGHLIGHT_ACTIVE_COLOR = window.STRAPI_HIGHLIGHT_ACTIVE_COLOR ?? '#7b79ff'; // dark primary600
14
15
  const SOURCE_ATTRIBUTE = 'data-strapi-source';
15
16
  const OVERLAY_ID = 'strapi-preview-overlay';
16
17
  const INTERNAL_EVENTS = {
17
- DUMMY_EVENT: 'dummyEvent'
18
+ STRAPI_FIELD_FOCUS: 'strapiFieldFocus',
19
+ STRAPI_FIELD_BLUR: 'strapiFieldBlur',
20
+ STRAPI_FIELD_CHANGE: 'strapiFieldChange',
21
+ STRAPI_FIELD_FOCUS_INTENT: 'strapiFieldFocusIntent'
18
22
  };
19
23
  /**
20
24
  * Calling the function in no-run mode lets us retrieve the constants from other files and keep
@@ -26,6 +30,14 @@
26
30
  };
27
31
  }
28
32
  /* -----------------------------------------------------------------------------------------------
33
+ * Utils
34
+ * ---------------------------------------------------------------------------------------------*/ const sendMessage = (type, payload)=>{
35
+ window.parent.postMessage({
36
+ type,
37
+ payload
38
+ }, '*');
39
+ };
40
+ /* -----------------------------------------------------------------------------------------------
29
41
  * Functionality pieces
30
42
  * ---------------------------------------------------------------------------------------------*/ const createOverlaySystem = ()=>{
31
43
  // Clean up before creating a new overlay so we can safely call previewScript multiple times
@@ -47,8 +59,10 @@
47
59
  };
48
60
  const createHighlightManager = (overlay)=>{
49
61
  const elements = window.document.querySelectorAll(`[${SOURCE_ATTRIBUTE}]`);
50
- const highlights = [];
51
62
  const eventListeners = [];
63
+ const highlights = [];
64
+ const focusedHighlights = [];
65
+ let focusedField = null;
52
66
  const drawHighlight = (target, highlight)=>{
53
67
  if (!highlight) return;
54
68
  const rect = target.getBoundingClientRect();
@@ -78,15 +92,31 @@
78
92
  `;
79
93
  // Move hover detection to the underlying element
80
94
  const mouseEnterHandler = ()=>{
81
- highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;
95
+ if (!highlightManager.focusedHighlights.includes(highlight)) {
96
+ highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;
97
+ }
82
98
  };
83
99
  const mouseLeaveHandler = ()=>{
84
- highlight.style.outlineColor = 'transparent';
100
+ if (!highlightManager.focusedHighlights.includes(highlight)) {
101
+ highlight.style.outlineColor = 'transparent';
102
+ }
85
103
  };
86
104
  const doubleClickHandler = ()=>{
87
- // TODO: handle for real
88
- // eslint-disable-next-line no-console
89
- console.log('Double click on highlight', element);
105
+ const sourceAttribute = element.getAttribute(SOURCE_ATTRIBUTE);
106
+ if (sourceAttribute) {
107
+ const rect = element.getBoundingClientRect();
108
+ sendMessage(INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT, {
109
+ path: sourceAttribute,
110
+ position: {
111
+ top: rect.top,
112
+ left: rect.left,
113
+ right: rect.right,
114
+ bottom: rect.bottom,
115
+ width: rect.width,
116
+ height: rect.height
117
+ }
118
+ });
119
+ }
90
120
  };
91
121
  const mouseDownHandler = (event)=>{
92
122
  // Prevent default multi click to select behavior
@@ -124,7 +154,13 @@
124
154
  return {
125
155
  elements,
126
156
  updateAllHighlights,
127
- eventListeners
157
+ eventListeners,
158
+ highlights,
159
+ focusedHighlights,
160
+ setFocusedField: (field)=>{
161
+ focusedField = field;
162
+ },
163
+ getFocusedField: ()=>focusedField
128
164
  };
129
165
  };
130
166
  const setupObservers = (highlightManager)=>{
@@ -168,8 +204,65 @@
168
204
  };
169
205
  };
170
206
  const setupEventHandlers = (highlightManager)=>{
171
- // TODO: The listeners for postMessage events will go here
172
- return highlightManager.eventListeners;
207
+ const handleMessage = (event)=>{
208
+ if (!event.data?.type) return;
209
+ // The user typed in an input, reflect the change in the preview
210
+ if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_CHANGE) {
211
+ const { field, value } = event.data.payload;
212
+ if (!field) return;
213
+ const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}="${field}"]`);
214
+ matchingElements.forEach((element)=>{
215
+ if (element instanceof HTMLElement) {
216
+ element.textContent = value || '';
217
+ }
218
+ });
219
+ return;
220
+ }
221
+ // The user focused a new input, update the highlights in the preview
222
+ if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS) {
223
+ const { field } = event.data.payload;
224
+ if (!field) return;
225
+ // Clear existing focused highlights
226
+ highlightManager.focusedHighlights.forEach((highlight)=>{
227
+ highlight.style.outlineColor = 'transparent';
228
+ });
229
+ highlightManager.focusedHighlights.length = 0;
230
+ // Set new focused field and highlight matching elements
231
+ highlightManager.setFocusedField(field);
232
+ const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}="${field}"]`);
233
+ matchingElements.forEach((element)=>{
234
+ const highlight = highlightManager.highlights[Array.from(highlightManager.elements).indexOf(element)];
235
+ if (highlight) {
236
+ highlight.style.outlineColor = HIGHLIGHT_ACTIVE_COLOR;
237
+ highlight.style.outlineWidth = '3px';
238
+ highlightManager.focusedHighlights.push(highlight);
239
+ }
240
+ });
241
+ return;
242
+ }
243
+ // The user is no longer focusing an input, remove the highlights
244
+ if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_BLUR) {
245
+ const { field } = event.data.payload;
246
+ if (field !== highlightManager.getFocusedField()) return;
247
+ highlightManager.focusedHighlights.forEach((highlight)=>{
248
+ highlight.style.outlineColor = 'transparent';
249
+ highlight.style.outlineWidth = '2px';
250
+ });
251
+ highlightManager.focusedHighlights.length = 0;
252
+ highlightManager.setFocusedField(null);
253
+ }
254
+ };
255
+ window.addEventListener('message', handleMessage);
256
+ // Add the message handler to the cleanup list
257
+ const messageEventListener = {
258
+ element: window,
259
+ type: 'message',
260
+ handler: handleMessage
261
+ };
262
+ return [
263
+ ...highlightManager.eventListeners,
264
+ messageEventListener
265
+ ];
173
266
  };
174
267
  const createCleanupSystem = (overlay, observers, eventHandlers)=>{
175
268
  window.__strapi_previewCleanup = ()=>{
@@ -1 +1 @@
1
- {"version":3,"file":"previewScript.js","sources":["../../../../admin/src/preview/utils/previewScript.ts"],"sourcesContent":["// NOTE: This override is for the properties on _user's site_, it's not about Strapi Admin.\ndeclare global {\n interface Window {\n __strapi_previewCleanup?: () => void;\n STRAPI_HIGHLIGHT_HOVER_COLOR?: string;\n }\n}\n\n/**\n * previewScript will be injected into the preview iframe after being stringified.\n * Therefore it CANNOT use any imports, or refer to any variables outside of its own scope.\n * It's why many functions are defined within previewScript, it's the only way to avoid going full spaghetti.\n * To get a better overview of everything previewScript does, go to the orchestration part at its end.\n */\nconst previewScript = (shouldRun = true) => {\n /* -----------------------------------------------------------------------------------------------\n * Params\n * ---------------------------------------------------------------------------------------------*/\n const HIGHLIGHT_PADDING = 2; // in pixels\n const HIGHLIGHT_HOVER_COLOR = window.STRAPI_HIGHLIGHT_HOVER_COLOR ?? '#4945ff'; // dark primary500\n const SOURCE_ATTRIBUTE = 'data-strapi-source';\n const OVERLAY_ID = 'strapi-preview-overlay';\n const INTERNAL_EVENTS = {\n DUMMY_EVENT: 'dummyEvent',\n } as const;\n\n /**\n * Calling the function in no-run mode lets us retrieve the constants from other files and keep\n * a single source of truth for them. It's the only way to do this because this script can't\n * refer to any variables outside of its own scope, because it's stringified before it's run.\n */\n if (!shouldRun) {\n return { INTERNAL_EVENTS };\n }\n\n /* -----------------------------------------------------------------------------------------------\n * Functionality pieces\n * ---------------------------------------------------------------------------------------------*/\n\n const createOverlaySystem = () => {\n // Clean up before creating a new overlay so we can safely call previewScript multiple times\n window.__strapi_previewCleanup?.();\n document.getElementById(OVERLAY_ID)?.remove();\n\n const overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 9999;\n `;\n\n window.document.body.appendChild(overlay);\n return overlay;\n };\n\n type EventListenersList = Array<{\n element: HTMLElement;\n type: keyof HTMLElementEventMap;\n handler: EventListener;\n }>;\n\n const createHighlightManager = (overlay: HTMLElement) => {\n const elements = window.document.querySelectorAll(`[${SOURCE_ATTRIBUTE}]`);\n const highlights: HTMLElement[] = [];\n const eventListeners: EventListenersList = [];\n\n const drawHighlight = (target: Element, highlight: HTMLElement) => {\n if (!highlight) return;\n\n const rect = target.getBoundingClientRect();\n highlight.style.width = `${rect.width + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.height = `${rect.height + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.transform = `translate(${rect.left - HIGHLIGHT_PADDING}px, ${rect.top - HIGHLIGHT_PADDING}px)`;\n };\n\n const updateAllHighlights = () => {\n highlights.forEach((highlight, index) => {\n const element = elements[index];\n if (element && highlight) {\n drawHighlight(element, highlight);\n }\n });\n };\n\n elements.forEach((element) => {\n if (element instanceof HTMLElement) {\n const highlight = document.createElement('div');\n highlight.style.cssText = `\n position: absolute;\n outline: 2px solid transparent;\n pointer-events: none;\n border-radius: 2px;\n background-color: transparent;\n will-change: transform;\n transition: outline-color 0.1s ease-in-out;\n `;\n\n // Move hover detection to the underlying element\n const mouseEnterHandler = () => {\n highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;\n };\n const mouseLeaveHandler = () => {\n highlight.style.outlineColor = 'transparent';\n };\n const doubleClickHandler = () => {\n // TODO: handle for real\n // eslint-disable-next-line no-console\n console.log('Double click on highlight', element);\n };\n const mouseDownHandler = (event: MouseEvent) => {\n // Prevent default multi click to select behavior\n if (event.detail >= 2) {\n event.preventDefault();\n }\n };\n\n element.addEventListener('mouseenter', mouseEnterHandler);\n element.addEventListener('mouseleave', mouseLeaveHandler);\n element.addEventListener('dblclick', doubleClickHandler);\n element.addEventListener('mousedown', mouseDownHandler);\n\n // Store event listeners for cleanup\n eventListeners.push(\n { element, type: 'mouseenter', handler: mouseEnterHandler },\n { element, type: 'mouseleave', handler: mouseLeaveHandler },\n { element, type: 'dblclick', handler: doubleClickHandler },\n { element, type: 'mousedown', handler: mouseDownHandler as EventListener }\n );\n\n highlights.push(highlight);\n overlay.appendChild(highlight);\n\n drawHighlight(element, highlight);\n }\n });\n\n return {\n elements,\n updateAllHighlights,\n eventListeners,\n };\n };\n\n type HighlightManager = ReturnType<typeof createHighlightManager>;\n\n const setupObservers = (highlightManager: HighlightManager) => {\n const resizeObserver = new ResizeObserver(() => {\n highlightManager.updateAllHighlights();\n });\n\n highlightManager.elements.forEach((element: Element) => {\n resizeObserver.observe(element);\n });\n\n resizeObserver.observe(document.documentElement);\n\n const updateOnScroll = () => {\n highlightManager.updateAllHighlights();\n };\n\n const scrollableElements = new Set<Element | Window>();\n scrollableElements.add(window);\n\n // Find all scrollable ancestors for all tracked elements\n highlightManager.elements.forEach((element) => {\n let parent = element.parentElement;\n while (parent) {\n const computedStyle = window.getComputedStyle(parent);\n const overflow = computedStyle.overflow + computedStyle.overflowX + computedStyle.overflowY;\n\n if (overflow.includes('scroll') || overflow.includes('auto')) {\n scrollableElements.add(parent);\n }\n\n parent = parent.parentElement;\n }\n });\n\n // Add scroll listeners to all scrollable elements\n scrollableElements.forEach((element) => {\n if (element === window) {\n window.addEventListener('scroll', updateOnScroll);\n window.addEventListener('resize', updateOnScroll);\n } else {\n (element as Element).addEventListener('scroll', updateOnScroll);\n }\n });\n\n return {\n resizeObserver,\n updateOnScroll,\n scrollableElements,\n };\n };\n\n const setupEventHandlers = (highlightManager: HighlightManager) => {\n // TODO: The listeners for postMessage events will go here\n return highlightManager.eventListeners;\n };\n\n const createCleanupSystem = (\n overlay: HTMLElement,\n observers: ReturnType<typeof setupObservers>,\n eventHandlers: EventListenersList\n ) => {\n window.__strapi_previewCleanup = () => {\n observers.resizeObserver.disconnect();\n\n // Remove all scroll listeners\n observers.scrollableElements.forEach((element) => {\n if (element === window) {\n window.removeEventListener('scroll', observers.updateOnScroll);\n window.removeEventListener('resize', observers.updateOnScroll);\n } else {\n (element as Element).removeEventListener('scroll', observers.updateOnScroll);\n }\n });\n\n // Remove highlight event listeners\n eventHandlers.forEach(({ element, type, handler }) => {\n element.removeEventListener(type, handler);\n });\n\n overlay.remove();\n };\n };\n\n /* -----------------------------------------------------------------------------------------------\n * Orchestration\n * ---------------------------------------------------------------------------------------------*/\n\n const overlay = createOverlaySystem();\n const highlightManager = createHighlightManager(overlay);\n const observers = setupObservers(highlightManager);\n const eventHandlers = setupEventHandlers(highlightManager);\n createCleanupSystem(overlay, observers, eventHandlers);\n};\n\nexport { previewScript };\n"],"names":["previewScript","shouldRun","HIGHLIGHT_PADDING","HIGHLIGHT_HOVER_COLOR","window","STRAPI_HIGHLIGHT_HOVER_COLOR","SOURCE_ATTRIBUTE","OVERLAY_ID","INTERNAL_EVENTS","DUMMY_EVENT","createOverlaySystem","__strapi_previewCleanup","document","getElementById","remove","overlay","createElement","id","style","cssText","body","appendChild","createHighlightManager","elements","querySelectorAll","highlights","eventListeners","drawHighlight","target","highlight","rect","getBoundingClientRect","width","height","transform","left","top","updateAllHighlights","forEach","index","element","HTMLElement","mouseEnterHandler","outlineColor","mouseLeaveHandler","doubleClickHandler","console","log","mouseDownHandler","event","detail","preventDefault","addEventListener","push","type","handler","setupObservers","highlightManager","resizeObserver","ResizeObserver","observe","documentElement","updateOnScroll","scrollableElements","Set","add","parent","parentElement","computedStyle","getComputedStyle","overflow","overflowX","overflowY","includes","setupEventHandlers","createCleanupSystem","observers","eventHandlers","disconnect","removeEventListener"],"mappings":"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"}
1
+ {"version":3,"file":"previewScript.js","sources":["../../../../admin/src/preview/utils/previewScript.ts"],"sourcesContent":["// NOTE: This override is for the properties on _user's site_, it's not about Strapi Admin.\ndeclare global {\n interface Window {\n __strapi_previewCleanup?: () => void;\n STRAPI_HIGHLIGHT_HOVER_COLOR?: string;\n STRAPI_HIGHLIGHT_ACTIVE_COLOR?: string;\n }\n}\n\n/**\n * previewScript will be injected into the preview iframe after being stringified.\n * Therefore it CANNOT use any imports, or refer to any variables outside of its own scope.\n * It's why many functions are defined within previewScript, it's the only way to avoid going full spaghetti.\n * To get a better overview of everything previewScript does, go to the orchestration part at its end.\n */\nconst previewScript = (shouldRun = true) => {\n /* -----------------------------------------------------------------------------------------------\n * Params\n * ---------------------------------------------------------------------------------------------*/\n const HIGHLIGHT_PADDING = 2; // in pixels\n const HIGHLIGHT_HOVER_COLOR = window.STRAPI_HIGHLIGHT_HOVER_COLOR ?? '#4945ff'; // dark primary500\n const HIGHLIGHT_ACTIVE_COLOR = window.STRAPI_HIGHLIGHT_ACTIVE_COLOR ?? '#7b79ff'; // dark primary600\n\n const SOURCE_ATTRIBUTE = 'data-strapi-source';\n const OVERLAY_ID = 'strapi-preview-overlay';\n const INTERNAL_EVENTS = {\n STRAPI_FIELD_FOCUS: 'strapiFieldFocus',\n STRAPI_FIELD_BLUR: 'strapiFieldBlur',\n STRAPI_FIELD_CHANGE: 'strapiFieldChange',\n STRAPI_FIELD_FOCUS_INTENT: 'strapiFieldFocusIntent',\n } as const;\n\n /**\n * Calling the function in no-run mode lets us retrieve the constants from other files and keep\n * a single source of truth for them. It's the only way to do this because this script can't\n * refer to any variables outside of its own scope, because it's stringified before it's run.\n */\n if (!shouldRun) {\n return { INTERNAL_EVENTS };\n }\n\n /* -----------------------------------------------------------------------------------------------\n * Utils\n * ---------------------------------------------------------------------------------------------*/\n\n const sendMessage = (\n type: (typeof INTERNAL_EVENTS)[keyof typeof INTERNAL_EVENTS],\n payload: unknown\n ) => {\n window.parent.postMessage({ type, payload }, '*');\n };\n\n /* -----------------------------------------------------------------------------------------------\n * Functionality pieces\n * ---------------------------------------------------------------------------------------------*/\n\n const createOverlaySystem = () => {\n // Clean up before creating a new overlay so we can safely call previewScript multiple times\n window.__strapi_previewCleanup?.();\n document.getElementById(OVERLAY_ID)?.remove();\n\n const overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 9999;\n `;\n\n window.document.body.appendChild(overlay);\n return overlay;\n };\n\n type EventListenersList = Array<{\n element: HTMLElement | Window;\n type: keyof HTMLElementEventMap | 'message';\n handler: EventListener;\n }>;\n\n const createHighlightManager = (overlay: HTMLElement) => {\n const elements = window.document.querySelectorAll(`[${SOURCE_ATTRIBUTE}]`);\n const eventListeners: EventListenersList = [];\n const highlights: HTMLElement[] = [];\n const focusedHighlights: HTMLElement[] = [];\n let focusedField: string | null = null;\n\n const drawHighlight = (target: Element, highlight: HTMLElement) => {\n if (!highlight) return;\n\n const rect = target.getBoundingClientRect();\n highlight.style.width = `${rect.width + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.height = `${rect.height + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.transform = `translate(${rect.left - HIGHLIGHT_PADDING}px, ${rect.top - HIGHLIGHT_PADDING}px)`;\n };\n\n const updateAllHighlights = () => {\n highlights.forEach((highlight, index) => {\n const element = elements[index];\n if (element && highlight) {\n drawHighlight(element, highlight);\n }\n });\n };\n\n elements.forEach((element) => {\n if (element instanceof HTMLElement) {\n const highlight = document.createElement('div');\n highlight.style.cssText = `\n position: absolute;\n outline: 2px solid transparent;\n pointer-events: none;\n border-radius: 2px;\n background-color: transparent;\n will-change: transform;\n transition: outline-color 0.1s ease-in-out;\n `;\n\n // Move hover detection to the underlying element\n const mouseEnterHandler = () => {\n if (!highlightManager.focusedHighlights.includes(highlight)) {\n highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;\n }\n };\n const mouseLeaveHandler = () => {\n if (!highlightManager.focusedHighlights.includes(highlight)) {\n highlight.style.outlineColor = 'transparent';\n }\n };\n const doubleClickHandler = () => {\n const sourceAttribute = element.getAttribute(SOURCE_ATTRIBUTE);\n if (sourceAttribute) {\n const rect = element.getBoundingClientRect();\n sendMessage(INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT, {\n path: sourceAttribute,\n position: {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n },\n });\n }\n };\n const mouseDownHandler = (event: MouseEvent) => {\n // Prevent default multi click to select behavior\n if (event.detail >= 2) {\n event.preventDefault();\n }\n };\n\n element.addEventListener('mouseenter', mouseEnterHandler);\n element.addEventListener('mouseleave', mouseLeaveHandler);\n element.addEventListener('dblclick', doubleClickHandler);\n element.addEventListener('mousedown', mouseDownHandler);\n\n // Store event listeners for cleanup\n eventListeners.push(\n { element, type: 'mouseenter', handler: mouseEnterHandler },\n { element, type: 'mouseleave', handler: mouseLeaveHandler },\n { element, type: 'dblclick', handler: doubleClickHandler },\n { element, type: 'mousedown', handler: mouseDownHandler as EventListener }\n );\n\n highlights.push(highlight);\n overlay.appendChild(highlight);\n\n drawHighlight(element, highlight);\n }\n });\n\n return {\n elements,\n updateAllHighlights,\n eventListeners,\n highlights,\n focusedHighlights,\n setFocusedField: (field: string | null) => {\n focusedField = field;\n },\n getFocusedField: () => focusedField,\n };\n };\n\n type HighlightManager = ReturnType<typeof createHighlightManager>;\n\n const setupObservers = (highlightManager: HighlightManager) => {\n const resizeObserver = new ResizeObserver(() => {\n highlightManager.updateAllHighlights();\n });\n\n highlightManager.elements.forEach((element: Element) => {\n resizeObserver.observe(element);\n });\n\n resizeObserver.observe(document.documentElement);\n\n const updateOnScroll = () => {\n highlightManager.updateAllHighlights();\n };\n\n const scrollableElements = new Set<Element | Window>();\n scrollableElements.add(window);\n\n // Find all scrollable ancestors for all tracked elements\n highlightManager.elements.forEach((element) => {\n let parent = element.parentElement;\n while (parent) {\n const computedStyle = window.getComputedStyle(parent);\n const overflow = computedStyle.overflow + computedStyle.overflowX + computedStyle.overflowY;\n\n if (overflow.includes('scroll') || overflow.includes('auto')) {\n scrollableElements.add(parent);\n }\n\n parent = parent.parentElement;\n }\n });\n\n // Add scroll listeners to all scrollable elements\n scrollableElements.forEach((element) => {\n if (element === window) {\n window.addEventListener('scroll', updateOnScroll);\n window.addEventListener('resize', updateOnScroll);\n } else {\n element.addEventListener('scroll', updateOnScroll);\n }\n });\n\n return {\n resizeObserver,\n updateOnScroll,\n scrollableElements,\n };\n };\n\n const setupEventHandlers = (highlightManager: HighlightManager) => {\n const handleMessage = (event: MessageEvent) => {\n if (!event.data?.type) return;\n\n // The user typed in an input, reflect the change in the preview\n if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_CHANGE) {\n const { field, value } = event.data.payload;\n if (!field) return;\n\n const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}=\"${field}\"]`);\n matchingElements.forEach((element) => {\n if (element instanceof HTMLElement) {\n element.textContent = value || '';\n }\n });\n return;\n }\n\n // The user focused a new input, update the highlights in the preview\n if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS) {\n const { field } = event.data.payload;\n if (!field) return;\n\n // Clear existing focused highlights\n highlightManager.focusedHighlights.forEach((highlight: HTMLElement) => {\n highlight.style.outlineColor = 'transparent';\n });\n highlightManager.focusedHighlights.length = 0;\n\n // Set new focused field and highlight matching elements\n highlightManager.setFocusedField(field);\n const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}=\"${field}\"]`);\n matchingElements.forEach((element) => {\n const highlight =\n highlightManager.highlights[Array.from(highlightManager.elements).indexOf(element)];\n if (highlight) {\n highlight.style.outlineColor = HIGHLIGHT_ACTIVE_COLOR;\n highlight.style.outlineWidth = '3px';\n highlightManager.focusedHighlights.push(highlight);\n }\n });\n return;\n }\n\n // The user is no longer focusing an input, remove the highlights\n if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_BLUR) {\n const { field } = event.data.payload;\n if (field !== highlightManager.getFocusedField()) return;\n\n highlightManager.focusedHighlights.forEach((highlight: HTMLElement) => {\n highlight.style.outlineColor = 'transparent';\n highlight.style.outlineWidth = '2px';\n });\n highlightManager.focusedHighlights.length = 0;\n highlightManager.setFocusedField(null);\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n // Add the message handler to the cleanup list\n const messageEventListener = {\n element: window,\n type: 'message' as keyof HTMLElementEventMap,\n handler: handleMessage as EventListener,\n };\n\n return [...highlightManager.eventListeners, messageEventListener];\n };\n\n const createCleanupSystem = (\n overlay: HTMLElement,\n observers: ReturnType<typeof setupObservers>,\n eventHandlers: EventListenersList\n ) => {\n window.__strapi_previewCleanup = () => {\n observers.resizeObserver.disconnect();\n\n // Remove all scroll listeners\n observers.scrollableElements.forEach((element) => {\n if (element === window) {\n window.removeEventListener('scroll', observers.updateOnScroll);\n window.removeEventListener('resize', observers.updateOnScroll);\n } else {\n (element as Element).removeEventListener('scroll', observers.updateOnScroll);\n }\n });\n\n // Remove highlight event listeners\n eventHandlers.forEach(({ element, type, handler }) => {\n element.removeEventListener(type, handler);\n });\n\n overlay.remove();\n };\n };\n\n /* -----------------------------------------------------------------------------------------------\n * Orchestration\n * ---------------------------------------------------------------------------------------------*/\n\n const overlay = createOverlaySystem();\n const highlightManager = createHighlightManager(overlay);\n const observers = setupObservers(highlightManager);\n const eventHandlers = setupEventHandlers(highlightManager);\n createCleanupSystem(overlay, observers, eventHandlers);\n};\n\nexport { previewScript };\n"],"names":["previewScript","shouldRun","HIGHLIGHT_PADDING","HIGHLIGHT_HOVER_COLOR","window","STRAPI_HIGHLIGHT_HOVER_COLOR","HIGHLIGHT_ACTIVE_COLOR","STRAPI_HIGHLIGHT_ACTIVE_COLOR","SOURCE_ATTRIBUTE","OVERLAY_ID","INTERNAL_EVENTS","STRAPI_FIELD_FOCUS","STRAPI_FIELD_BLUR","STRAPI_FIELD_CHANGE","STRAPI_FIELD_FOCUS_INTENT","sendMessage","type","payload","parent","postMessage","createOverlaySystem","__strapi_previewCleanup","document","getElementById","remove","overlay","createElement","id","style","cssText","body","appendChild","createHighlightManager","elements","querySelectorAll","eventListeners","highlights","focusedHighlights","focusedField","drawHighlight","target","highlight","rect","getBoundingClientRect","width","height","transform","left","top","updateAllHighlights","forEach","index","element","HTMLElement","mouseEnterHandler","highlightManager","includes","outlineColor","mouseLeaveHandler","doubleClickHandler","sourceAttribute","getAttribute","path","position","right","bottom","mouseDownHandler","event","detail","preventDefault","addEventListener","push","handler","setFocusedField","field","getFocusedField","setupObservers","resizeObserver","ResizeObserver","observe","documentElement","updateOnScroll","scrollableElements","Set","add","parentElement","computedStyle","getComputedStyle","overflow","overflowX","overflowY","setupEventHandlers","handleMessage","data","value","matchingElements","textContent","length","Array","from","indexOf","outlineWidth","messageEventListener","createCleanupSystem","observers","eventHandlers","disconnect","removeEventListener"],"mappings":"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"}
@@ -9,10 +9,14 @@
9
9
  * Params
10
10
  * ---------------------------------------------------------------------------------------------*/ const HIGHLIGHT_PADDING = 2; // in pixels
11
11
  const HIGHLIGHT_HOVER_COLOR = window.STRAPI_HIGHLIGHT_HOVER_COLOR ?? '#4945ff'; // dark primary500
12
+ const HIGHLIGHT_ACTIVE_COLOR = window.STRAPI_HIGHLIGHT_ACTIVE_COLOR ?? '#7b79ff'; // dark primary600
12
13
  const SOURCE_ATTRIBUTE = 'data-strapi-source';
13
14
  const OVERLAY_ID = 'strapi-preview-overlay';
14
15
  const INTERNAL_EVENTS = {
15
- DUMMY_EVENT: 'dummyEvent'
16
+ STRAPI_FIELD_FOCUS: 'strapiFieldFocus',
17
+ STRAPI_FIELD_BLUR: 'strapiFieldBlur',
18
+ STRAPI_FIELD_CHANGE: 'strapiFieldChange',
19
+ STRAPI_FIELD_FOCUS_INTENT: 'strapiFieldFocusIntent'
16
20
  };
17
21
  /**
18
22
  * Calling the function in no-run mode lets us retrieve the constants from other files and keep
@@ -24,6 +28,14 @@
24
28
  };
25
29
  }
26
30
  /* -----------------------------------------------------------------------------------------------
31
+ * Utils
32
+ * ---------------------------------------------------------------------------------------------*/ const sendMessage = (type, payload)=>{
33
+ window.parent.postMessage({
34
+ type,
35
+ payload
36
+ }, '*');
37
+ };
38
+ /* -----------------------------------------------------------------------------------------------
27
39
  * Functionality pieces
28
40
  * ---------------------------------------------------------------------------------------------*/ const createOverlaySystem = ()=>{
29
41
  // Clean up before creating a new overlay so we can safely call previewScript multiple times
@@ -45,8 +57,10 @@
45
57
  };
46
58
  const createHighlightManager = (overlay)=>{
47
59
  const elements = window.document.querySelectorAll(`[${SOURCE_ATTRIBUTE}]`);
48
- const highlights = [];
49
60
  const eventListeners = [];
61
+ const highlights = [];
62
+ const focusedHighlights = [];
63
+ let focusedField = null;
50
64
  const drawHighlight = (target, highlight)=>{
51
65
  if (!highlight) return;
52
66
  const rect = target.getBoundingClientRect();
@@ -76,15 +90,31 @@
76
90
  `;
77
91
  // Move hover detection to the underlying element
78
92
  const mouseEnterHandler = ()=>{
79
- highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;
93
+ if (!highlightManager.focusedHighlights.includes(highlight)) {
94
+ highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;
95
+ }
80
96
  };
81
97
  const mouseLeaveHandler = ()=>{
82
- highlight.style.outlineColor = 'transparent';
98
+ if (!highlightManager.focusedHighlights.includes(highlight)) {
99
+ highlight.style.outlineColor = 'transparent';
100
+ }
83
101
  };
84
102
  const doubleClickHandler = ()=>{
85
- // TODO: handle for real
86
- // eslint-disable-next-line no-console
87
- console.log('Double click on highlight', element);
103
+ const sourceAttribute = element.getAttribute(SOURCE_ATTRIBUTE);
104
+ if (sourceAttribute) {
105
+ const rect = element.getBoundingClientRect();
106
+ sendMessage(INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT, {
107
+ path: sourceAttribute,
108
+ position: {
109
+ top: rect.top,
110
+ left: rect.left,
111
+ right: rect.right,
112
+ bottom: rect.bottom,
113
+ width: rect.width,
114
+ height: rect.height
115
+ }
116
+ });
117
+ }
88
118
  };
89
119
  const mouseDownHandler = (event)=>{
90
120
  // Prevent default multi click to select behavior
@@ -122,7 +152,13 @@
122
152
  return {
123
153
  elements,
124
154
  updateAllHighlights,
125
- eventListeners
155
+ eventListeners,
156
+ highlights,
157
+ focusedHighlights,
158
+ setFocusedField: (field)=>{
159
+ focusedField = field;
160
+ },
161
+ getFocusedField: ()=>focusedField
126
162
  };
127
163
  };
128
164
  const setupObservers = (highlightManager)=>{
@@ -166,8 +202,65 @@
166
202
  };
167
203
  };
168
204
  const setupEventHandlers = (highlightManager)=>{
169
- // TODO: The listeners for postMessage events will go here
170
- return highlightManager.eventListeners;
205
+ const handleMessage = (event)=>{
206
+ if (!event.data?.type) return;
207
+ // The user typed in an input, reflect the change in the preview
208
+ if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_CHANGE) {
209
+ const { field, value } = event.data.payload;
210
+ if (!field) return;
211
+ const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}="${field}"]`);
212
+ matchingElements.forEach((element)=>{
213
+ if (element instanceof HTMLElement) {
214
+ element.textContent = value || '';
215
+ }
216
+ });
217
+ return;
218
+ }
219
+ // The user focused a new input, update the highlights in the preview
220
+ if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS) {
221
+ const { field } = event.data.payload;
222
+ if (!field) return;
223
+ // Clear existing focused highlights
224
+ highlightManager.focusedHighlights.forEach((highlight)=>{
225
+ highlight.style.outlineColor = 'transparent';
226
+ });
227
+ highlightManager.focusedHighlights.length = 0;
228
+ // Set new focused field and highlight matching elements
229
+ highlightManager.setFocusedField(field);
230
+ const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}="${field}"]`);
231
+ matchingElements.forEach((element)=>{
232
+ const highlight = highlightManager.highlights[Array.from(highlightManager.elements).indexOf(element)];
233
+ if (highlight) {
234
+ highlight.style.outlineColor = HIGHLIGHT_ACTIVE_COLOR;
235
+ highlight.style.outlineWidth = '3px';
236
+ highlightManager.focusedHighlights.push(highlight);
237
+ }
238
+ });
239
+ return;
240
+ }
241
+ // The user is no longer focusing an input, remove the highlights
242
+ if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_BLUR) {
243
+ const { field } = event.data.payload;
244
+ if (field !== highlightManager.getFocusedField()) return;
245
+ highlightManager.focusedHighlights.forEach((highlight)=>{
246
+ highlight.style.outlineColor = 'transparent';
247
+ highlight.style.outlineWidth = '2px';
248
+ });
249
+ highlightManager.focusedHighlights.length = 0;
250
+ highlightManager.setFocusedField(null);
251
+ }
252
+ };
253
+ window.addEventListener('message', handleMessage);
254
+ // Add the message handler to the cleanup list
255
+ const messageEventListener = {
256
+ element: window,
257
+ type: 'message',
258
+ handler: handleMessage
259
+ };
260
+ return [
261
+ ...highlightManager.eventListeners,
262
+ messageEventListener
263
+ ];
171
264
  };
172
265
  const createCleanupSystem = (overlay, observers, eventHandlers)=>{
173
266
  window.__strapi_previewCleanup = ()=>{
@@ -1 +1 @@
1
- {"version":3,"file":"previewScript.mjs","sources":["../../../../admin/src/preview/utils/previewScript.ts"],"sourcesContent":["// NOTE: This override is for the properties on _user's site_, it's not about Strapi Admin.\ndeclare global {\n interface Window {\n __strapi_previewCleanup?: () => void;\n STRAPI_HIGHLIGHT_HOVER_COLOR?: string;\n }\n}\n\n/**\n * previewScript will be injected into the preview iframe after being stringified.\n * Therefore it CANNOT use any imports, or refer to any variables outside of its own scope.\n * It's why many functions are defined within previewScript, it's the only way to avoid going full spaghetti.\n * To get a better overview of everything previewScript does, go to the orchestration part at its end.\n */\nconst previewScript = (shouldRun = true) => {\n /* -----------------------------------------------------------------------------------------------\n * Params\n * ---------------------------------------------------------------------------------------------*/\n const HIGHLIGHT_PADDING = 2; // in pixels\n const HIGHLIGHT_HOVER_COLOR = window.STRAPI_HIGHLIGHT_HOVER_COLOR ?? '#4945ff'; // dark primary500\n const SOURCE_ATTRIBUTE = 'data-strapi-source';\n const OVERLAY_ID = 'strapi-preview-overlay';\n const INTERNAL_EVENTS = {\n DUMMY_EVENT: 'dummyEvent',\n } as const;\n\n /**\n * Calling the function in no-run mode lets us retrieve the constants from other files and keep\n * a single source of truth for them. It's the only way to do this because this script can't\n * refer to any variables outside of its own scope, because it's stringified before it's run.\n */\n if (!shouldRun) {\n return { INTERNAL_EVENTS };\n }\n\n /* -----------------------------------------------------------------------------------------------\n * Functionality pieces\n * ---------------------------------------------------------------------------------------------*/\n\n const createOverlaySystem = () => {\n // Clean up before creating a new overlay so we can safely call previewScript multiple times\n window.__strapi_previewCleanup?.();\n document.getElementById(OVERLAY_ID)?.remove();\n\n const overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 9999;\n `;\n\n window.document.body.appendChild(overlay);\n return overlay;\n };\n\n type EventListenersList = Array<{\n element: HTMLElement;\n type: keyof HTMLElementEventMap;\n handler: EventListener;\n }>;\n\n const createHighlightManager = (overlay: HTMLElement) => {\n const elements = window.document.querySelectorAll(`[${SOURCE_ATTRIBUTE}]`);\n const highlights: HTMLElement[] = [];\n const eventListeners: EventListenersList = [];\n\n const drawHighlight = (target: Element, highlight: HTMLElement) => {\n if (!highlight) return;\n\n const rect = target.getBoundingClientRect();\n highlight.style.width = `${rect.width + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.height = `${rect.height + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.transform = `translate(${rect.left - HIGHLIGHT_PADDING}px, ${rect.top - HIGHLIGHT_PADDING}px)`;\n };\n\n const updateAllHighlights = () => {\n highlights.forEach((highlight, index) => {\n const element = elements[index];\n if (element && highlight) {\n drawHighlight(element, highlight);\n }\n });\n };\n\n elements.forEach((element) => {\n if (element instanceof HTMLElement) {\n const highlight = document.createElement('div');\n highlight.style.cssText = `\n position: absolute;\n outline: 2px solid transparent;\n pointer-events: none;\n border-radius: 2px;\n background-color: transparent;\n will-change: transform;\n transition: outline-color 0.1s ease-in-out;\n `;\n\n // Move hover detection to the underlying element\n const mouseEnterHandler = () => {\n highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;\n };\n const mouseLeaveHandler = () => {\n highlight.style.outlineColor = 'transparent';\n };\n const doubleClickHandler = () => {\n // TODO: handle for real\n // eslint-disable-next-line no-console\n console.log('Double click on highlight', element);\n };\n const mouseDownHandler = (event: MouseEvent) => {\n // Prevent default multi click to select behavior\n if (event.detail >= 2) {\n event.preventDefault();\n }\n };\n\n element.addEventListener('mouseenter', mouseEnterHandler);\n element.addEventListener('mouseleave', mouseLeaveHandler);\n element.addEventListener('dblclick', doubleClickHandler);\n element.addEventListener('mousedown', mouseDownHandler);\n\n // Store event listeners for cleanup\n eventListeners.push(\n { element, type: 'mouseenter', handler: mouseEnterHandler },\n { element, type: 'mouseleave', handler: mouseLeaveHandler },\n { element, type: 'dblclick', handler: doubleClickHandler },\n { element, type: 'mousedown', handler: mouseDownHandler as EventListener }\n );\n\n highlights.push(highlight);\n overlay.appendChild(highlight);\n\n drawHighlight(element, highlight);\n }\n });\n\n return {\n elements,\n updateAllHighlights,\n eventListeners,\n };\n };\n\n type HighlightManager = ReturnType<typeof createHighlightManager>;\n\n const setupObservers = (highlightManager: HighlightManager) => {\n const resizeObserver = new ResizeObserver(() => {\n highlightManager.updateAllHighlights();\n });\n\n highlightManager.elements.forEach((element: Element) => {\n resizeObserver.observe(element);\n });\n\n resizeObserver.observe(document.documentElement);\n\n const updateOnScroll = () => {\n highlightManager.updateAllHighlights();\n };\n\n const scrollableElements = new Set<Element | Window>();\n scrollableElements.add(window);\n\n // Find all scrollable ancestors for all tracked elements\n highlightManager.elements.forEach((element) => {\n let parent = element.parentElement;\n while (parent) {\n const computedStyle = window.getComputedStyle(parent);\n const overflow = computedStyle.overflow + computedStyle.overflowX + computedStyle.overflowY;\n\n if (overflow.includes('scroll') || overflow.includes('auto')) {\n scrollableElements.add(parent);\n }\n\n parent = parent.parentElement;\n }\n });\n\n // Add scroll listeners to all scrollable elements\n scrollableElements.forEach((element) => {\n if (element === window) {\n window.addEventListener('scroll', updateOnScroll);\n window.addEventListener('resize', updateOnScroll);\n } else {\n (element as Element).addEventListener('scroll', updateOnScroll);\n }\n });\n\n return {\n resizeObserver,\n updateOnScroll,\n scrollableElements,\n };\n };\n\n const setupEventHandlers = (highlightManager: HighlightManager) => {\n // TODO: The listeners for postMessage events will go here\n return highlightManager.eventListeners;\n };\n\n const createCleanupSystem = (\n overlay: HTMLElement,\n observers: ReturnType<typeof setupObservers>,\n eventHandlers: EventListenersList\n ) => {\n window.__strapi_previewCleanup = () => {\n observers.resizeObserver.disconnect();\n\n // Remove all scroll listeners\n observers.scrollableElements.forEach((element) => {\n if (element === window) {\n window.removeEventListener('scroll', observers.updateOnScroll);\n window.removeEventListener('resize', observers.updateOnScroll);\n } else {\n (element as Element).removeEventListener('scroll', observers.updateOnScroll);\n }\n });\n\n // Remove highlight event listeners\n eventHandlers.forEach(({ element, type, handler }) => {\n element.removeEventListener(type, handler);\n });\n\n overlay.remove();\n };\n };\n\n /* -----------------------------------------------------------------------------------------------\n * Orchestration\n * ---------------------------------------------------------------------------------------------*/\n\n const overlay = createOverlaySystem();\n const highlightManager = createHighlightManager(overlay);\n const observers = setupObservers(highlightManager);\n const eventHandlers = setupEventHandlers(highlightManager);\n createCleanupSystem(overlay, observers, eventHandlers);\n};\n\nexport { previewScript };\n"],"names":["previewScript","shouldRun","HIGHLIGHT_PADDING","HIGHLIGHT_HOVER_COLOR","window","STRAPI_HIGHLIGHT_HOVER_COLOR","SOURCE_ATTRIBUTE","OVERLAY_ID","INTERNAL_EVENTS","DUMMY_EVENT","createOverlaySystem","__strapi_previewCleanup","document","getElementById","remove","overlay","createElement","id","style","cssText","body","appendChild","createHighlightManager","elements","querySelectorAll","highlights","eventListeners","drawHighlight","target","highlight","rect","getBoundingClientRect","width","height","transform","left","top","updateAllHighlights","forEach","index","element","HTMLElement","mouseEnterHandler","outlineColor","mouseLeaveHandler","doubleClickHandler","console","log","mouseDownHandler","event","detail","preventDefault","addEventListener","push","type","handler","setupObservers","highlightManager","resizeObserver","ResizeObserver","observe","documentElement","updateOnScroll","scrollableElements","Set","add","parent","parentElement","computedStyle","getComputedStyle","overflow","overflowX","overflowY","includes","setupEventHandlers","createCleanupSystem","observers","eventHandlers","disconnect","removeEventListener"],"mappings":"AAAA;AAQA;;;;;AAKC,IACKA,MAAAA,aAAAA,GAAgB,CAACC,SAAAA,GAAY,IAAI,GAAA;AACrC;;qGAGA,MAAMC,iBAAoB,GAAA,CAAA,CAAA;AAC1B,IAAA,MAAMC,qBAAwBC,GAAAA,MAAAA,CAAOC,4BAA4B,IAAI;AACrE,IAAA,MAAMC,gBAAmB,GAAA,oBAAA;AACzB,IAAA,MAAMC,UAAa,GAAA,wBAAA;AACnB,IAAA,MAAMC,eAAkB,GAAA;QACtBC,WAAa,EAAA;AACf,KAAA;AAEA;;;;MAKA,IAAI,CAACR,SAAW,EAAA;QACd,OAAO;AAAEO,YAAAA;AAAgB,SAAA;AAC3B;AAEA;;AAEgG,qGAEhG,MAAME,mBAAsB,GAAA,IAAA;;AAE1BN,QAAAA,MAAAA,CAAOO,uBAAuB,IAAA;QAC9BC,QAASC,CAAAA,cAAc,CAACN,UAAaO,CAAAA,EAAAA,MAAAA,EAAAA;QAErC,MAAMC,OAAAA,GAAUH,QAASI,CAAAA,aAAa,CAAC,KAAA,CAAA;AACvCD,QAAAA,OAAAA,CAAQE,EAAE,GAAGV,UAAAA;AACbQ,QAAAA,OAAAA,CAAQG,KAAK,CAACC,OAAO,GAAG;;;;;;;;IAQxB,CAAC;AAEDf,QAAAA,MAAAA,CAAOQ,QAAQ,CAACQ,IAAI,CAACC,WAAW,CAACN,OAAAA,CAAAA;QACjC,OAAOA,OAAAA;AACT,KAAA;AAQA,IAAA,MAAMO,yBAAyB,CAACP,OAAAA,GAAAA;QAC9B,MAAMQ,QAAAA,GAAWnB,MAAOQ,CAAAA,QAAQ,CAACY,gBAAgB,CAAC,CAAC,CAAC,EAAElB,gBAAiB,CAAA,CAAC,CAAC,CAAA;AACzE,QAAA,MAAMmB,aAA4B,EAAE;AACpC,QAAA,MAAMC,iBAAqC,EAAE;QAE7C,MAAMC,aAAAA,GAAgB,CAACC,MAAiBC,EAAAA,SAAAA,GAAAA;AACtC,YAAA,IAAI,CAACA,SAAW,EAAA;YAEhB,MAAMC,IAAAA,GAAOF,OAAOG,qBAAqB,EAAA;AACzCF,YAAAA,SAAAA,CAAUX,KAAK,CAACc,KAAK,GAAG,CAAC,EAAEF,IAAKE,CAAAA,KAAK,GAAG9B,iBAAAA,GAAoB,CAAE,CAAA,EAAE,CAAC;AACjE2B,YAAAA,SAAAA,CAAUX,KAAK,CAACe,MAAM,GAAG,CAAC,EAAEH,IAAKG,CAAAA,MAAM,GAAG/B,iBAAAA,GAAoB,CAAE,CAAA,EAAE,CAAC;AACnE2B,YAAAA,SAAAA,CAAUX,KAAK,CAACgB,SAAS,GAAG,CAAC,UAAU,EAAEJ,IAAKK,CAAAA,IAAI,GAAGjC,iBAAAA,CAAkB,IAAI,EAAE4B,IAAAA,CAAKM,GAAG,GAAGlC,iBAAAA,CAAkB,GAAG,CAAC;AAChH,SAAA;AAEA,QAAA,MAAMmC,mBAAsB,GAAA,IAAA;YAC1BZ,UAAWa,CAAAA,OAAO,CAAC,CAACT,SAAWU,EAAAA,KAAAA,GAAAA;gBAC7B,MAAMC,OAAAA,GAAUjB,QAAQ,CAACgB,KAAM,CAAA;AAC/B,gBAAA,IAAIC,WAAWX,SAAW,EAAA;AACxBF,oBAAAA,aAAAA,CAAca,OAASX,EAAAA,SAAAA,CAAAA;AACzB;AACF,aAAA,CAAA;AACF,SAAA;QAEAN,QAASe,CAAAA,OAAO,CAAC,CAACE,OAAAA,GAAAA;AAChB,YAAA,IAAIA,mBAAmBC,WAAa,EAAA;gBAClC,MAAMZ,SAAAA,GAAYjB,QAASI,CAAAA,aAAa,CAAC,KAAA,CAAA;AACzCa,gBAAAA,SAAAA,CAAUX,KAAK,CAACC,OAAO,GAAG;;;;;;;;QAQ1B,CAAC;;AAGD,gBAAA,MAAMuB,iBAAoB,GAAA,IAAA;oBACxBb,SAAUX,CAAAA,KAAK,CAACyB,YAAY,GAAGxC,qBAAAA;AACjC,iBAAA;AACA,gBAAA,MAAMyC,iBAAoB,GAAA,IAAA;oBACxBf,SAAUX,CAAAA,KAAK,CAACyB,YAAY,GAAG,aAAA;AACjC,iBAAA;AACA,gBAAA,MAAME,kBAAqB,GAAA,IAAA;;;oBAGzBC,OAAQC,CAAAA,GAAG,CAAC,2BAA6BP,EAAAA,OAAAA,CAAAA;AAC3C,iBAAA;AACA,gBAAA,MAAMQ,mBAAmB,CAACC,KAAAA,GAAAA;;oBAExB,IAAIA,KAAAA,CAAMC,MAAM,IAAI,CAAG,EAAA;AACrBD,wBAAAA,KAAAA,CAAME,cAAc,EAAA;AACtB;AACF,iBAAA;gBAEAX,OAAQY,CAAAA,gBAAgB,CAAC,YAAcV,EAAAA,iBAAAA,CAAAA;gBACvCF,OAAQY,CAAAA,gBAAgB,CAAC,YAAcR,EAAAA,iBAAAA,CAAAA;gBACvCJ,OAAQY,CAAAA,gBAAgB,CAAC,UAAYP,EAAAA,kBAAAA,CAAAA;gBACrCL,OAAQY,CAAAA,gBAAgB,CAAC,WAAaJ,EAAAA,gBAAAA,CAAAA;;AAGtCtB,gBAAAA,cAAAA,CAAe2B,IAAI,CACjB;AAAEb,oBAAAA,OAAAA;oBAASc,IAAM,EAAA,YAAA;oBAAcC,OAASb,EAAAA;iBACxC,EAAA;AAAEF,oBAAAA,OAAAA;oBAASc,IAAM,EAAA,YAAA;oBAAcC,OAASX,EAAAA;iBACxC,EAAA;AAAEJ,oBAAAA,OAAAA;oBAASc,IAAM,EAAA,UAAA;oBAAYC,OAASV,EAAAA;iBACtC,EAAA;AAAEL,oBAAAA,OAAAA;oBAASc,IAAM,EAAA,WAAA;oBAAaC,OAASP,EAAAA;AAAkC,iBAAA,CAAA;AAG3EvB,gBAAAA,UAAAA,CAAW4B,IAAI,CAACxB,SAAAA,CAAAA;AAChBd,gBAAAA,OAAAA,CAAQM,WAAW,CAACQ,SAAAA,CAAAA;AAEpBF,gBAAAA,aAAAA,CAAca,OAASX,EAAAA,SAAAA,CAAAA;AACzB;AACF,SAAA,CAAA;QAEA,OAAO;AACLN,YAAAA,QAAAA;AACAc,YAAAA,mBAAAA;AACAX,YAAAA;AACF,SAAA;AACF,KAAA;AAIA,IAAA,MAAM8B,iBAAiB,CAACC,gBAAAA,GAAAA;QACtB,MAAMC,cAAAA,GAAiB,IAAIC,cAAe,CAAA,IAAA;AACxCF,YAAAA,gBAAAA,CAAiBpB,mBAAmB,EAAA;AACtC,SAAA,CAAA;AAEAoB,QAAAA,gBAAAA,CAAiBlC,QAAQ,CAACe,OAAO,CAAC,CAACE,OAAAA,GAAAA;AACjCkB,YAAAA,cAAAA,CAAeE,OAAO,CAACpB,OAAAA,CAAAA;AACzB,SAAA,CAAA;QAEAkB,cAAeE,CAAAA,OAAO,CAAChD,QAAAA,CAASiD,eAAe,CAAA;AAE/C,QAAA,MAAMC,cAAiB,GAAA,IAAA;AACrBL,YAAAA,gBAAAA,CAAiBpB,mBAAmB,EAAA;AACtC,SAAA;AAEA,QAAA,MAAM0B,qBAAqB,IAAIC,GAAAA,EAAAA;AAC/BD,QAAAA,kBAAAA,CAAmBE,GAAG,CAAC7D,MAAAA,CAAAA;;AAGvBqD,QAAAA,gBAAAA,CAAiBlC,QAAQ,CAACe,OAAO,CAAC,CAACE,OAAAA,GAAAA;YACjC,IAAI0B,MAAAA,GAAS1B,QAAQ2B,aAAa;AAClC,YAAA,MAAOD,MAAQ,CAAA;gBACb,MAAME,aAAAA,GAAgBhE,MAAOiE,CAAAA,gBAAgB,CAACH,MAAAA,CAAAA;gBAC9C,MAAMI,QAAAA,GAAWF,cAAcE,QAAQ,GAAGF,cAAcG,SAAS,GAAGH,cAAcI,SAAS;AAE3F,gBAAA,IAAIF,SAASG,QAAQ,CAAC,aAAaH,QAASG,CAAAA,QAAQ,CAAC,MAAS,CAAA,EAAA;AAC5DV,oBAAAA,kBAAAA,CAAmBE,GAAG,CAACC,MAAAA,CAAAA;AACzB;AAEAA,gBAAAA,MAAAA,GAASA,OAAOC,aAAa;AAC/B;AACF,SAAA,CAAA;;QAGAJ,kBAAmBzB,CAAAA,OAAO,CAAC,CAACE,OAAAA,GAAAA;AAC1B,YAAA,IAAIA,YAAYpC,MAAQ,EAAA;gBACtBA,MAAOgD,CAAAA,gBAAgB,CAAC,QAAUU,EAAAA,cAAAA,CAAAA;gBAClC1D,MAAOgD,CAAAA,gBAAgB,CAAC,QAAUU,EAAAA,cAAAA,CAAAA;aAC7B,MAAA;gBACJtB,OAAoBY,CAAAA,gBAAgB,CAAC,QAAUU,EAAAA,cAAAA,CAAAA;AAClD;AACF,SAAA,CAAA;QAEA,OAAO;AACLJ,YAAAA,cAAAA;AACAI,YAAAA,cAAAA;AACAC,YAAAA;AACF,SAAA;AACF,KAAA;AAEA,IAAA,MAAMW,qBAAqB,CAACjB,gBAAAA,GAAAA;;AAE1B,QAAA,OAAOA,iBAAiB/B,cAAc;AACxC,KAAA;IAEA,MAAMiD,mBAAAA,GAAsB,CAC1B5D,OAAAA,EACA6D,SACAC,EAAAA,aAAAA,GAAAA;AAEAzE,QAAAA,MAAAA,CAAOO,uBAAuB,GAAG,IAAA;YAC/BiE,SAAUlB,CAAAA,cAAc,CAACoB,UAAU,EAAA;;AAGnCF,YAAAA,SAAAA,CAAUb,kBAAkB,CAACzB,OAAO,CAAC,CAACE,OAAAA,GAAAA;AACpC,gBAAA,IAAIA,YAAYpC,MAAQ,EAAA;AACtBA,oBAAAA,MAAAA,CAAO2E,mBAAmB,CAAC,QAAUH,EAAAA,SAAAA,CAAUd,cAAc,CAAA;AAC7D1D,oBAAAA,MAAAA,CAAO2E,mBAAmB,CAAC,QAAUH,EAAAA,SAAAA,CAAUd,cAAc,CAAA;iBACxD,MAAA;AACJtB,oBAAAA,OAAAA,CAAoBuC,mBAAmB,CAAC,QAAUH,EAAAA,SAAAA,CAAUd,cAAc,CAAA;AAC7E;AACF,aAAA,CAAA;;YAGAe,aAAcvC,CAAAA,OAAO,CAAC,CAAC,EAAEE,OAAO,EAAEc,IAAI,EAAEC,OAAO,EAAE,GAAA;gBAC/Cf,OAAQuC,CAAAA,mBAAmB,CAACzB,IAAMC,EAAAA,OAAAA,CAAAA;AACpC,aAAA,CAAA;AAEAxC,YAAAA,OAAAA,CAAQD,MAAM,EAAA;AAChB,SAAA;AACF,KAAA;AAEA;;AAEgG,qGAEhG,MAAMC,OAAUL,GAAAA,mBAAAA,EAAAA;AAChB,IAAA,MAAM+C,mBAAmBnC,sBAAuBP,CAAAA,OAAAA,CAAAA;AAChD,IAAA,MAAM6D,YAAYpB,cAAeC,CAAAA,gBAAAA,CAAAA;AACjC,IAAA,MAAMoB,gBAAgBH,kBAAmBjB,CAAAA,gBAAAA,CAAAA;AACzCkB,IAAAA,mBAAAA,CAAoB5D,SAAS6D,SAAWC,EAAAA,aAAAA,CAAAA;AAC1C;;;;"}
1
+ {"version":3,"file":"previewScript.mjs","sources":["../../../../admin/src/preview/utils/previewScript.ts"],"sourcesContent":["// NOTE: This override is for the properties on _user's site_, it's not about Strapi Admin.\ndeclare global {\n interface Window {\n __strapi_previewCleanup?: () => void;\n STRAPI_HIGHLIGHT_HOVER_COLOR?: string;\n STRAPI_HIGHLIGHT_ACTIVE_COLOR?: string;\n }\n}\n\n/**\n * previewScript will be injected into the preview iframe after being stringified.\n * Therefore it CANNOT use any imports, or refer to any variables outside of its own scope.\n * It's why many functions are defined within previewScript, it's the only way to avoid going full spaghetti.\n * To get a better overview of everything previewScript does, go to the orchestration part at its end.\n */\nconst previewScript = (shouldRun = true) => {\n /* -----------------------------------------------------------------------------------------------\n * Params\n * ---------------------------------------------------------------------------------------------*/\n const HIGHLIGHT_PADDING = 2; // in pixels\n const HIGHLIGHT_HOVER_COLOR = window.STRAPI_HIGHLIGHT_HOVER_COLOR ?? '#4945ff'; // dark primary500\n const HIGHLIGHT_ACTIVE_COLOR = window.STRAPI_HIGHLIGHT_ACTIVE_COLOR ?? '#7b79ff'; // dark primary600\n\n const SOURCE_ATTRIBUTE = 'data-strapi-source';\n const OVERLAY_ID = 'strapi-preview-overlay';\n const INTERNAL_EVENTS = {\n STRAPI_FIELD_FOCUS: 'strapiFieldFocus',\n STRAPI_FIELD_BLUR: 'strapiFieldBlur',\n STRAPI_FIELD_CHANGE: 'strapiFieldChange',\n STRAPI_FIELD_FOCUS_INTENT: 'strapiFieldFocusIntent',\n } as const;\n\n /**\n * Calling the function in no-run mode lets us retrieve the constants from other files and keep\n * a single source of truth for them. It's the only way to do this because this script can't\n * refer to any variables outside of its own scope, because it's stringified before it's run.\n */\n if (!shouldRun) {\n return { INTERNAL_EVENTS };\n }\n\n /* -----------------------------------------------------------------------------------------------\n * Utils\n * ---------------------------------------------------------------------------------------------*/\n\n const sendMessage = (\n type: (typeof INTERNAL_EVENTS)[keyof typeof INTERNAL_EVENTS],\n payload: unknown\n ) => {\n window.parent.postMessage({ type, payload }, '*');\n };\n\n /* -----------------------------------------------------------------------------------------------\n * Functionality pieces\n * ---------------------------------------------------------------------------------------------*/\n\n const createOverlaySystem = () => {\n // Clean up before creating a new overlay so we can safely call previewScript multiple times\n window.__strapi_previewCleanup?.();\n document.getElementById(OVERLAY_ID)?.remove();\n\n const overlay = document.createElement('div');\n overlay.id = OVERLAY_ID;\n overlay.style.cssText = `\n position: fixed;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n pointer-events: none;\n z-index: 9999;\n `;\n\n window.document.body.appendChild(overlay);\n return overlay;\n };\n\n type EventListenersList = Array<{\n element: HTMLElement | Window;\n type: keyof HTMLElementEventMap | 'message';\n handler: EventListener;\n }>;\n\n const createHighlightManager = (overlay: HTMLElement) => {\n const elements = window.document.querySelectorAll(`[${SOURCE_ATTRIBUTE}]`);\n const eventListeners: EventListenersList = [];\n const highlights: HTMLElement[] = [];\n const focusedHighlights: HTMLElement[] = [];\n let focusedField: string | null = null;\n\n const drawHighlight = (target: Element, highlight: HTMLElement) => {\n if (!highlight) return;\n\n const rect = target.getBoundingClientRect();\n highlight.style.width = `${rect.width + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.height = `${rect.height + HIGHLIGHT_PADDING * 2}px`;\n highlight.style.transform = `translate(${rect.left - HIGHLIGHT_PADDING}px, ${rect.top - HIGHLIGHT_PADDING}px)`;\n };\n\n const updateAllHighlights = () => {\n highlights.forEach((highlight, index) => {\n const element = elements[index];\n if (element && highlight) {\n drawHighlight(element, highlight);\n }\n });\n };\n\n elements.forEach((element) => {\n if (element instanceof HTMLElement) {\n const highlight = document.createElement('div');\n highlight.style.cssText = `\n position: absolute;\n outline: 2px solid transparent;\n pointer-events: none;\n border-radius: 2px;\n background-color: transparent;\n will-change: transform;\n transition: outline-color 0.1s ease-in-out;\n `;\n\n // Move hover detection to the underlying element\n const mouseEnterHandler = () => {\n if (!highlightManager.focusedHighlights.includes(highlight)) {\n highlight.style.outlineColor = HIGHLIGHT_HOVER_COLOR;\n }\n };\n const mouseLeaveHandler = () => {\n if (!highlightManager.focusedHighlights.includes(highlight)) {\n highlight.style.outlineColor = 'transparent';\n }\n };\n const doubleClickHandler = () => {\n const sourceAttribute = element.getAttribute(SOURCE_ATTRIBUTE);\n if (sourceAttribute) {\n const rect = element.getBoundingClientRect();\n sendMessage(INTERNAL_EVENTS.STRAPI_FIELD_FOCUS_INTENT, {\n path: sourceAttribute,\n position: {\n top: rect.top,\n left: rect.left,\n right: rect.right,\n bottom: rect.bottom,\n width: rect.width,\n height: rect.height,\n },\n });\n }\n };\n const mouseDownHandler = (event: MouseEvent) => {\n // Prevent default multi click to select behavior\n if (event.detail >= 2) {\n event.preventDefault();\n }\n };\n\n element.addEventListener('mouseenter', mouseEnterHandler);\n element.addEventListener('mouseleave', mouseLeaveHandler);\n element.addEventListener('dblclick', doubleClickHandler);\n element.addEventListener('mousedown', mouseDownHandler);\n\n // Store event listeners for cleanup\n eventListeners.push(\n { element, type: 'mouseenter', handler: mouseEnterHandler },\n { element, type: 'mouseleave', handler: mouseLeaveHandler },\n { element, type: 'dblclick', handler: doubleClickHandler },\n { element, type: 'mousedown', handler: mouseDownHandler as EventListener }\n );\n\n highlights.push(highlight);\n overlay.appendChild(highlight);\n\n drawHighlight(element, highlight);\n }\n });\n\n return {\n elements,\n updateAllHighlights,\n eventListeners,\n highlights,\n focusedHighlights,\n setFocusedField: (field: string | null) => {\n focusedField = field;\n },\n getFocusedField: () => focusedField,\n };\n };\n\n type HighlightManager = ReturnType<typeof createHighlightManager>;\n\n const setupObservers = (highlightManager: HighlightManager) => {\n const resizeObserver = new ResizeObserver(() => {\n highlightManager.updateAllHighlights();\n });\n\n highlightManager.elements.forEach((element: Element) => {\n resizeObserver.observe(element);\n });\n\n resizeObserver.observe(document.documentElement);\n\n const updateOnScroll = () => {\n highlightManager.updateAllHighlights();\n };\n\n const scrollableElements = new Set<Element | Window>();\n scrollableElements.add(window);\n\n // Find all scrollable ancestors for all tracked elements\n highlightManager.elements.forEach((element) => {\n let parent = element.parentElement;\n while (parent) {\n const computedStyle = window.getComputedStyle(parent);\n const overflow = computedStyle.overflow + computedStyle.overflowX + computedStyle.overflowY;\n\n if (overflow.includes('scroll') || overflow.includes('auto')) {\n scrollableElements.add(parent);\n }\n\n parent = parent.parentElement;\n }\n });\n\n // Add scroll listeners to all scrollable elements\n scrollableElements.forEach((element) => {\n if (element === window) {\n window.addEventListener('scroll', updateOnScroll);\n window.addEventListener('resize', updateOnScroll);\n } else {\n element.addEventListener('scroll', updateOnScroll);\n }\n });\n\n return {\n resizeObserver,\n updateOnScroll,\n scrollableElements,\n };\n };\n\n const setupEventHandlers = (highlightManager: HighlightManager) => {\n const handleMessage = (event: MessageEvent) => {\n if (!event.data?.type) return;\n\n // The user typed in an input, reflect the change in the preview\n if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_CHANGE) {\n const { field, value } = event.data.payload;\n if (!field) return;\n\n const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}=\"${field}\"]`);\n matchingElements.forEach((element) => {\n if (element instanceof HTMLElement) {\n element.textContent = value || '';\n }\n });\n return;\n }\n\n // The user focused a new input, update the highlights in the preview\n if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_FOCUS) {\n const { field } = event.data.payload;\n if (!field) return;\n\n // Clear existing focused highlights\n highlightManager.focusedHighlights.forEach((highlight: HTMLElement) => {\n highlight.style.outlineColor = 'transparent';\n });\n highlightManager.focusedHighlights.length = 0;\n\n // Set new focused field and highlight matching elements\n highlightManager.setFocusedField(field);\n const matchingElements = document.querySelectorAll(`[${SOURCE_ATTRIBUTE}=\"${field}\"]`);\n matchingElements.forEach((element) => {\n const highlight =\n highlightManager.highlights[Array.from(highlightManager.elements).indexOf(element)];\n if (highlight) {\n highlight.style.outlineColor = HIGHLIGHT_ACTIVE_COLOR;\n highlight.style.outlineWidth = '3px';\n highlightManager.focusedHighlights.push(highlight);\n }\n });\n return;\n }\n\n // The user is no longer focusing an input, remove the highlights\n if (event.data.type === INTERNAL_EVENTS.STRAPI_FIELD_BLUR) {\n const { field } = event.data.payload;\n if (field !== highlightManager.getFocusedField()) return;\n\n highlightManager.focusedHighlights.forEach((highlight: HTMLElement) => {\n highlight.style.outlineColor = 'transparent';\n highlight.style.outlineWidth = '2px';\n });\n highlightManager.focusedHighlights.length = 0;\n highlightManager.setFocusedField(null);\n }\n };\n\n window.addEventListener('message', handleMessage);\n\n // Add the message handler to the cleanup list\n const messageEventListener = {\n element: window,\n type: 'message' as keyof HTMLElementEventMap,\n handler: handleMessage as EventListener,\n };\n\n return [...highlightManager.eventListeners, messageEventListener];\n };\n\n const createCleanupSystem = (\n overlay: HTMLElement,\n observers: ReturnType<typeof setupObservers>,\n eventHandlers: EventListenersList\n ) => {\n window.__strapi_previewCleanup = () => {\n observers.resizeObserver.disconnect();\n\n // Remove all scroll listeners\n observers.scrollableElements.forEach((element) => {\n if (element === window) {\n window.removeEventListener('scroll', observers.updateOnScroll);\n window.removeEventListener('resize', observers.updateOnScroll);\n } else {\n (element as Element).removeEventListener('scroll', observers.updateOnScroll);\n }\n });\n\n // Remove highlight event listeners\n eventHandlers.forEach(({ element, type, handler }) => {\n element.removeEventListener(type, handler);\n });\n\n overlay.remove();\n };\n };\n\n /* -----------------------------------------------------------------------------------------------\n * Orchestration\n * ---------------------------------------------------------------------------------------------*/\n\n const overlay = createOverlaySystem();\n const highlightManager = createHighlightManager(overlay);\n const observers = setupObservers(highlightManager);\n const eventHandlers = setupEventHandlers(highlightManager);\n createCleanupSystem(overlay, observers, eventHandlers);\n};\n\nexport { previewScript };\n"],"names":["previewScript","shouldRun","HIGHLIGHT_PADDING","HIGHLIGHT_HOVER_COLOR","window","STRAPI_HIGHLIGHT_HOVER_COLOR","HIGHLIGHT_ACTIVE_COLOR","STRAPI_HIGHLIGHT_ACTIVE_COLOR","SOURCE_ATTRIBUTE","OVERLAY_ID","INTERNAL_EVENTS","STRAPI_FIELD_FOCUS","STRAPI_FIELD_BLUR","STRAPI_FIELD_CHANGE","STRAPI_FIELD_FOCUS_INTENT","sendMessage","type","payload","parent","postMessage","createOverlaySystem","__strapi_previewCleanup","document","getElementById","remove","overlay","createElement","id","style","cssText","body","appendChild","createHighlightManager","elements","querySelectorAll","eventListeners","highlights","focusedHighlights","focusedField","drawHighlight","target","highlight","rect","getBoundingClientRect","width","height","transform","left","top","updateAllHighlights","forEach","index","element","HTMLElement","mouseEnterHandler","highlightManager","includes","outlineColor","mouseLeaveHandler","doubleClickHandler","sourceAttribute","getAttribute","path","position","right","bottom","mouseDownHandler","event","detail","preventDefault","addEventListener","push","handler","setFocusedField","field","getFocusedField","setupObservers","resizeObserver","ResizeObserver","observe","documentElement","updateOnScroll","scrollableElements","Set","add","parentElement","computedStyle","getComputedStyle","overflow","overflowX","overflowY","setupEventHandlers","handleMessage","data","value","matchingElements","textContent","length","Array","from","indexOf","outlineWidth","messageEventListener","createCleanupSystem","observers","eventHandlers","disconnect","removeEventListener"],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Prevents users from leaving the page with unsaved form changes
3
+ */
4
+ declare const Blocker: () => import("react/jsx-runtime").JSX.Element;
5
+ export { Blocker };
@@ -7,6 +7,6 @@ type InputRendererProps = DistributiveOmit<EditFieldLayout, 'size'> & {
7
7
  document: ReturnType<UseDocument>;
8
8
  };
9
9
  declare const useFieldHint: (hint: React.ReactNode, attribute: Schema.Attribute.AnyAttribute) => string | number | boolean | import("react/jsx-runtime").JSX.Element | Iterable<React.ReactNode> | (string | import("react/jsx-runtime").JSX.Element | React.ReactElement<any, string | React.JSXElementConstructor<any>> | Iterable<React.ReactNode> | React.ReactPortal)[] | null | undefined;
10
- declare const MemoizedInputRenderer: React.MemoExoticComponent<({ visible, hint: providedHint, document, ...props }: InputRendererProps) => import("react/jsx-runtime").JSX.Element | null>;
10
+ declare const MemoizedInputRenderer: React.MemoExoticComponent<({ visible, hint: providedHint, document, ...inputProps }: InputRendererProps) => import("react/jsx-runtime").JSX.Element | null>;
11
11
  export type { InputRendererProps };
12
12
  export { MemoizedInputRenderer as InputRenderer, useFieldHint };
@@ -0,0 +1,6 @@
1
+ import { type UseDocument } from '../../hooks/useDocument';
2
+ declare const InputPopover: ({ documentResponse }: {
3
+ documentResponse: ReturnType<UseDocument>;
4
+ }) => import("react/jsx-runtime").JSX.Element | null;
5
+ declare function useHasInputPopoverParent(): boolean;
6
+ export { InputPopover, useHasInputPopoverParent };
@@ -0,0 +1,4 @@
1
+ import * as React from 'react';
2
+ type PreviewInputProps = Pick<Required<React.InputHTMLAttributes<HTMLInputElement>>, 'onFocus' | 'onBlur'>;
3
+ export declare function usePreviewInputManager(name: string): PreviewInputProps;
4
+ export {};
@@ -1,5 +1,10 @@
1
+ import * as React from 'react';
1
2
  import { type UseDocument } from '../../hooks/useDocument';
2
3
  import { type EditLayout } from '../../hooks/useDocumentLayout';
4
+ interface PopoverField {
5
+ path: string;
6
+ position: DOMRect;
7
+ }
3
8
  interface PreviewContextValue {
4
9
  url: string;
5
10
  title: string;
@@ -8,6 +13,9 @@ interface PreviewContextValue {
8
13
  schema: NonNullable<ReturnType<UseDocument>['schema']>;
9
14
  layout: EditLayout;
10
15
  onPreview: () => void;
16
+ iframeRef: React.RefObject<HTMLIFrameElement>;
17
+ popoverField: PopoverField | null;
18
+ setPopoverField: (value: PopoverField | null) => void;
11
19
  }
12
20
  declare const usePreviewContext: <Selected, ShouldThrow extends boolean = true>(consumerName: string, selector: (value: PreviewContextValue) => Selected, shouldThrowOnMissingContext?: ShouldThrow | undefined) => ShouldThrow extends true ? Selected : Selected | undefined;
13
21
  declare const ProtectedPreviewPage: () => import("react/jsx-runtime").JSX.Element;
@@ -4,7 +4,10 @@
4
4
  * do what we want with them.
5
5
  */
6
6
  export declare const INTERNAL_EVENTS: {
7
- readonly DUMMY_EVENT: "dummyEvent";
7
+ readonly STRAPI_FIELD_FOCUS: "strapiFieldFocus";
8
+ readonly STRAPI_FIELD_BLUR: "strapiFieldBlur";
9
+ readonly STRAPI_FIELD_CHANGE: "strapiFieldChange";
10
+ readonly STRAPI_FIELD_FOCUS_INTENT: "strapiFieldFocusIntent";
8
11
  };
9
12
  /**
10
13
  * These events are documented to users, and will be hardcoded in their frontends.
@@ -0,0 +1,11 @@
1
+ /// <reference types="react" />
2
+ import type { INTERNAL_EVENTS, PUBLIC_EVENTS } from './constants';
3
+ type MessageType = (typeof INTERNAL_EVENTS)[keyof typeof INTERNAL_EVENTS] | (typeof PUBLIC_EVENTS)[keyof typeof PUBLIC_EVENTS];
4
+ /**
5
+ * A function factory so we can generate a new sendMessage everytime we need one.
6
+ * We can't store and reuse a single sendMessage because it needs to have a stable identity
7
+ * as it used in a useEffect function. And we can't rely on useCallback because we need the
8
+ * up-to-date iframe ref, and this would make it stale (refs don't trigger callback reevaluations).
9
+ */
10
+ export declare function getSendMessage(iframe: React.RefObject<HTMLIFrameElement> | undefined): (type: MessageType, payload?: unknown) => void;
11
+ export {};
@@ -2,6 +2,7 @@ declare global {
2
2
  interface Window {
3
3
  __strapi_previewCleanup?: () => void;
4
4
  STRAPI_HIGHLIGHT_HOVER_COLOR?: string;
5
+ STRAPI_HIGHLIGHT_ACTIVE_COLOR?: string;
5
6
  }
6
7
  }
7
8
  /**
@@ -12,7 +13,10 @@ declare global {
12
13
  */
13
14
  declare const previewScript: (shouldRun?: boolean) => {
14
15
  INTERNAL_EVENTS: {
15
- readonly DUMMY_EVENT: "dummyEvent";
16
+ readonly STRAPI_FIELD_FOCUS: "strapiFieldFocus";
17
+ readonly STRAPI_FIELD_BLUR: "strapiFieldBlur";
18
+ readonly STRAPI_FIELD_CHANGE: "strapiFieldChange";
19
+ readonly STRAPI_FIELD_FOCUS_INTENT: "strapiFieldFocusIntent";
16
20
  };
17
21
  } | undefined;
18
22
  export { previewScript };
@@ -313,6 +313,7 @@ var en = {
313
313
  "validation.error.unreadable-required-field": "Your current permissions prevent access to certain required fields. Please request access from an administrator to proceed.",
314
314
  "bulk-publish.edit": "Edit",
315
315
  "widget.chart-entries.title": "Entries",
316
+ "widget.chart-entries.count.label": "{count, plural, =0 {Entries} one {Entry} other {Entries}}",
316
317
  "widget.chart-entries.tooltip": "{count} {label}",
317
318
  "widget.last-edited.title": "Last edited entries",
318
319
  "widget.last-edited.single-type": "Single-Type",