@strapi/content-manager 5.52.3 → 5.54.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/admin/components/ActionsDrawer.js +17 -6
  2. package/dist/admin/components/ActionsDrawer.js.map +1 -1
  3. package/dist/admin/components/ActionsDrawer.mjs +19 -8
  4. package/dist/admin/components/ActionsDrawer.mjs.map +1 -1
  5. package/dist/admin/history/components/VersionsList.js +37 -43
  6. package/dist/admin/history/components/VersionsList.js.map +1 -1
  7. package/dist/admin/history/components/VersionsList.mjs +37 -43
  8. package/dist/admin/history/components/VersionsList.mjs.map +1 -1
  9. package/dist/admin/pages/EditView/EditViewPage.js +15 -20
  10. package/dist/admin/pages/EditView/EditViewPage.js.map +1 -1
  11. package/dist/admin/pages/EditView/EditViewPage.mjs +15 -20
  12. package/dist/admin/pages/EditView/EditViewPage.mjs.map +1 -1
  13. package/dist/admin/pages/EditView/components/DocumentActions.js +2 -0
  14. package/dist/admin/pages/EditView/components/DocumentActions.js.map +1 -1
  15. package/dist/admin/pages/EditView/components/DocumentActions.mjs +2 -0
  16. package/dist/admin/pages/EditView/components/DocumentActions.mjs.map +1 -1
  17. package/dist/admin/pages/EditView/components/EditorToolbarObserver.js +74 -7
  18. package/dist/admin/pages/EditView/components/EditorToolbarObserver.js.map +1 -1
  19. package/dist/admin/pages/EditView/components/EditorToolbarObserver.mjs +74 -7
  20. package/dist/admin/pages/EditView/components/EditorToolbarObserver.mjs.map +1 -1
  21. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.js +25 -16
  22. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.js.map +1 -1
  23. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.mjs +25 -16
  24. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.mjs.map +1 -1
  25. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js +7 -2
  26. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.js.map +1 -1
  27. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs +7 -2
  28. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.mjs.map +1 -1
  29. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js +59 -2
  30. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.js.map +1 -1
  31. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs +60 -3
  32. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.mjs.map +1 -1
  33. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.js +4 -1
  34. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.js.map +1 -1
  35. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.mjs +4 -1
  36. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.mjs.map +1 -1
  37. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js +4 -1
  38. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.js.map +1 -1
  39. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs +4 -1
  40. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/BlocksToolbar.mjs.map +1 -1
  41. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js +2 -1
  42. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.js.map +1 -1
  43. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs +2 -1
  44. package/dist/admin/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.mjs.map +1 -1
  45. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.js +25 -2
  46. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.js.map +1 -1
  47. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.mjs +5 -2
  48. package/dist/admin/pages/EditView/components/FormInputs/Wysiwyg/WysiwygNav.mjs.map +1 -1
  49. package/dist/admin/pages/EditView/components/InputRenderer.js +5 -1
  50. package/dist/admin/pages/EditView/components/InputRenderer.js.map +1 -1
  51. package/dist/admin/pages/EditView/components/InputRenderer.mjs +6 -2
  52. package/dist/admin/pages/EditView/components/InputRenderer.mjs.map +1 -1
  53. package/dist/admin/pages/ListView/ListViewPage.js +1 -0
  54. package/dist/admin/pages/ListView/ListViewPage.js.map +1 -1
  55. package/dist/admin/pages/ListView/ListViewPage.mjs +1 -0
  56. package/dist/admin/pages/ListView/ListViewPage.mjs.map +1 -1
  57. package/dist/admin/preview/components/InputPopover.js +64 -46
  58. package/dist/admin/preview/components/InputPopover.js.map +1 -1
  59. package/dist/admin/preview/components/InputPopover.mjs +66 -49
  60. package/dist/admin/preview/components/InputPopover.mjs.map +1 -1
  61. package/dist/admin/preview/hooks/usePreviewInputManager.js +23 -7
  62. package/dist/admin/preview/hooks/usePreviewInputManager.js.map +1 -1
  63. package/dist/admin/preview/hooks/usePreviewInputManager.mjs +25 -9
  64. package/dist/admin/preview/hooks/usePreviewInputManager.mjs.map +1 -1
  65. package/dist/admin/preview/pages/Preview.js +19 -0
  66. package/dist/admin/preview/pages/Preview.js.map +1 -1
  67. package/dist/admin/preview/pages/Preview.mjs +20 -1
  68. package/dist/admin/preview/pages/Preview.mjs.map +1 -1
  69. package/dist/admin/preview/utils/constants.js +9 -3
  70. package/dist/admin/preview/utils/constants.js.map +1 -1
  71. package/dist/admin/preview/utils/constants.mjs +9 -3
  72. package/dist/admin/preview/utils/constants.mjs.map +1 -1
  73. package/dist/admin/src/components/ActionsDrawer.d.ts +1 -0
  74. package/dist/admin/src/pages/EditView/components/EditorToolbarObserver.d.ts +2 -1
  75. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksContent.d.ts +5 -1
  76. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksEditor.d.ts +5 -0
  77. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +5 -0
  78. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/EditorLayout.d.ts +2 -1
  79. package/dist/admin/src/preview/components/InputPopover.d.ts +2 -1
  80. package/dist/admin/src/preview/pages/Preview.d.ts +1 -0
  81. package/dist/admin/src/preview/utils/constants.d.ts +8 -1
  82. package/dist/server/preview/controllers/previewScript.js +548 -22
  83. package/package.json +5 -5
@@ -37,12 +37,17 @@ const ObservedToolbarComponent = ({ index, lastVisibleIndex, setLastVisibleIndex
37
37
  */ if (isVisible) {
38
38
  setLastVisibleIndex((prev)=>Math.max(prev, index));
39
39
  }
40
- }, {
40
+ }, // Use a getter so root is read inside useElementOnScreen's useEffect (after refs are
41
+ // committed) rather than at render time (when containerRef.current is still null).
42
+ {
41
43
  threshold: 1,
42
- root: rootRef.current
44
+ get root () {
45
+ return rootRef.current;
46
+ }
43
47
  });
44
48
  return /*#__PURE__*/ jsxRuntime.jsx("div", {
45
49
  ref: containerRef,
50
+ "data-toolbar-item": "true",
46
51
  style: {
47
52
  /**
48
53
  * Use visibility so that the element occupies the space if requires even when there's not
@@ -83,12 +88,70 @@ const ObservedToolbarComponent = ({ index, lastVisibleIndex, setLastVisibleIndex
83
88
  display: none;
84
89
  }
85
90
  `;
86
- const EditorToolbarObserver = ({ observedComponents, menuTriggerVariant = 'ghost' })=>{
91
+ const EditorToolbarObserver = ({ observedComponents, menuTriggerVariant = 'ghost', containerRef })=>{
87
92
  const { formatMessage } = reactIntl.useIntl();
88
- const toolbarRef = React__namespace.useRef(null);
89
93
  const [lastVisibleIndex, setLastVisibleIndex] = React__namespace.useState(observedComponents.length - 1);
90
94
  const hasHiddenItems = lastVisibleIndex < observedComponents.length - 1;
91
95
  const menuIndex = lastVisibleIndex + 1;
96
+ /**
97
+ * Measure whether toolbar items overflow the container using clientWidth/offsetWidth.
98
+ * These layout-box dimensions are unaffected by CSS transforms (including the Radix
99
+ * popover positioning transform), so the result is always correct.
100
+ *
101
+ * We run this both synchronously on mount (useLayoutEffect) and on every container
102
+ * resize (ResizeObserver) so that label changes in BlocksDropdown, which narrow the
103
+ * toolbar container, are caught and the More menu appears as needed.
104
+ */ const measureOverflow = React__namespace.useCallback(()=>{
105
+ const container = containerRef.current;
106
+ if (!container) return;
107
+ // Items are in DOM order 0..N-1 regardless of where the trigger sits.
108
+ // data-toolbar-trigger is skipped by the [data-toolbar-item] selector.
109
+ const triggerEl = container.querySelector('[data-toolbar-trigger="true"]');
110
+ const itemEls = Array.from(container.querySelectorAll('[data-toolbar-item="true"]'));
111
+ if (!triggerEl || itemEls.length === 0) return;
112
+ const containerWidth = container.clientWidth;
113
+ const triggerWidth = triggerEl.offsetWidth;
114
+ const gap = parseFloat(getComputedStyle(container).columnGap) || 0;
115
+ const itemWidths = itemEls.map((el)=>el.offsetWidth);
116
+ const totalItemsWidth = itemWidths.reduce((sum, w)=>sum + w, 0);
117
+ // Check if all items fit without the trigger
118
+ if (totalItemsWidth + Math.max(0, itemEls.length - 1) * gap <= containerWidth) {
119
+ setLastVisibleIndex(itemEls.length - 1);
120
+ return;
121
+ }
122
+ // Items overflow: find the last item that fits alongside the trigger
123
+ let cumWidth = 0;
124
+ let lastFitting = -1;
125
+ for(let i = 0; i < itemWidths.length; i++){
126
+ const widthWithItem = cumWidth + (i > 0 ? gap : 0) + itemWidths[i];
127
+ if (widthWithItem + gap + triggerWidth <= containerWidth) {
128
+ cumWidth = widthWithItem;
129
+ lastFitting = i;
130
+ } else {
131
+ break;
132
+ }
133
+ }
134
+ setLastVisibleIndex(lastFitting);
135
+ }, [
136
+ containerRef
137
+ ]);
138
+ // Synchronous initial measurement before the first paint
139
+ React__namespace.useLayoutEffect(()=>{
140
+ measureOverflow();
141
+ }, [
142
+ measureOverflow
143
+ ]);
144
+ // Re-measure whenever the container resizes (e.g. BlocksDropdown label changes width)
145
+ React__namespace.useEffect(()=>{
146
+ const container = containerRef.current;
147
+ if (!container) return;
148
+ const ro = new ResizeObserver(measureOverflow);
149
+ ro.observe(container);
150
+ return ()=>ro.disconnect();
151
+ }, [
152
+ containerRef,
153
+ measureOverflow
154
+ ]);
92
155
  const [open, setOpen] = React__namespace.useState(false);
93
156
  const isMenuOpenWithContent = open && hasHiddenItems;
94
157
  const menuTriggerRef = strapiAdmin.useElementOnScreen((isVisible)=>{
@@ -101,19 +164,23 @@ const EditorToolbarObserver = ({ observedComponents, menuTriggerVariant = 'ghost
101
164
  // Maintain the menu state if it has content
102
165
  setOpen(isMenuOpenWithContent);
103
166
  }
104
- }, {
167
+ }, // Same getter pattern — root is read at effect time, not render time.
168
+ {
105
169
  threshold: 1,
106
- root: toolbarRef.current
170
+ get root () {
171
+ return containerRef.current;
172
+ }
107
173
  });
108
174
  return observedComponents.map((component, index)=>{
109
175
  return /*#__PURE__*/ jsxRuntime.jsx(ObservedToolbarComponent, {
110
176
  index: index,
111
177
  lastVisibleIndex: lastVisibleIndex,
112
178
  setLastVisibleIndex: setLastVisibleIndex,
113
- rootRef: toolbarRef,
179
+ rootRef: containerRef,
114
180
  children: component.toolbar
115
181
  }, component.key);
116
182
  }).toSpliced(menuIndex, 0, /*#__PURE__*/ jsxRuntime.jsx(MenuTriggerWrapper, {
183
+ "data-toolbar-trigger": "true",
117
184
  style: {
118
185
  visibility: hasHiddenItems ? 'visible' : 'hidden'
119
186
  },
@@ -1 +1 @@
1
- {"version":3,"file":"EditorToolbarObserver.js","sources":["../../../../../admin/src/pages/EditView/components/EditorToolbarObserver.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useElementOnScreen } from '@strapi/admin/strapi-admin';\nimport { Box, IconButton, Menu } from '@strapi/design-system';\nimport { More } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * ObservedToolbarComponent\n * -----------------------------------------------------------------------------------------------*/\n\ninterface ObservedToolbarComponentProps {\n index: number;\n lastVisibleIndex: number;\n setLastVisibleIndex: React.Dispatch<React.SetStateAction<number>>;\n rootRef: React.RefObject<HTMLElement>;\n children: React.ReactNode;\n}\n\nconst ObservedToolbarComponent = ({\n index,\n lastVisibleIndex,\n setLastVisibleIndex,\n rootRef,\n children,\n}: ObservedToolbarComponentProps) => {\n const isVisible = index <= lastVisibleIndex;\n\n const containerRef = useElementOnScreen<HTMLDivElement>(\n (isVisible) => {\n /**\n * It's the MoreMenu's job to make an item not visible when there's not room for it.\n * But we need to react here to the element becoming visible again.\n */\n if (isVisible) {\n setLastVisibleIndex((prev) => Math.max(prev, index));\n }\n },\n { threshold: 1, root: rootRef.current }\n );\n\n return (\n <div\n ref={containerRef}\n style={{\n /**\n * Use visibility so that the element occupies the space if requires even when there's not\n * enough room for it to be visible. The empty reserved space will be clipped by the\n * overflow:hidden rule on the parent, so it doesn't affect the UI.\n * This way we can keep observing its visiblity and react to browser resize events.\n */\n visibility: isVisible ? 'visible' : 'hidden',\n }}\n >\n {children}\n </div>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * EditorToolbarObserver\n * -----------------------------------------------------------------------------------------------*/\n\nexport interface ObservedComponent {\n toolbar: React.ReactNode;\n menu: React.ReactNode;\n key: string;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * MenuTriggerWrapper\n * -----------------------------------------------------------------------------------------------*/\n/**\n * The menu trigger is rendered by the observer, after the last visible toolbar item.\n * We use a wrapper with a ::before pseudo-element to render a vertical separator that\n * always appears immediately before the \"More\" menu button, regardless of which items\n * are visible or moved into the overflow menu.\n */\nconst MenuTriggerWrapper = styled(Box)`\n display: flex;\n align-items: center;\n\n &::before {\n content: '';\n background: ${({ theme }) => theme.colors.neutral150};\n width: 1px;\n height: 2.4rem;\n margin-left: ${({ theme }) => theme.spaces[1]};\n margin-right: ${({ theme }) => theme.spaces[1]};\n\n ${({ theme }) => theme.breakpoints.medium} {\n margin-left: ${({ theme }) => theme.spaces[2]};\n margin-right: ${({ theme }) => theme.spaces[2]};\n }\n }\n\n [data-hide-toolbar-separator='true'] &::before {\n display: none;\n }\n`;\n\nexport const EditorToolbarObserver = ({\n observedComponents,\n menuTriggerVariant = 'ghost',\n}: {\n observedComponents: ObservedComponent[];\n menuTriggerVariant?: Menu.TriggerProps['variant'];\n}) => {\n const { formatMessage } = useIntl();\n const toolbarRef = React.useRef<HTMLElement>(null);\n\n const [lastVisibleIndex, setLastVisibleIndex] = React.useState<number>(\n observedComponents.length - 1\n );\n const hasHiddenItems = lastVisibleIndex < observedComponents.length - 1;\n const menuIndex = lastVisibleIndex + 1;\n\n const [open, setOpen] = React.useState(false);\n const isMenuOpenWithContent = open && hasHiddenItems;\n const menuTriggerRef = useElementOnScreen<HTMLButtonElement>(\n (isVisible) => {\n // We only react to the menu becoming invisible. When that happens, we hide the last item.\n if (!isVisible) {\n /**\n * If there's no room for any item, the index can be -1.\n * This is intentional, in that case only the more menu will be visible.\n **/\n setLastVisibleIndex((prev) => prev - 1);\n // Maintain the menu state if it has content\n setOpen(isMenuOpenWithContent);\n }\n },\n { threshold: 1, root: toolbarRef.current }\n );\n\n return observedComponents\n .map((component, index) => {\n return (\n <ObservedToolbarComponent\n key={component.key}\n index={index}\n lastVisibleIndex={lastVisibleIndex}\n setLastVisibleIndex={setLastVisibleIndex}\n rootRef={toolbarRef}\n >\n {component.toolbar}\n </ObservedToolbarComponent>\n );\n })\n .toSpliced(\n menuIndex,\n 0,\n <MenuTriggerWrapper\n key=\"more-menu-wrapper\"\n style={{ visibility: hasHiddenItems ? 'visible' : 'hidden' }}\n >\n <Menu.Root defaultOpen={false} open={isMenuOpenWithContent} onOpenChange={setOpen}>\n <Menu.Trigger\n paddingLeft={0}\n paddingRight={0}\n ref={menuTriggerRef}\n variant={menuTriggerVariant}\n label={formatMessage({ id: 'global.more', defaultMessage: 'More' })}\n tag={IconButton}\n icon={<More />}\n />\n <Menu.Content\n onCloseAutoFocus={(e) => e.preventDefault()}\n maxHeight=\"100%\"\n minWidth=\"256px\"\n popoverPlacement=\"bottom-end\"\n zIndex={2}\n >\n {observedComponents.slice(menuIndex).map((component) => (\n <React.Fragment key={component.key}>{component.menu}</React.Fragment>\n ))}\n </Menu.Content>\n </Menu.Root>\n </MenuTriggerWrapper>\n );\n};\n"],"names":["ObservedToolbarComponent","index","lastVisibleIndex","setLastVisibleIndex","rootRef","children","isVisible","containerRef","useElementOnScreen","prev","Math","max","threshold","root","current","_jsx","div","ref","style","visibility","MenuTriggerWrapper","styled","Box","theme","colors","neutral150","spaces","breakpoints","medium","EditorToolbarObserver","observedComponents","menuTriggerVariant","formatMessage","useIntl","toolbarRef","React","useRef","useState","length","hasHiddenItems","menuIndex","open","setOpen","isMenuOpenWithContent","menuTriggerRef","map","component","toolbar","key","toSpliced","_jsxs","Menu","Root","defaultOpen","onOpenChange","Trigger","paddingLeft","paddingRight","variant","label","id","defaultMessage","tag","IconButton","icon","More","Content","onCloseAutoFocus","e","preventDefault","maxHeight","minWidth","popoverPlacement","zIndex","slice","Fragment","menu"],"mappings":"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"}
1
+ {"version":3,"file":"EditorToolbarObserver.js","sources":["../../../../../admin/src/pages/EditView/components/EditorToolbarObserver.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useElementOnScreen } from '@strapi/admin/strapi-admin';\nimport { Box, IconButton, Menu } from '@strapi/design-system';\nimport { More } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * ObservedToolbarComponent\n * -----------------------------------------------------------------------------------------------*/\n\ninterface ObservedToolbarComponentProps {\n index: number;\n lastVisibleIndex: number;\n setLastVisibleIndex: React.Dispatch<React.SetStateAction<number>>;\n rootRef: React.RefObject<HTMLElement | null>;\n children: React.ReactNode;\n}\n\nconst ObservedToolbarComponent = ({\n index,\n lastVisibleIndex,\n setLastVisibleIndex,\n rootRef,\n children,\n}: ObservedToolbarComponentProps) => {\n const isVisible = index <= lastVisibleIndex;\n\n const containerRef = useElementOnScreen<HTMLDivElement>(\n (isVisible) => {\n /**\n * It's the MoreMenu's job to make an item not visible when there's not room for it.\n * But we need to react here to the element becoming visible again.\n */\n if (isVisible) {\n setLastVisibleIndex((prev) => Math.max(prev, index));\n }\n },\n // Use a getter so root is read inside useElementOnScreen's useEffect (after refs are\n // committed) rather than at render time (when containerRef.current is still null).\n {\n threshold: 1,\n get root() {\n return rootRef.current;\n },\n }\n );\n\n return (\n <div\n ref={containerRef}\n data-toolbar-item=\"true\"\n style={{\n /**\n * Use visibility so that the element occupies the space if requires even when there's not\n * enough room for it to be visible. The empty reserved space will be clipped by the\n * overflow:hidden rule on the parent, so it doesn't affect the UI.\n * This way we can keep observing its visiblity and react to browser resize events.\n */\n visibility: isVisible ? 'visible' : 'hidden',\n }}\n >\n {children}\n </div>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * EditorToolbarObserver\n * -----------------------------------------------------------------------------------------------*/\n\nexport interface ObservedComponent {\n toolbar: React.ReactNode;\n menu: React.ReactNode;\n key: string;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * MenuTriggerWrapper\n * -----------------------------------------------------------------------------------------------*/\n/**\n * The menu trigger is rendered by the observer, after the last visible toolbar item.\n * We use a wrapper with a ::before pseudo-element to render a vertical separator that\n * always appears immediately before the \"More\" menu button, regardless of which items\n * are visible or moved into the overflow menu.\n */\nconst MenuTriggerWrapper = styled(Box)`\n display: flex;\n align-items: center;\n\n &::before {\n content: '';\n background: ${({ theme }) => theme.colors.neutral150};\n width: 1px;\n height: 2.4rem;\n margin-left: ${({ theme }) => theme.spaces[1]};\n margin-right: ${({ theme }) => theme.spaces[1]};\n\n ${({ theme }) => theme.breakpoints.medium} {\n margin-left: ${({ theme }) => theme.spaces[2]};\n margin-right: ${({ theme }) => theme.spaces[2]};\n }\n }\n\n [data-hide-toolbar-separator='true'] &::before {\n display: none;\n }\n`;\n\nexport const EditorToolbarObserver = ({\n observedComponents,\n menuTriggerVariant = 'ghost',\n containerRef,\n}: {\n observedComponents: ObservedComponent[];\n menuTriggerVariant?: Menu.TriggerProps['variant'];\n containerRef: React.RefObject<HTMLElement | null>;\n}) => {\n const { formatMessage } = useIntl();\n\n const [lastVisibleIndex, setLastVisibleIndex] = React.useState<number>(\n observedComponents.length - 1\n );\n const hasHiddenItems = lastVisibleIndex < observedComponents.length - 1;\n const menuIndex = lastVisibleIndex + 1;\n\n /**\n * Measure whether toolbar items overflow the container using clientWidth/offsetWidth.\n * These layout-box dimensions are unaffected by CSS transforms (including the Radix\n * popover positioning transform), so the result is always correct.\n *\n * We run this both synchronously on mount (useLayoutEffect) and on every container\n * resize (ResizeObserver) so that label changes in BlocksDropdown, which narrow the\n * toolbar container, are caught and the More menu appears as needed.\n */\n const measureOverflow = React.useCallback(() => {\n const container = containerRef.current;\n if (!container) return;\n\n // Items are in DOM order 0..N-1 regardless of where the trigger sits.\n // data-toolbar-trigger is skipped by the [data-toolbar-item] selector.\n const triggerEl = container.querySelector(\n '[data-toolbar-trigger=\"true\"]'\n ) as HTMLElement | null;\n const itemEls = Array.from(\n container.querySelectorAll('[data-toolbar-item=\"true\"]')\n ) as HTMLElement[];\n\n if (!triggerEl || itemEls.length === 0) return;\n\n const containerWidth = container.clientWidth;\n const triggerWidth = triggerEl.offsetWidth;\n const gap = parseFloat(getComputedStyle(container).columnGap) || 0;\n\n const itemWidths = itemEls.map((el) => el.offsetWidth);\n const totalItemsWidth = itemWidths.reduce((sum, w) => sum + w, 0);\n\n // Check if all items fit without the trigger\n if (totalItemsWidth + Math.max(0, itemEls.length - 1) * gap <= containerWidth) {\n setLastVisibleIndex(itemEls.length - 1);\n return;\n }\n\n // Items overflow: find the last item that fits alongside the trigger\n let cumWidth = 0;\n let lastFitting = -1;\n for (let i = 0; i < itemWidths.length; i++) {\n const widthWithItem = cumWidth + (i > 0 ? gap : 0) + itemWidths[i];\n if (widthWithItem + gap + triggerWidth <= containerWidth) {\n cumWidth = widthWithItem;\n lastFitting = i;\n } else {\n break;\n }\n }\n\n setLastVisibleIndex(lastFitting);\n }, [containerRef]);\n\n // Synchronous initial measurement before the first paint\n React.useLayoutEffect(() => {\n measureOverflow();\n }, [measureOverflow]);\n\n // Re-measure whenever the container resizes (e.g. BlocksDropdown label changes width)\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const ro = new ResizeObserver(measureOverflow);\n ro.observe(container);\n return () => ro.disconnect();\n }, [containerRef, measureOverflow]);\n\n const [open, setOpen] = React.useState(false);\n const isMenuOpenWithContent = open && hasHiddenItems;\n const menuTriggerRef = useElementOnScreen<HTMLButtonElement>(\n (isVisible) => {\n // We only react to the menu becoming invisible. When that happens, we hide the last item.\n if (!isVisible) {\n /**\n * If there's no room for any item, the index can be -1.\n * This is intentional, in that case only the more menu will be visible.\n **/\n setLastVisibleIndex((prev) => prev - 1);\n // Maintain the menu state if it has content\n setOpen(isMenuOpenWithContent);\n }\n },\n // Same getter pattern — root is read at effect time, not render time.\n {\n threshold: 1,\n get root() {\n return containerRef.current;\n },\n }\n );\n\n return observedComponents\n .map((component, index) => {\n return (\n <ObservedToolbarComponent\n key={component.key}\n index={index}\n lastVisibleIndex={lastVisibleIndex}\n setLastVisibleIndex={setLastVisibleIndex}\n rootRef={containerRef}\n >\n {component.toolbar}\n </ObservedToolbarComponent>\n );\n })\n .toSpliced(\n menuIndex,\n 0,\n <MenuTriggerWrapper\n key=\"more-menu-wrapper\"\n data-toolbar-trigger=\"true\"\n style={{ visibility: hasHiddenItems ? 'visible' : 'hidden' }}\n >\n <Menu.Root defaultOpen={false} open={isMenuOpenWithContent} onOpenChange={setOpen}>\n <Menu.Trigger\n paddingLeft={0}\n paddingRight={0}\n ref={menuTriggerRef}\n variant={menuTriggerVariant}\n label={formatMessage({ id: 'global.more', defaultMessage: 'More' })}\n tag={IconButton}\n icon={<More />}\n />\n <Menu.Content\n onCloseAutoFocus={(e) => e.preventDefault()}\n maxHeight=\"100%\"\n minWidth=\"256px\"\n popoverPlacement=\"bottom-end\"\n zIndex={2}\n >\n {observedComponents.slice(menuIndex).map((component) => (\n <React.Fragment key={component.key}>{component.menu}</React.Fragment>\n ))}\n </Menu.Content>\n </Menu.Root>\n </MenuTriggerWrapper>\n );\n};\n"],"names":["ObservedToolbarComponent","index","lastVisibleIndex","setLastVisibleIndex","rootRef","children","isVisible","containerRef","useElementOnScreen","prev","Math","max","threshold","root","current","_jsx","div","ref","data-toolbar-item","style","visibility","MenuTriggerWrapper","styled","Box","theme","colors","neutral150","spaces","breakpoints","medium","EditorToolbarObserver","observedComponents","menuTriggerVariant","formatMessage","useIntl","React","useState","length","hasHiddenItems","menuIndex","measureOverflow","useCallback","container","triggerEl","querySelector","itemEls","Array","from","querySelectorAll","containerWidth","clientWidth","triggerWidth","offsetWidth","gap","parseFloat","getComputedStyle","columnGap","itemWidths","map","el","totalItemsWidth","reduce","sum","w","cumWidth","lastFitting","i","widthWithItem","useLayoutEffect","useEffect","ro","ResizeObserver","observe","disconnect","open","setOpen","isMenuOpenWithContent","menuTriggerRef","component","toolbar","key","toSpliced","data-toolbar-trigger","_jsxs","Menu","Root","defaultOpen","onOpenChange","Trigger","paddingLeft","paddingRight","variant","label","id","defaultMessage","tag","IconButton","icon","More","Content","onCloseAutoFocus","e","preventDefault","maxHeight","minWidth","popoverPlacement","zIndex","slice","Fragment","menu"],"mappings":"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"}
@@ -15,12 +15,17 @@ const ObservedToolbarComponent = ({ index, lastVisibleIndex, setLastVisibleIndex
15
15
  */ if (isVisible) {
16
16
  setLastVisibleIndex((prev)=>Math.max(prev, index));
17
17
  }
18
- }, {
18
+ }, // Use a getter so root is read inside useElementOnScreen's useEffect (after refs are
19
+ // committed) rather than at render time (when containerRef.current is still null).
20
+ {
19
21
  threshold: 1,
20
- root: rootRef.current
22
+ get root () {
23
+ return rootRef.current;
24
+ }
21
25
  });
22
26
  return /*#__PURE__*/ jsx("div", {
23
27
  ref: containerRef,
28
+ "data-toolbar-item": "true",
24
29
  style: {
25
30
  /**
26
31
  * Use visibility so that the element occupies the space if requires even when there's not
@@ -61,12 +66,70 @@ const ObservedToolbarComponent = ({ index, lastVisibleIndex, setLastVisibleIndex
61
66
  display: none;
62
67
  }
63
68
  `;
64
- const EditorToolbarObserver = ({ observedComponents, menuTriggerVariant = 'ghost' })=>{
69
+ const EditorToolbarObserver = ({ observedComponents, menuTriggerVariant = 'ghost', containerRef })=>{
65
70
  const { formatMessage } = useIntl();
66
- const toolbarRef = React.useRef(null);
67
71
  const [lastVisibleIndex, setLastVisibleIndex] = React.useState(observedComponents.length - 1);
68
72
  const hasHiddenItems = lastVisibleIndex < observedComponents.length - 1;
69
73
  const menuIndex = lastVisibleIndex + 1;
74
+ /**
75
+ * Measure whether toolbar items overflow the container using clientWidth/offsetWidth.
76
+ * These layout-box dimensions are unaffected by CSS transforms (including the Radix
77
+ * popover positioning transform), so the result is always correct.
78
+ *
79
+ * We run this both synchronously on mount (useLayoutEffect) and on every container
80
+ * resize (ResizeObserver) so that label changes in BlocksDropdown, which narrow the
81
+ * toolbar container, are caught and the More menu appears as needed.
82
+ */ const measureOverflow = React.useCallback(()=>{
83
+ const container = containerRef.current;
84
+ if (!container) return;
85
+ // Items are in DOM order 0..N-1 regardless of where the trigger sits.
86
+ // data-toolbar-trigger is skipped by the [data-toolbar-item] selector.
87
+ const triggerEl = container.querySelector('[data-toolbar-trigger="true"]');
88
+ const itemEls = Array.from(container.querySelectorAll('[data-toolbar-item="true"]'));
89
+ if (!triggerEl || itemEls.length === 0) return;
90
+ const containerWidth = container.clientWidth;
91
+ const triggerWidth = triggerEl.offsetWidth;
92
+ const gap = parseFloat(getComputedStyle(container).columnGap) || 0;
93
+ const itemWidths = itemEls.map((el)=>el.offsetWidth);
94
+ const totalItemsWidth = itemWidths.reduce((sum, w)=>sum + w, 0);
95
+ // Check if all items fit without the trigger
96
+ if (totalItemsWidth + Math.max(0, itemEls.length - 1) * gap <= containerWidth) {
97
+ setLastVisibleIndex(itemEls.length - 1);
98
+ return;
99
+ }
100
+ // Items overflow: find the last item that fits alongside the trigger
101
+ let cumWidth = 0;
102
+ let lastFitting = -1;
103
+ for(let i = 0; i < itemWidths.length; i++){
104
+ const widthWithItem = cumWidth + (i > 0 ? gap : 0) + itemWidths[i];
105
+ if (widthWithItem + gap + triggerWidth <= containerWidth) {
106
+ cumWidth = widthWithItem;
107
+ lastFitting = i;
108
+ } else {
109
+ break;
110
+ }
111
+ }
112
+ setLastVisibleIndex(lastFitting);
113
+ }, [
114
+ containerRef
115
+ ]);
116
+ // Synchronous initial measurement before the first paint
117
+ React.useLayoutEffect(()=>{
118
+ measureOverflow();
119
+ }, [
120
+ measureOverflow
121
+ ]);
122
+ // Re-measure whenever the container resizes (e.g. BlocksDropdown label changes width)
123
+ React.useEffect(()=>{
124
+ const container = containerRef.current;
125
+ if (!container) return;
126
+ const ro = new ResizeObserver(measureOverflow);
127
+ ro.observe(container);
128
+ return ()=>ro.disconnect();
129
+ }, [
130
+ containerRef,
131
+ measureOverflow
132
+ ]);
70
133
  const [open, setOpen] = React.useState(false);
71
134
  const isMenuOpenWithContent = open && hasHiddenItems;
72
135
  const menuTriggerRef = useElementOnScreen((isVisible)=>{
@@ -79,19 +142,23 @@ const EditorToolbarObserver = ({ observedComponents, menuTriggerVariant = 'ghost
79
142
  // Maintain the menu state if it has content
80
143
  setOpen(isMenuOpenWithContent);
81
144
  }
82
- }, {
145
+ }, // Same getter pattern — root is read at effect time, not render time.
146
+ {
83
147
  threshold: 1,
84
- root: toolbarRef.current
148
+ get root () {
149
+ return containerRef.current;
150
+ }
85
151
  });
86
152
  return observedComponents.map((component, index)=>{
87
153
  return /*#__PURE__*/ jsx(ObservedToolbarComponent, {
88
154
  index: index,
89
155
  lastVisibleIndex: lastVisibleIndex,
90
156
  setLastVisibleIndex: setLastVisibleIndex,
91
- rootRef: toolbarRef,
157
+ rootRef: containerRef,
92
158
  children: component.toolbar
93
159
  }, component.key);
94
160
  }).toSpliced(menuIndex, 0, /*#__PURE__*/ jsx(MenuTriggerWrapper, {
161
+ "data-toolbar-trigger": "true",
95
162
  style: {
96
163
  visibility: hasHiddenItems ? 'visible' : 'hidden'
97
164
  },
@@ -1 +1 @@
1
- {"version":3,"file":"EditorToolbarObserver.mjs","sources":["../../../../../admin/src/pages/EditView/components/EditorToolbarObserver.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useElementOnScreen } from '@strapi/admin/strapi-admin';\nimport { Box, IconButton, Menu } from '@strapi/design-system';\nimport { More } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * ObservedToolbarComponent\n * -----------------------------------------------------------------------------------------------*/\n\ninterface ObservedToolbarComponentProps {\n index: number;\n lastVisibleIndex: number;\n setLastVisibleIndex: React.Dispatch<React.SetStateAction<number>>;\n rootRef: React.RefObject<HTMLElement>;\n children: React.ReactNode;\n}\n\nconst ObservedToolbarComponent = ({\n index,\n lastVisibleIndex,\n setLastVisibleIndex,\n rootRef,\n children,\n}: ObservedToolbarComponentProps) => {\n const isVisible = index <= lastVisibleIndex;\n\n const containerRef = useElementOnScreen<HTMLDivElement>(\n (isVisible) => {\n /**\n * It's the MoreMenu's job to make an item not visible when there's not room for it.\n * But we need to react here to the element becoming visible again.\n */\n if (isVisible) {\n setLastVisibleIndex((prev) => Math.max(prev, index));\n }\n },\n { threshold: 1, root: rootRef.current }\n );\n\n return (\n <div\n ref={containerRef}\n style={{\n /**\n * Use visibility so that the element occupies the space if requires even when there's not\n * enough room for it to be visible. The empty reserved space will be clipped by the\n * overflow:hidden rule on the parent, so it doesn't affect the UI.\n * This way we can keep observing its visiblity and react to browser resize events.\n */\n visibility: isVisible ? 'visible' : 'hidden',\n }}\n >\n {children}\n </div>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * EditorToolbarObserver\n * -----------------------------------------------------------------------------------------------*/\n\nexport interface ObservedComponent {\n toolbar: React.ReactNode;\n menu: React.ReactNode;\n key: string;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * MenuTriggerWrapper\n * -----------------------------------------------------------------------------------------------*/\n/**\n * The menu trigger is rendered by the observer, after the last visible toolbar item.\n * We use a wrapper with a ::before pseudo-element to render a vertical separator that\n * always appears immediately before the \"More\" menu button, regardless of which items\n * are visible or moved into the overflow menu.\n */\nconst MenuTriggerWrapper = styled(Box)`\n display: flex;\n align-items: center;\n\n &::before {\n content: '';\n background: ${({ theme }) => theme.colors.neutral150};\n width: 1px;\n height: 2.4rem;\n margin-left: ${({ theme }) => theme.spaces[1]};\n margin-right: ${({ theme }) => theme.spaces[1]};\n\n ${({ theme }) => theme.breakpoints.medium} {\n margin-left: ${({ theme }) => theme.spaces[2]};\n margin-right: ${({ theme }) => theme.spaces[2]};\n }\n }\n\n [data-hide-toolbar-separator='true'] &::before {\n display: none;\n }\n`;\n\nexport const EditorToolbarObserver = ({\n observedComponents,\n menuTriggerVariant = 'ghost',\n}: {\n observedComponents: ObservedComponent[];\n menuTriggerVariant?: Menu.TriggerProps['variant'];\n}) => {\n const { formatMessage } = useIntl();\n const toolbarRef = React.useRef<HTMLElement>(null);\n\n const [lastVisibleIndex, setLastVisibleIndex] = React.useState<number>(\n observedComponents.length - 1\n );\n const hasHiddenItems = lastVisibleIndex < observedComponents.length - 1;\n const menuIndex = lastVisibleIndex + 1;\n\n const [open, setOpen] = React.useState(false);\n const isMenuOpenWithContent = open && hasHiddenItems;\n const menuTriggerRef = useElementOnScreen<HTMLButtonElement>(\n (isVisible) => {\n // We only react to the menu becoming invisible. When that happens, we hide the last item.\n if (!isVisible) {\n /**\n * If there's no room for any item, the index can be -1.\n * This is intentional, in that case only the more menu will be visible.\n **/\n setLastVisibleIndex((prev) => prev - 1);\n // Maintain the menu state if it has content\n setOpen(isMenuOpenWithContent);\n }\n },\n { threshold: 1, root: toolbarRef.current }\n );\n\n return observedComponents\n .map((component, index) => {\n return (\n <ObservedToolbarComponent\n key={component.key}\n index={index}\n lastVisibleIndex={lastVisibleIndex}\n setLastVisibleIndex={setLastVisibleIndex}\n rootRef={toolbarRef}\n >\n {component.toolbar}\n </ObservedToolbarComponent>\n );\n })\n .toSpliced(\n menuIndex,\n 0,\n <MenuTriggerWrapper\n key=\"more-menu-wrapper\"\n style={{ visibility: hasHiddenItems ? 'visible' : 'hidden' }}\n >\n <Menu.Root defaultOpen={false} open={isMenuOpenWithContent} onOpenChange={setOpen}>\n <Menu.Trigger\n paddingLeft={0}\n paddingRight={0}\n ref={menuTriggerRef}\n variant={menuTriggerVariant}\n label={formatMessage({ id: 'global.more', defaultMessage: 'More' })}\n tag={IconButton}\n icon={<More />}\n />\n <Menu.Content\n onCloseAutoFocus={(e) => e.preventDefault()}\n maxHeight=\"100%\"\n minWidth=\"256px\"\n popoverPlacement=\"bottom-end\"\n zIndex={2}\n >\n {observedComponents.slice(menuIndex).map((component) => (\n <React.Fragment key={component.key}>{component.menu}</React.Fragment>\n ))}\n </Menu.Content>\n </Menu.Root>\n </MenuTriggerWrapper>\n );\n};\n"],"names":["ObservedToolbarComponent","index","lastVisibleIndex","setLastVisibleIndex","rootRef","children","isVisible","containerRef","useElementOnScreen","prev","Math","max","threshold","root","current","_jsx","div","ref","style","visibility","MenuTriggerWrapper","styled","Box","theme","colors","neutral150","spaces","breakpoints","medium","EditorToolbarObserver","observedComponents","menuTriggerVariant","formatMessage","useIntl","toolbarRef","React","useRef","useState","length","hasHiddenItems","menuIndex","open","setOpen","isMenuOpenWithContent","menuTriggerRef","map","component","toolbar","key","toSpliced","_jsxs","Menu","Root","defaultOpen","onOpenChange","Trigger","paddingLeft","paddingRight","variant","label","id","defaultMessage","tag","IconButton","icon","More","Content","onCloseAutoFocus","e","preventDefault","maxHeight","minWidth","popoverPlacement","zIndex","slice","Fragment","menu"],"mappings":"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"}
1
+ {"version":3,"file":"EditorToolbarObserver.mjs","sources":["../../../../../admin/src/pages/EditView/components/EditorToolbarObserver.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useElementOnScreen } from '@strapi/admin/strapi-admin';\nimport { Box, IconButton, Menu } from '@strapi/design-system';\nimport { More } from '@strapi/icons';\nimport { useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\n/* -------------------------------------------------------------------------------------------------\n * ObservedToolbarComponent\n * -----------------------------------------------------------------------------------------------*/\n\ninterface ObservedToolbarComponentProps {\n index: number;\n lastVisibleIndex: number;\n setLastVisibleIndex: React.Dispatch<React.SetStateAction<number>>;\n rootRef: React.RefObject<HTMLElement | null>;\n children: React.ReactNode;\n}\n\nconst ObservedToolbarComponent = ({\n index,\n lastVisibleIndex,\n setLastVisibleIndex,\n rootRef,\n children,\n}: ObservedToolbarComponentProps) => {\n const isVisible = index <= lastVisibleIndex;\n\n const containerRef = useElementOnScreen<HTMLDivElement>(\n (isVisible) => {\n /**\n * It's the MoreMenu's job to make an item not visible when there's not room for it.\n * But we need to react here to the element becoming visible again.\n */\n if (isVisible) {\n setLastVisibleIndex((prev) => Math.max(prev, index));\n }\n },\n // Use a getter so root is read inside useElementOnScreen's useEffect (after refs are\n // committed) rather than at render time (when containerRef.current is still null).\n {\n threshold: 1,\n get root() {\n return rootRef.current;\n },\n }\n );\n\n return (\n <div\n ref={containerRef}\n data-toolbar-item=\"true\"\n style={{\n /**\n * Use visibility so that the element occupies the space if requires even when there's not\n * enough room for it to be visible. The empty reserved space will be clipped by the\n * overflow:hidden rule on the parent, so it doesn't affect the UI.\n * This way we can keep observing its visiblity and react to browser resize events.\n */\n visibility: isVisible ? 'visible' : 'hidden',\n }}\n >\n {children}\n </div>\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * EditorToolbarObserver\n * -----------------------------------------------------------------------------------------------*/\n\nexport interface ObservedComponent {\n toolbar: React.ReactNode;\n menu: React.ReactNode;\n key: string;\n}\n\n/* -------------------------------------------------------------------------------------------------\n * MenuTriggerWrapper\n * -----------------------------------------------------------------------------------------------*/\n/**\n * The menu trigger is rendered by the observer, after the last visible toolbar item.\n * We use a wrapper with a ::before pseudo-element to render a vertical separator that\n * always appears immediately before the \"More\" menu button, regardless of which items\n * are visible or moved into the overflow menu.\n */\nconst MenuTriggerWrapper = styled(Box)`\n display: flex;\n align-items: center;\n\n &::before {\n content: '';\n background: ${({ theme }) => theme.colors.neutral150};\n width: 1px;\n height: 2.4rem;\n margin-left: ${({ theme }) => theme.spaces[1]};\n margin-right: ${({ theme }) => theme.spaces[1]};\n\n ${({ theme }) => theme.breakpoints.medium} {\n margin-left: ${({ theme }) => theme.spaces[2]};\n margin-right: ${({ theme }) => theme.spaces[2]};\n }\n }\n\n [data-hide-toolbar-separator='true'] &::before {\n display: none;\n }\n`;\n\nexport const EditorToolbarObserver = ({\n observedComponents,\n menuTriggerVariant = 'ghost',\n containerRef,\n}: {\n observedComponents: ObservedComponent[];\n menuTriggerVariant?: Menu.TriggerProps['variant'];\n containerRef: React.RefObject<HTMLElement | null>;\n}) => {\n const { formatMessage } = useIntl();\n\n const [lastVisibleIndex, setLastVisibleIndex] = React.useState<number>(\n observedComponents.length - 1\n );\n const hasHiddenItems = lastVisibleIndex < observedComponents.length - 1;\n const menuIndex = lastVisibleIndex + 1;\n\n /**\n * Measure whether toolbar items overflow the container using clientWidth/offsetWidth.\n * These layout-box dimensions are unaffected by CSS transforms (including the Radix\n * popover positioning transform), so the result is always correct.\n *\n * We run this both synchronously on mount (useLayoutEffect) and on every container\n * resize (ResizeObserver) so that label changes in BlocksDropdown, which narrow the\n * toolbar container, are caught and the More menu appears as needed.\n */\n const measureOverflow = React.useCallback(() => {\n const container = containerRef.current;\n if (!container) return;\n\n // Items are in DOM order 0..N-1 regardless of where the trigger sits.\n // data-toolbar-trigger is skipped by the [data-toolbar-item] selector.\n const triggerEl = container.querySelector(\n '[data-toolbar-trigger=\"true\"]'\n ) as HTMLElement | null;\n const itemEls = Array.from(\n container.querySelectorAll('[data-toolbar-item=\"true\"]')\n ) as HTMLElement[];\n\n if (!triggerEl || itemEls.length === 0) return;\n\n const containerWidth = container.clientWidth;\n const triggerWidth = triggerEl.offsetWidth;\n const gap = parseFloat(getComputedStyle(container).columnGap) || 0;\n\n const itemWidths = itemEls.map((el) => el.offsetWidth);\n const totalItemsWidth = itemWidths.reduce((sum, w) => sum + w, 0);\n\n // Check if all items fit without the trigger\n if (totalItemsWidth + Math.max(0, itemEls.length - 1) * gap <= containerWidth) {\n setLastVisibleIndex(itemEls.length - 1);\n return;\n }\n\n // Items overflow: find the last item that fits alongside the trigger\n let cumWidth = 0;\n let lastFitting = -1;\n for (let i = 0; i < itemWidths.length; i++) {\n const widthWithItem = cumWidth + (i > 0 ? gap : 0) + itemWidths[i];\n if (widthWithItem + gap + triggerWidth <= containerWidth) {\n cumWidth = widthWithItem;\n lastFitting = i;\n } else {\n break;\n }\n }\n\n setLastVisibleIndex(lastFitting);\n }, [containerRef]);\n\n // Synchronous initial measurement before the first paint\n React.useLayoutEffect(() => {\n measureOverflow();\n }, [measureOverflow]);\n\n // Re-measure whenever the container resizes (e.g. BlocksDropdown label changes width)\n React.useEffect(() => {\n const container = containerRef.current;\n if (!container) return;\n const ro = new ResizeObserver(measureOverflow);\n ro.observe(container);\n return () => ro.disconnect();\n }, [containerRef, measureOverflow]);\n\n const [open, setOpen] = React.useState(false);\n const isMenuOpenWithContent = open && hasHiddenItems;\n const menuTriggerRef = useElementOnScreen<HTMLButtonElement>(\n (isVisible) => {\n // We only react to the menu becoming invisible. When that happens, we hide the last item.\n if (!isVisible) {\n /**\n * If there's no room for any item, the index can be -1.\n * This is intentional, in that case only the more menu will be visible.\n **/\n setLastVisibleIndex((prev) => prev - 1);\n // Maintain the menu state if it has content\n setOpen(isMenuOpenWithContent);\n }\n },\n // Same getter pattern — root is read at effect time, not render time.\n {\n threshold: 1,\n get root() {\n return containerRef.current;\n },\n }\n );\n\n return observedComponents\n .map((component, index) => {\n return (\n <ObservedToolbarComponent\n key={component.key}\n index={index}\n lastVisibleIndex={lastVisibleIndex}\n setLastVisibleIndex={setLastVisibleIndex}\n rootRef={containerRef}\n >\n {component.toolbar}\n </ObservedToolbarComponent>\n );\n })\n .toSpliced(\n menuIndex,\n 0,\n <MenuTriggerWrapper\n key=\"more-menu-wrapper\"\n data-toolbar-trigger=\"true\"\n style={{ visibility: hasHiddenItems ? 'visible' : 'hidden' }}\n >\n <Menu.Root defaultOpen={false} open={isMenuOpenWithContent} onOpenChange={setOpen}>\n <Menu.Trigger\n paddingLeft={0}\n paddingRight={0}\n ref={menuTriggerRef}\n variant={menuTriggerVariant}\n label={formatMessage({ id: 'global.more', defaultMessage: 'More' })}\n tag={IconButton}\n icon={<More />}\n />\n <Menu.Content\n onCloseAutoFocus={(e) => e.preventDefault()}\n maxHeight=\"100%\"\n minWidth=\"256px\"\n popoverPlacement=\"bottom-end\"\n zIndex={2}\n >\n {observedComponents.slice(menuIndex).map((component) => (\n <React.Fragment key={component.key}>{component.menu}</React.Fragment>\n ))}\n </Menu.Content>\n </Menu.Root>\n </MenuTriggerWrapper>\n );\n};\n"],"names":["ObservedToolbarComponent","index","lastVisibleIndex","setLastVisibleIndex","rootRef","children","isVisible","containerRef","useElementOnScreen","prev","Math","max","threshold","root","current","_jsx","div","ref","data-toolbar-item","style","visibility","MenuTriggerWrapper","styled","Box","theme","colors","neutral150","spaces","breakpoints","medium","EditorToolbarObserver","observedComponents","menuTriggerVariant","formatMessage","useIntl","React","useState","length","hasHiddenItems","menuIndex","measureOverflow","useCallback","container","triggerEl","querySelector","itemEls","Array","from","querySelectorAll","containerWidth","clientWidth","triggerWidth","offsetWidth","gap","parseFloat","getComputedStyle","columnGap","itemWidths","map","el","totalItemsWidth","reduce","sum","w","cumWidth","lastFitting","i","widthWithItem","useLayoutEffect","useEffect","ro","ResizeObserver","observe","disconnect","open","setOpen","isMenuOpenWithContent","menuTriggerRef","component","toolbar","key","toSpliced","data-toolbar-trigger","_jsxs","Menu","Root","defaultOpen","onOpenChange","Trigger","paddingLeft","paddingRight","variant","label","id","defaultMessage","tag","IconButton","icon","More","Content","onCloseAutoFocus","e","preventDefault","maxHeight","minWidth","popoverPlacement","zIndex","slice","Fragment","menu"],"mappings":"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"}
@@ -32,6 +32,28 @@ var React__namespace = /*#__PURE__*/_interopNamespace(React);
32
32
  const isLinkNode = (element)=>{
33
33
  return element.type === 'link';
34
34
  };
35
+ const ALLOWED_LINK_PROTOCOLS = new Set([
36
+ 'http:',
37
+ 'https:',
38
+ 'ftp:',
39
+ 'mailto:',
40
+ 'tel:'
41
+ ]);
42
+ const isValidLink = (link)=>{
43
+ try {
44
+ const url = new URL(link.startsWith('/') ? `https://strapi.io${link}` : link);
45
+ return ALLOWED_LINK_PROTOCOLS.has(url.protocol);
46
+ } catch {
47
+ return false;
48
+ }
49
+ };
50
+ const isValidAbsoluteLink = (link)=>{
51
+ try {
52
+ return ALLOWED_LINK_PROTOCOLS.has(new URL(link).protocol);
53
+ } catch {
54
+ return false;
55
+ }
56
+ };
35
57
  const removeLink = (editor)=>{
36
58
  slate.Transforms.unwrapNodes(editor, {
37
59
  match: (node)=>!slate.Editor.isEditor(node) && slate.Element.isElement(node) && node.type === 'link'
@@ -129,23 +151,14 @@ const LinkContent = /*#__PURE__*/ React__namespace.forwardRef(({ link, children,
129
151
  const [linkTarget, setLinkTarget] = React__namespace.useState(link.target);
130
152
  const linkInputRef = React__namespace.useRef(null);
131
153
  const isLastInsertedLink = editor.lastInsertedLinkPath ? !slate.Path.equals(path, editor.lastInsertedLinkPath) : true;
132
- const [isSaveDisabled, setIsSaveDisabled] = React__namespace.useState(false);
154
+ const isSaveDisabled = !isValidLink(linkUrl);
133
155
  const onLinkChange = (e)=>{
134
- setIsSaveDisabled(false);
135
156
  setLinkUrl(e.target.value);
136
- try {
137
- // eslint-disable-next-line no-new
138
- new URL(e.target.value?.startsWith('/') ? `https://strapi.io${e.target.value}` : e.target.value);
139
- } catch {
140
- setIsSaveDisabled(true);
141
- }
142
157
  };
143
158
  const onLinkRelChange = (e)=>{
144
- setIsSaveDisabled(false);
145
159
  setLinRel(e.target.value);
146
160
  };
147
161
  const onLinkTargetChange = (e)=>{
148
- setIsSaveDisabled(false);
149
162
  setLinkTarget(e.target.value);
150
163
  };
151
164
  const handleSave = (e)=>{
@@ -187,7 +200,7 @@ const LinkContent = /*#__PURE__*/ React__namespace.forwardRef(({ link, children,
187
200
  ...attributes,
188
201
  ref: forwardedRef,
189
202
  tag: "a",
190
- href: link.url,
203
+ href: isValidLink(link.url) ? link.url : undefined,
191
204
  rel: link.rel,
192
205
  target: link.target,
193
206
  onClick: ()=>setPopoverOpen(true),
@@ -425,17 +438,13 @@ const withLinks = (editor)=>{
425
438
  editor.insertData = (data)=>{
426
439
  const pastedText = data.getData('text/plain');
427
440
  if (pastedText) {
428
- try {
429
- // eslint-disable-next-line no-new
430
- new URL(pastedText);
441
+ if (isValidAbsoluteLink(pastedText)) {
431
442
  // Do not show link popup on copy-paste a link, so do not save its path
432
443
  editor.shouldSaveLinkPath = false;
433
444
  insertLink(editor, {
434
445
  url: pastedText
435
446
  });
436
447
  return;
437
- } catch {
438
- // continue normal data insertion
439
448
  }
440
449
  }
441
450
  insertData(data);
@@ -1 +1 @@
1
- {"version":3,"file":"Link.js","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Button, Field, Flex, Popover } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport {\n BaseEditor,\n Editor,\n Element,\n Path,\n Point,\n Range,\n Transforms,\n Element as SlateElement,\n Node,\n} from 'slate';\nimport { type RenderElementProps, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\n\nimport { type BlocksStore, useBlocksEditorContext } from '../BlocksEditor';\nimport { type Block } from '../utils/types';\n\nimport type { Schema } from '@strapi/types';\n\nconst isLinkNode = (element: Element): element is Schema.Attribute.LinkInlineNode => {\n return element.type === 'link';\n};\n\nconst removeLink = (editor: Editor) => {\n Transforms.unwrapNodes(editor, {\n match: (node) => !Editor.isEditor(node) && SlateElement.isElement(node) && node.type === 'link',\n });\n};\n\nconst insertLink = (editor: Editor, { url }: { url: string }) => {\n if (editor.selection) {\n // We want to remove all link on the selection\n const linkNodes = Array.from(\n Editor.nodes(editor, {\n at: editor.selection,\n match: (node) => !Editor.isEditor(node) && node.type === 'link',\n })\n );\n\n linkNodes.forEach(([, path]) => {\n Transforms.unwrapNodes(editor, { at: path });\n });\n\n if (Range.isCollapsed(editor.selection)) {\n const link: Block<'link'> = {\n type: 'link',\n url: url ?? '',\n children: [{ type: 'text', text: url }],\n rel: '',\n target: '',\n };\n\n Transforms.insertNodes(editor, link);\n } else {\n Transforms.wrapNodes(editor, { type: 'link', url: url ?? '' } as Block<'link'>, {\n split: true,\n });\n }\n }\n};\n\nconst editLink = (\n editor: Editor,\n link: { url: string; text: string; rel: string; target: string }\n) => {\n const { url, text, rel, target } = link;\n\n if (!editor.selection) {\n return;\n }\n\n const linkEntry = Editor.above(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'link',\n });\n\n if (linkEntry) {\n const [, linkPath] = linkEntry;\n Transforms.setNodes(editor, { url, rel, target }, { at: linkPath });\n\n // If link text is different, we remove the old text and insert the new one\n if (text !== '' && text !== Editor.string(editor, linkPath)) {\n const linkNodeChildrens = Array.from(Node.children(editor, linkPath, { reverse: true }));\n\n linkNodeChildrens.forEach(([, childPath]) => {\n Transforms.removeNodes(editor, { at: childPath });\n });\n\n Transforms.insertNodes(editor, [{ type: 'text', text }], { at: linkPath.concat(0) });\n }\n }\n};\n\nconst StyledLink = styled(Box)`\n text-decoration: none;\n`;\n\nconst RemoveButton = styled(Button)<{ $visible: boolean }>`\n visibility: ${(props) => (props.$visible ? 'visible' : 'hidden')};\n`;\n\ninterface LinkContentProps extends RenderElementProps {\n link: Block<'link'>;\n}\n\nconst LinkContent = React.forwardRef<HTMLAnchorElement, LinkContentProps>(\n ({ link, children, attributes }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const { editor } = useBlocksEditorContext('Link');\n const path = ReactEditor.findPath(editor, link);\n const [popoverOpen, setPopoverOpen] = React.useState(\n editor.lastInsertedLinkPath ? Path.equals(path, editor.lastInsertedLinkPath) : false\n );\n const elementText = link.children.map((child) => child.text).join('');\n const [linkText, setLinkText] = React.useState(elementText);\n const [linkUrl, setLinkUrl] = React.useState(link.url);\n const [linkRel, setLinRel] = React.useState(link.rel);\n const [linkTarget, setLinkTarget] = React.useState(link.target);\n const linkInputRef = React.useRef<HTMLInputElement>(null);\n const isLastInsertedLink = editor.lastInsertedLinkPath\n ? !Path.equals(path, editor.lastInsertedLinkPath)\n : true;\n const [isSaveDisabled, setIsSaveDisabled] = React.useState(false);\n\n const onLinkChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setIsSaveDisabled(false);\n setLinkUrl(e.target.value);\n\n try {\n // eslint-disable-next-line no-new\n new URL(\n e.target.value?.startsWith('/') ? `https://strapi.io${e.target.value}` : e.target.value\n );\n } catch {\n setIsSaveDisabled(true);\n }\n };\n\n const onLinkRelChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setIsSaveDisabled(false);\n setLinRel(e.target.value);\n };\n\n const onLinkTargetChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setIsSaveDisabled(false);\n setLinkTarget(e.target.value);\n };\n\n const handleSave: React.FormEventHandler = (e) => {\n e.stopPropagation();\n\n // If the selection is collapsed, we select the parent node because we want all the link to be replaced)\n if (editor.selection && Range.isCollapsed(editor.selection)) {\n const [, parentPath] = Editor.parent(editor, editor.selection.focus?.path);\n Transforms.select(editor, parentPath);\n }\n\n editLink(editor, { url: linkUrl, text: linkText, rel: linkRel, target: linkTarget });\n setPopoverOpen(false);\n editor.lastInsertedLinkPath = null;\n ReactEditor.focus(editor);\n };\n\n const handleClose = () => {\n if (link.url === '') {\n removeLink(editor);\n }\n\n setPopoverOpen(false);\n ReactEditor.focus(editor);\n };\n\n React.useEffect(() => {\n // Focus on the link input element when the popover opens\n if (popoverOpen) linkInputRef.current?.focus();\n }, [popoverOpen]);\n\n const inputNotDirty =\n !linkText ||\n !linkUrl ||\n (link.url &&\n link.url === linkUrl &&\n elementText &&\n elementText === linkText &&\n link.rel === linkRel &&\n link.target === linkTarget);\n\n return (\n <Popover.Root open={popoverOpen}>\n <Popover.Trigger>\n <StyledLink\n {...attributes}\n ref={forwardedRef}\n tag=\"a\"\n href={link.url}\n rel={link.rel}\n target={link.target}\n onClick={() => setPopoverOpen(true)}\n color=\"primary600\"\n >\n {children}\n </StyledLink>\n </Popover.Trigger>\n <Popover.Content onPointerDownOutside={handleClose}>\n <Flex padding={4} direction=\"column\" gap={4}>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.text',\n defaultMessage: 'Text',\n })}\n </Field.Label>\n <Field.Input\n name=\"text\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.text.placeholder',\n defaultMessage: 'Enter link text',\n })}\n value={linkText}\n onChange={(e) => {\n setLinkText(e.target.value);\n }}\n />\n </Flex>\n </Field.Root>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.link',\n defaultMessage: 'Link',\n })}\n </Field.Label>\n <Field.Input\n ref={linkInputRef}\n name=\"url\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.link.placeholder',\n defaultMessage: 'Paste link',\n })}\n value={linkUrl}\n onChange={onLinkChange}\n />\n </Flex>\n </Field.Root>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.link.rel',\n defaultMessage: 'Rel (optional)',\n })}\n </Field.Label>\n <Field.Input\n name=\"rel\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.link.rel.placeholder',\n defaultMessage: 'noopener, nofollow, noreferrer',\n })}\n value={linkRel}\n onChange={onLinkRelChange}\n />\n </Flex>\n </Field.Root>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.link.target',\n defaultMessage: 'Target (optional)',\n })}\n </Field.Label>\n <Field.Input\n name=\"target\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.link.target.placeholder',\n defaultMessage: '_blank, _self, _parent, _top',\n })}\n value={linkTarget}\n onChange={onLinkTargetChange}\n />\n </Flex>\n </Field.Root>\n <Flex justifyContent=\"space-between\" width={{ initial: '100%', medium: '368px' }}>\n <RemoveButton\n variant=\"danger-light\"\n onClick={() => removeLink(editor)}\n $visible={isLastInsertedLink}\n >\n {formatMessage({\n id: 'components.Blocks.popover.remove',\n defaultMessage: 'Remove',\n })}\n </RemoveButton>\n <Flex gap={2}>\n <Button variant=\"tertiary\" onClick={handleClose}>\n {formatMessage({\n id: 'global.cancel',\n defaultMessage: 'Cancel',\n })}\n </Button>\n <Button disabled={Boolean(inputNotDirty) || isSaveDisabled} onClick={handleSave}>\n {formatMessage({\n id: 'global.save',\n defaultMessage: 'Save',\n })}\n </Button>\n </Flex>\n </Flex>\n </Flex>\n </Popover.Content>\n </Popover.Root>\n );\n }\n);\n\nconst Link = React.forwardRef<HTMLAnchorElement, RenderElementProps>((props, forwardedRef) => {\n if (!isLinkNode(props.element)) {\n return null;\n }\n\n // LinkContent uses React hooks that rely on props.element being a link. If the type guard above\n // doesn't pass, those hooks would be called conditionnally, which is not allowed.\n // Hence the need for a separate component.\n return <LinkContent {...props} link={props.element} ref={forwardedRef} />;\n});\n\nconst withLinks = (editor: Editor) => {\n const { isInline, apply, insertText, insertData } = editor;\n\n // Links are inline elements, so we need to override the isInline method for slate\n editor.isInline = (element) => {\n return element.type === 'link' ? true : isInline(element);\n };\n\n // We keep a track of the last inserted link path\n // So we can show the popover on the link component if that link is the last one inserted\n editor.lastInsertedLinkPath = null;\n\n // We intercept the apply method, so everytime we insert a new link, we save its path\n editor.apply = (operation) => {\n if (operation.type === 'insert_node') {\n if (\n !Editor.isEditor(operation.node) &&\n operation.node.type === 'link' &&\n editor.shouldSaveLinkPath\n ) {\n editor.lastInsertedLinkPath = operation.path;\n }\n } else if (operation.type === 'move_node') {\n // We need to update the last inserted link path when link is moved\n // If link is the first word in the paragraph we dont need to update the path\n if (\n Path.hasPrevious(operation.path) &&\n editor.lastInsertedLinkPath &&\n editor.shouldSaveLinkPath\n ) {\n editor.lastInsertedLinkPath = Path.transform(editor.lastInsertedLinkPath, operation);\n }\n }\n\n apply(operation);\n };\n\n editor.insertText = (text) => {\n // When selection is at the end of a link and user types a space, we want to break the link\n if (editor.selection && Range.isCollapsed(editor.selection) && text === ' ') {\n const linksInSelection = Array.from(\n Editor.nodes(editor, {\n at: editor.selection,\n match: (node) => !Editor.isEditor(node) && node.type === 'link',\n })\n );\n\n const selectionIsInLink = editor.selection && linksInSelection.length > 0;\n const selectionIsAtEndOfLink =\n selectionIsInLink &&\n Point.equals(editor.selection.anchor, Editor.end(editor, linksInSelection[0][1]));\n\n if (selectionIsAtEndOfLink) {\n Transforms.insertNodes(\n editor,\n { text: ' ', type: 'text' },\n { at: Path.next(linksInSelection[0][1]), select: true }\n );\n\n return;\n }\n }\n\n insertText(text);\n };\n\n // Add data as a clickable link if its a valid URL\n editor.insertData = (data) => {\n const pastedText = data.getData('text/plain');\n\n if (pastedText) {\n try {\n // eslint-disable-next-line no-new\n new URL(pastedText);\n // Do not show link popup on copy-paste a link, so do not save its path\n editor.shouldSaveLinkPath = false;\n insertLink(editor, { url: pastedText });\n return;\n } catch {\n // continue normal data insertion\n }\n }\n\n insertData(data);\n };\n\n return editor;\n};\n\nconst linkBlocks: Pick<BlocksStore, 'link'> = {\n link: {\n renderElement: (props) => (\n <Link element={props.element} attributes={props.attributes}>\n {props.children}\n </Link>\n ),\n // No handleConvert here, links are created via the link button in the toolbar\n matchNode: (node) => node.type === 'link',\n isInBlocksSelector: false,\n plugin: withLinks,\n isDraggable: () => false,\n },\n};\n\nexport interface LinkEditor extends BaseEditor {\n lastInsertedLinkPath: Path | null;\n shouldSaveLinkPath: boolean;\n}\n\nexport { linkBlocks, insertLink };\n"],"names":["isLinkNode","element","type","removeLink","editor","Transforms","unwrapNodes","match","node","Editor","isEditor","SlateElement","isElement","insertLink","url","selection","linkNodes","Array","from","nodes","at","forEach","path","Range","isCollapsed","link","children","text","rel","target","insertNodes","wrapNodes","split","editLink","linkEntry","above","linkPath","setNodes","string","linkNodeChildrens","Node","reverse","childPath","removeNodes","concat","StyledLink","styled","Box","RemoveButton","Button","props","$visible","LinkContent","React","forwardRef","attributes","forwardedRef","formatMessage","useIntl","useBlocksEditorContext","ReactEditor","findPath","popoverOpen","setPopoverOpen","useState","lastInsertedLinkPath","Path","equals","elementText","map","child","join","linkText","setLinkText","linkUrl","setLinkUrl","linkRel","setLinRel","linkTarget","setLinkTarget","linkInputRef","useRef","isLastInsertedLink","isSaveDisabled","setIsSaveDisabled","onLinkChange","e","value","URL","startsWith","onLinkRelChange","onLinkTargetChange","handleSave","stopPropagation","parentPath","parent","focus","select","handleClose","useEffect","current","inputNotDirty","_jsxs","Popover","Root","open","_jsx","Trigger","ref","tag","href","onClick","color","Content","onPointerDownOutside","Flex","padding","direction","gap","Field","width","initial","medium","alignItems","Label","id","defaultMessage","Input","name","placeholder","onChange","justifyContent","variant","disabled","Boolean","Link","withLinks","isInline","apply","insertText","insertData","operation","shouldSaveLinkPath","hasPrevious","transform","linksInSelection","selectionIsInLink","length","selectionIsAtEndOfLink","Point","anchor","end","next","data","pastedText","getData","linkBlocks","renderElement","matchNode","isInBlocksSelector","plugin","isDraggable"],"mappings":"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"}
1
+ {"version":3,"file":"Link.js","sources":["../../../../../../../../admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Link.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { Box, Button, Field, Flex, Popover } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\nimport {\n BaseEditor,\n Editor,\n Element,\n Path,\n Point,\n Range,\n Transforms,\n Element as SlateElement,\n Node,\n} from 'slate';\nimport { type RenderElementProps, ReactEditor } from 'slate-react';\nimport { styled } from 'styled-components';\n\nimport { type BlocksStore, useBlocksEditorContext } from '../BlocksEditor';\nimport { type Block } from '../utils/types';\n\nimport type { Schema } from '@strapi/types';\n\nconst isLinkNode = (element: Element): element is Schema.Attribute.LinkInlineNode => {\n return element.type === 'link';\n};\n\nconst ALLOWED_LINK_PROTOCOLS = new Set(['http:', 'https:', 'ftp:', 'mailto:', 'tel:']);\n\nconst isValidLink = (link: string) => {\n try {\n const url = new URL(link.startsWith('/') ? `https://strapi.io${link}` : link);\n\n return ALLOWED_LINK_PROTOCOLS.has(url.protocol);\n } catch {\n return false;\n }\n};\n\nconst isValidAbsoluteLink = (link: string) => {\n try {\n return ALLOWED_LINK_PROTOCOLS.has(new URL(link).protocol);\n } catch {\n return false;\n }\n};\n\nconst removeLink = (editor: Editor) => {\n Transforms.unwrapNodes(editor, {\n match: (node) => !Editor.isEditor(node) && SlateElement.isElement(node) && node.type === 'link',\n });\n};\n\nconst insertLink = (editor: Editor, { url }: { url: string }) => {\n if (editor.selection) {\n // We want to remove all link on the selection\n const linkNodes = Array.from(\n Editor.nodes(editor, {\n at: editor.selection,\n match: (node) => !Editor.isEditor(node) && node.type === 'link',\n })\n );\n\n linkNodes.forEach(([, path]) => {\n Transforms.unwrapNodes(editor, { at: path });\n });\n\n if (Range.isCollapsed(editor.selection)) {\n const link: Block<'link'> = {\n type: 'link',\n url: url ?? '',\n children: [{ type: 'text', text: url }],\n rel: '',\n target: '',\n };\n\n Transforms.insertNodes(editor, link);\n } else {\n Transforms.wrapNodes(editor, { type: 'link', url: url ?? '' } as Block<'link'>, {\n split: true,\n });\n }\n }\n};\n\nconst editLink = (\n editor: Editor,\n link: { url: string; text: string; rel: string; target: string }\n) => {\n const { url, text, rel, target } = link;\n\n if (!editor.selection) {\n return;\n }\n\n const linkEntry = Editor.above(editor, {\n match: (node) => !Editor.isEditor(node) && node.type === 'link',\n });\n\n if (linkEntry) {\n const [, linkPath] = linkEntry;\n Transforms.setNodes(editor, { url, rel, target }, { at: linkPath });\n\n // If link text is different, we remove the old text and insert the new one\n if (text !== '' && text !== Editor.string(editor, linkPath)) {\n const linkNodeChildrens = Array.from(Node.children(editor, linkPath, { reverse: true }));\n\n linkNodeChildrens.forEach(([, childPath]) => {\n Transforms.removeNodes(editor, { at: childPath });\n });\n\n Transforms.insertNodes(editor, [{ type: 'text', text }], { at: linkPath.concat(0) });\n }\n }\n};\n\nconst StyledLink = styled(Box)`\n text-decoration: none;\n`;\n\nconst RemoveButton = styled(Button)<{ $visible: boolean }>`\n visibility: ${(props) => (props.$visible ? 'visible' : 'hidden')};\n`;\n\ninterface LinkContentProps extends RenderElementProps {\n link: Block<'link'>;\n}\n\nconst LinkContent = React.forwardRef<HTMLAnchorElement, LinkContentProps>(\n ({ link, children, attributes }, forwardedRef) => {\n const { formatMessage } = useIntl();\n const { editor } = useBlocksEditorContext('Link');\n const path = ReactEditor.findPath(editor, link);\n const [popoverOpen, setPopoverOpen] = React.useState(\n editor.lastInsertedLinkPath ? Path.equals(path, editor.lastInsertedLinkPath) : false\n );\n const elementText = link.children.map((child) => child.text).join('');\n const [linkText, setLinkText] = React.useState(elementText);\n const [linkUrl, setLinkUrl] = React.useState(link.url);\n const [linkRel, setLinRel] = React.useState(link.rel);\n const [linkTarget, setLinkTarget] = React.useState(link.target);\n const linkInputRef = React.useRef<HTMLInputElement>(null);\n const isLastInsertedLink = editor.lastInsertedLinkPath\n ? !Path.equals(path, editor.lastInsertedLinkPath)\n : true;\n const isSaveDisabled = !isValidLink(linkUrl);\n\n const onLinkChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setLinkUrl(e.target.value);\n };\n\n const onLinkRelChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setLinRel(e.target.value);\n };\n\n const onLinkTargetChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n setLinkTarget(e.target.value);\n };\n\n const handleSave: React.FormEventHandler = (e) => {\n e.stopPropagation();\n\n // If the selection is collapsed, we select the parent node because we want all the link to be replaced)\n if (editor.selection && Range.isCollapsed(editor.selection)) {\n const [, parentPath] = Editor.parent(editor, editor.selection.focus?.path);\n Transforms.select(editor, parentPath);\n }\n\n editLink(editor, { url: linkUrl, text: linkText, rel: linkRel, target: linkTarget });\n setPopoverOpen(false);\n editor.lastInsertedLinkPath = null;\n ReactEditor.focus(editor);\n };\n\n const handleClose = () => {\n if (link.url === '') {\n removeLink(editor);\n }\n\n setPopoverOpen(false);\n ReactEditor.focus(editor);\n };\n\n React.useEffect(() => {\n // Focus on the link input element when the popover opens\n if (popoverOpen) linkInputRef.current?.focus();\n }, [popoverOpen]);\n\n const inputNotDirty =\n !linkText ||\n !linkUrl ||\n (link.url &&\n link.url === linkUrl &&\n elementText &&\n elementText === linkText &&\n link.rel === linkRel &&\n link.target === linkTarget);\n\n return (\n <Popover.Root open={popoverOpen}>\n <Popover.Trigger>\n <StyledLink\n {...attributes}\n ref={forwardedRef}\n tag=\"a\"\n href={isValidLink(link.url) ? link.url : undefined}\n rel={link.rel}\n target={link.target}\n onClick={() => setPopoverOpen(true)}\n color=\"primary600\"\n >\n {children}\n </StyledLink>\n </Popover.Trigger>\n <Popover.Content onPointerDownOutside={handleClose}>\n <Flex padding={4} direction=\"column\" gap={4}>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.text',\n defaultMessage: 'Text',\n })}\n </Field.Label>\n <Field.Input\n name=\"text\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.text.placeholder',\n defaultMessage: 'Enter link text',\n })}\n value={linkText}\n onChange={(e) => {\n setLinkText(e.target.value);\n }}\n />\n </Flex>\n </Field.Root>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.link',\n defaultMessage: 'Link',\n })}\n </Field.Label>\n <Field.Input\n ref={linkInputRef}\n name=\"url\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.link.placeholder',\n defaultMessage: 'Paste link',\n })}\n value={linkUrl}\n onChange={onLinkChange}\n />\n </Flex>\n </Field.Root>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.link.rel',\n defaultMessage: 'Rel (optional)',\n })}\n </Field.Label>\n <Field.Input\n name=\"rel\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.link.rel.placeholder',\n defaultMessage: 'noopener, nofollow, noreferrer',\n })}\n value={linkRel}\n onChange={onLinkRelChange}\n />\n </Flex>\n </Field.Root>\n <Field.Root width={{ initial: '100%', medium: '368px' }}>\n <Flex direction=\"column\" gap={1} alignItems=\"stretch\">\n <Field.Label>\n {formatMessage({\n id: 'components.Blocks.popover.link.target',\n defaultMessage: 'Target (optional)',\n })}\n </Field.Label>\n <Field.Input\n name=\"target\"\n placeholder={formatMessage({\n id: 'components.Blocks.popover.link.target.placeholder',\n defaultMessage: '_blank, _self, _parent, _top',\n })}\n value={linkTarget}\n onChange={onLinkTargetChange}\n />\n </Flex>\n </Field.Root>\n <Flex justifyContent=\"space-between\" width={{ initial: '100%', medium: '368px' }}>\n <RemoveButton\n variant=\"danger-light\"\n onClick={() => removeLink(editor)}\n $visible={isLastInsertedLink}\n >\n {formatMessage({\n id: 'components.Blocks.popover.remove',\n defaultMessage: 'Remove',\n })}\n </RemoveButton>\n <Flex gap={2}>\n <Button variant=\"tertiary\" onClick={handleClose}>\n {formatMessage({\n id: 'global.cancel',\n defaultMessage: 'Cancel',\n })}\n </Button>\n <Button disabled={Boolean(inputNotDirty) || isSaveDisabled} onClick={handleSave}>\n {formatMessage({\n id: 'global.save',\n defaultMessage: 'Save',\n })}\n </Button>\n </Flex>\n </Flex>\n </Flex>\n </Popover.Content>\n </Popover.Root>\n );\n }\n);\n\nconst Link = React.forwardRef<HTMLAnchorElement, RenderElementProps>((props, forwardedRef) => {\n if (!isLinkNode(props.element)) {\n return null;\n }\n\n // LinkContent uses React hooks that rely on props.element being a link. If the type guard above\n // doesn't pass, those hooks would be called conditionnally, which is not allowed.\n // Hence the need for a separate component.\n return <LinkContent {...props} link={props.element} ref={forwardedRef} />;\n});\n\nconst withLinks = (editor: Editor) => {\n const { isInline, apply, insertText, insertData } = editor;\n\n // Links are inline elements, so we need to override the isInline method for slate\n editor.isInline = (element) => {\n return element.type === 'link' ? true : isInline(element);\n };\n\n // We keep a track of the last inserted link path\n // So we can show the popover on the link component if that link is the last one inserted\n editor.lastInsertedLinkPath = null;\n\n // We intercept the apply method, so everytime we insert a new link, we save its path\n editor.apply = (operation) => {\n if (operation.type === 'insert_node') {\n if (\n !Editor.isEditor(operation.node) &&\n operation.node.type === 'link' &&\n editor.shouldSaveLinkPath\n ) {\n editor.lastInsertedLinkPath = operation.path;\n }\n } else if (operation.type === 'move_node') {\n // We need to update the last inserted link path when link is moved\n // If link is the first word in the paragraph we dont need to update the path\n if (\n Path.hasPrevious(operation.path) &&\n editor.lastInsertedLinkPath &&\n editor.shouldSaveLinkPath\n ) {\n editor.lastInsertedLinkPath = Path.transform(editor.lastInsertedLinkPath, operation);\n }\n }\n\n apply(operation);\n };\n\n editor.insertText = (text) => {\n // When selection is at the end of a link and user types a space, we want to break the link\n if (editor.selection && Range.isCollapsed(editor.selection) && text === ' ') {\n const linksInSelection = Array.from(\n Editor.nodes(editor, {\n at: editor.selection,\n match: (node) => !Editor.isEditor(node) && node.type === 'link',\n })\n );\n\n const selectionIsInLink = editor.selection && linksInSelection.length > 0;\n const selectionIsAtEndOfLink =\n selectionIsInLink &&\n Point.equals(editor.selection.anchor, Editor.end(editor, linksInSelection[0][1]));\n\n if (selectionIsAtEndOfLink) {\n Transforms.insertNodes(\n editor,\n { text: ' ', type: 'text' },\n { at: Path.next(linksInSelection[0][1]), select: true }\n );\n\n return;\n }\n }\n\n insertText(text);\n };\n\n // Add data as a clickable link if its a valid URL\n editor.insertData = (data) => {\n const pastedText = data.getData('text/plain');\n\n if (pastedText) {\n if (isValidAbsoluteLink(pastedText)) {\n // Do not show link popup on copy-paste a link, so do not save its path\n editor.shouldSaveLinkPath = false;\n insertLink(editor, { url: pastedText });\n return;\n }\n }\n\n insertData(data);\n };\n\n return editor;\n};\n\nconst linkBlocks: Pick<BlocksStore, 'link'> = {\n link: {\n renderElement: (props) => (\n <Link element={props.element} attributes={props.attributes}>\n {props.children}\n </Link>\n ),\n // No handleConvert here, links are created via the link button in the toolbar\n matchNode: (node) => node.type === 'link',\n isInBlocksSelector: false,\n plugin: withLinks,\n isDraggable: () => false,\n },\n};\n\nexport interface LinkEditor extends BaseEditor {\n lastInsertedLinkPath: Path | null;\n shouldSaveLinkPath: boolean;\n}\n\nexport { linkBlocks, insertLink };\n"],"names":["isLinkNode","element","type","ALLOWED_LINK_PROTOCOLS","Set","isValidLink","link","url","URL","startsWith","has","protocol","isValidAbsoluteLink","removeLink","editor","Transforms","unwrapNodes","match","node","Editor","isEditor","SlateElement","isElement","insertLink","selection","linkNodes","Array","from","nodes","at","forEach","path","Range","isCollapsed","children","text","rel","target","insertNodes","wrapNodes","split","editLink","linkEntry","above","linkPath","setNodes","string","linkNodeChildrens","Node","reverse","childPath","removeNodes","concat","StyledLink","styled","Box","RemoveButton","Button","props","$visible","LinkContent","React","forwardRef","attributes","forwardedRef","formatMessage","useIntl","useBlocksEditorContext","ReactEditor","findPath","popoverOpen","setPopoverOpen","useState","lastInsertedLinkPath","Path","equals","elementText","map","child","join","linkText","setLinkText","linkUrl","setLinkUrl","linkRel","setLinRel","linkTarget","setLinkTarget","linkInputRef","useRef","isLastInsertedLink","isSaveDisabled","onLinkChange","e","value","onLinkRelChange","onLinkTargetChange","handleSave","stopPropagation","parentPath","parent","focus","select","handleClose","useEffect","current","inputNotDirty","_jsxs","Popover","Root","open","_jsx","Trigger","ref","tag","href","undefined","onClick","color","Content","onPointerDownOutside","Flex","padding","direction","gap","Field","width","initial","medium","alignItems","Label","id","defaultMessage","Input","name","placeholder","onChange","justifyContent","variant","disabled","Boolean","Link","withLinks","isInline","apply","insertText","insertData","operation","shouldSaveLinkPath","hasPrevious","transform","linksInSelection","selectionIsInLink","length","selectionIsAtEndOfLink","Point","anchor","end","next","data","pastedText","getData","linkBlocks","renderElement","matchNode","isInBlocksSelector","plugin","isDraggable"],"mappings":"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"}