payload-better-editor 1.0.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 (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +57 -0
  3. package/dist/admin/ErrorBoundary.d.ts +17 -0
  4. package/dist/admin/ErrorBoundary.js +62 -0
  5. package/dist/admin/ErrorBoundary.js.map +1 -0
  6. package/dist/admin/LiveEditorOverlay.d.ts +12 -0
  7. package/dist/admin/LiveEditorOverlay.js +160 -0
  8. package/dist/admin/LiveEditorOverlay.js.map +1 -0
  9. package/dist/admin/LiveEditorToggle.d.ts +7 -0
  10. package/dist/admin/LiveEditorToggle.js +84 -0
  11. package/dist/admin/LiveEditorToggle.js.map +1 -0
  12. package/dist/admin/PreviewFrame.d.ts +22 -0
  13. package/dist/admin/PreviewFrame.js +137 -0
  14. package/dist/admin/PreviewFrame.js.map +1 -0
  15. package/dist/admin/PreviewToolbar.d.ts +16 -0
  16. package/dist/admin/PreviewToolbar.js +90 -0
  17. package/dist/admin/PreviewToolbar.js.map +1 -0
  18. package/dist/admin/SettingsBanner.d.ts +3 -0
  19. package/dist/admin/SettingsBanner.js +105 -0
  20. package/dist/admin/SettingsBanner.js.map +1 -0
  21. package/dist/admin/ViewportToggle.d.ts +7 -0
  22. package/dist/admin/ViewportToggle.js +79 -0
  23. package/dist/admin/ViewportToggle.js.map +1 -0
  24. package/dist/admin/blocks/AddBlockDrawer.d.ts +9 -0
  25. package/dist/admin/blocks/AddBlockDrawer.js +16 -0
  26. package/dist/admin/blocks/AddBlockDrawer.js.map +1 -0
  27. package/dist/admin/blocks/BlockActionsToolbar.d.ts +15 -0
  28. package/dist/admin/blocks/BlockActionsToolbar.js +102 -0
  29. package/dist/admin/blocks/BlockActionsToolbar.js.map +1 -0
  30. package/dist/admin/blocks/BlockEmptyState.d.ts +6 -0
  31. package/dist/admin/blocks/BlockEmptyState.js +26 -0
  32. package/dist/admin/blocks/BlockEmptyState.js.map +1 -0
  33. package/dist/admin/blocks/BlockHeader.d.ts +7 -0
  34. package/dist/admin/blocks/BlockHeader.js +32 -0
  35. package/dist/admin/blocks/BlockHeader.js.map +1 -0
  36. package/dist/admin/blocks/schema.d.ts +19 -0
  37. package/dist/admin/blocks/schema.js +80 -0
  38. package/dist/admin/blocks/schema.js.map +1 -0
  39. package/dist/admin/blocks/useBlockActions.d.ts +24 -0
  40. package/dist/admin/blocks/useBlockActions.js +100 -0
  41. package/dist/admin/blocks/useBlockActions.js.map +1 -0
  42. package/dist/admin/icons.d.ts +24 -0
  43. package/dist/admin/icons.js +36 -0
  44. package/dist/admin/icons.js.map +1 -0
  45. package/dist/admin/sidebar/BlockSettingsTab.d.ts +10 -0
  46. package/dist/admin/sidebar/BlockSettingsTab.js +153 -0
  47. package/dist/admin/sidebar/BlockSettingsTab.js.map +1 -0
  48. package/dist/admin/sidebar/DocumentFieldsTab.d.ts +8 -0
  49. package/dist/admin/sidebar/DocumentFieldsTab.js +38 -0
  50. package/dist/admin/sidebar/DocumentFieldsTab.js.map +1 -0
  51. package/dist/admin/sidebar/DocumentMetaTab.d.ts +2 -0
  52. package/dist/admin/sidebar/DocumentMetaTab.js +11 -0
  53. package/dist/admin/sidebar/DocumentMetaTab.js.map +1 -0
  54. package/dist/admin/sidebar/DocumentSettingsTab.d.ts +2 -0
  55. package/dist/admin/sidebar/DocumentSettingsTab.js +48 -0
  56. package/dist/admin/sidebar/DocumentSettingsTab.js.map +1 -0
  57. package/dist/admin/sidebar/Sidebar.d.ts +10 -0
  58. package/dist/admin/sidebar/Sidebar.js +92 -0
  59. package/dist/admin/sidebar/Sidebar.js.map +1 -0
  60. package/dist/client.d.ts +34 -0
  61. package/dist/client.js +30 -0
  62. package/dist/client.js.map +1 -0
  63. package/dist/global.d.ts +4 -0
  64. package/dist/global.js +200 -0
  65. package/dist/global.js.map +1 -0
  66. package/dist/hooks/useAddBlockDrawer.d.ts +14 -0
  67. package/dist/hooks/useAddBlockDrawer.js +26 -0
  68. package/dist/hooks/useAddBlockDrawer.js.map +1 -0
  69. package/dist/hooks/useBlockActionMessages.d.ts +8 -0
  70. package/dist/hooks/useBlockActionMessages.js +107 -0
  71. package/dist/hooks/useBlockActionMessages.js.map +1 -0
  72. package/dist/hooks/useDocConfig.d.ts +6 -0
  73. package/dist/hooks/useDocConfig.js +18 -0
  74. package/dist/hooks/useDocConfig.js.map +1 -0
  75. package/dist/hooks/useFocusTrap.d.ts +2 -0
  76. package/dist/hooks/useFocusTrap.js +84 -0
  77. package/dist/hooks/useFocusTrap.js.map +1 -0
  78. package/dist/hooks/useFullscreenOverlay.d.ts +2 -0
  79. package/dist/hooks/useFullscreenOverlay.js +30 -0
  80. package/dist/hooks/useFullscreenOverlay.js.map +1 -0
  81. package/dist/hooks/useIframeResizeObserver.d.ts +2 -0
  82. package/dist/hooks/useIframeResizeObserver.js +20 -0
  83. package/dist/hooks/useIframeResizeObserver.js.map +1 -0
  84. package/dist/hooks/useLatestRef.d.ts +6 -0
  85. package/dist/hooks/useLatestRef.js +12 -0
  86. package/dist/hooks/useLatestRef.js.map +1 -0
  87. package/dist/hooks/useMainWrapperPortal.d.ts +1 -0
  88. package/dist/hooks/useMainWrapperPortal.js +64 -0
  89. package/dist/hooks/useMainWrapperPortal.js.map +1 -0
  90. package/dist/hooks/useOverlayKeyboard.d.ts +6 -0
  91. package/dist/hooks/useOverlayKeyboard.js +43 -0
  92. package/dist/hooks/useOverlayKeyboard.js.map +1 -0
  93. package/dist/hooks/usePreviewBinding.d.ts +28 -0
  94. package/dist/hooks/usePreviewBinding.js +108 -0
  95. package/dist/hooks/usePreviewBinding.js.map +1 -0
  96. package/dist/hooks/usePreviewHandleDrag.d.ts +11 -0
  97. package/dist/hooks/usePreviewHandleDrag.js +53 -0
  98. package/dist/hooks/usePreviewHandleDrag.js.map +1 -0
  99. package/dist/hooks/usePreviewSelectionSync.d.ts +15 -0
  100. package/dist/hooks/usePreviewSelectionSync.js +80 -0
  101. package/dist/hooks/usePreviewSelectionSync.js.map +1 -0
  102. package/dist/hooks/usePreviewSettingsSync.d.ts +17 -0
  103. package/dist/hooks/usePreviewSettingsSync.js +55 -0
  104. package/dist/hooks/usePreviewSettingsSync.js.map +1 -0
  105. package/dist/hooks/useSidebarResize.d.ts +8 -0
  106. package/dist/hooks/useSidebarResize.js +101 -0
  107. package/dist/hooks/useSidebarResize.js.map +1 -0
  108. package/dist/hooks/useViewportState.d.ts +10 -0
  109. package/dist/hooks/useViewportState.js +44 -0
  110. package/dist/hooks/useViewportState.js.map +1 -0
  111. package/dist/index.d.ts +25 -0
  112. package/dist/index.js +104 -0
  113. package/dist/index.js.map +1 -0
  114. package/dist/internal/constants.d.ts +22 -0
  115. package/dist/internal/constants.js +38 -0
  116. package/dist/internal/constants.js.map +1 -0
  117. package/dist/internal/dom.d.ts +4 -0
  118. package/dist/internal/dom.js +6 -0
  119. package/dist/internal/dom.js.map +1 -0
  120. package/dist/internal/iframe.d.ts +5 -0
  121. package/dist/internal/iframe.js +12 -0
  122. package/dist/internal/iframe.js.map +1 -0
  123. package/dist/internal/limits.d.ts +9 -0
  124. package/dist/internal/limits.js +11 -0
  125. package/dist/internal/limits.js.map +1 -0
  126. package/dist/internal/path.d.ts +5 -0
  127. package/dist/internal/path.js +12 -0
  128. package/dist/internal/path.js.map +1 -0
  129. package/dist/internal/postmessage.d.ts +3 -0
  130. package/dist/internal/postmessage.js +21 -0
  131. package/dist/internal/postmessage.js.map +1 -0
  132. package/dist/internal/storage-keys.d.ts +8 -0
  133. package/dist/internal/storage-keys.js +9 -0
  134. package/dist/internal/storage-keys.js.map +1 -0
  135. package/dist/internal/storage.d.ts +2 -0
  136. package/dist/internal/storage.js +20 -0
  137. package/dist/internal/storage.js.map +1 -0
  138. package/dist/preview/HoverToolbar.d.ts +8 -0
  139. package/dist/preview/HoverToolbar.js +48 -0
  140. package/dist/preview/HoverToolbar.js.map +1 -0
  141. package/dist/preview/HoverToolbarController.d.ts +31 -0
  142. package/dist/preview/HoverToolbarController.js +160 -0
  143. package/dist/preview/HoverToolbarController.js.map +1 -0
  144. package/dist/preview/hover-css.d.ts +11 -0
  145. package/dist/preview/hover-css.js +94 -0
  146. package/dist/preview/hover-css.js.map +1 -0
  147. package/dist/preview/installClickToFocus.d.ts +6 -0
  148. package/dist/preview/installClickToFocus.js +21 -0
  149. package/dist/preview/installClickToFocus.js.map +1 -0
  150. package/dist/preview/installHoverStyles.d.ts +2 -0
  151. package/dist/preview/installHoverStyles.js +15 -0
  152. package/dist/preview/installHoverStyles.js.map +1 -0
  153. package/dist/preview/protocol.d.ts +11 -0
  154. package/dist/preview/protocol.js +19 -0
  155. package/dist/preview/protocol.js.map +1 -0
  156. package/dist/preview/toolbar-position.d.ts +20 -0
  157. package/dist/preview/toolbar-position.js +22 -0
  158. package/dist/preview/toolbar-position.js.map +1 -0
  159. package/dist/providers/BetterEditorConfigProvider.d.ts +14 -0
  160. package/dist/providers/BetterEditorConfigProvider.js +26 -0
  161. package/dist/providers/BetterEditorConfigProvider.js.map +1 -0
  162. package/dist/providers/OverlayProviders.d.ts +8 -0
  163. package/dist/providers/OverlayProviders.js +22 -0
  164. package/dist/providers/OverlayProviders.js.map +1 -0
  165. package/dist/state/useBetterEditorSettings.d.ts +18 -0
  166. package/dist/state/useBetterEditorSettings.js +65 -0
  167. package/dist/state/useBetterEditorSettings.js.map +1 -0
  168. package/dist/state/useEditorHistory.d.ts +16 -0
  169. package/dist/state/useEditorHistory.js +157 -0
  170. package/dist/state/useEditorHistory.js.map +1 -0
  171. package/dist/styles/blocks-tab.css +163 -0
  172. package/dist/styles/overlay.css +133 -0
  173. package/dist/styles/preview.css +211 -0
  174. package/dist/styles/settings-banner.css +73 -0
  175. package/dist/styles/sidebar.css +88 -0
  176. package/dist/types.d.ts +41 -0
  177. package/dist/types.js +3 -0
  178. package/dist/types.js.map +1 -0
  179. package/dist/version.d.ts +1 -0
  180. package/dist/version.js +6 -0
  181. package/dist/version.js.map +1 -0
  182. package/package.json +117 -0
@@ -0,0 +1,2 @@
1
+ import { type HoverVars } from './hover-css';
2
+ export declare const installHoverStyles: (doc: Document, vars: HoverVars) => (() => void);
@@ -0,0 +1,15 @@
1
+ import { HOVER_CSS, HOVER_STYLE_ID, clearHoverVars, setHoverVars } from './hover-css';
2
+ export const installHoverStyles = (doc, vars)=>{
3
+ doc.getElementById(HOVER_STYLE_ID)?.remove();
4
+ const style = doc.createElement('style');
5
+ style.id = HOVER_STYLE_ID;
6
+ style.textContent = HOVER_CSS;
7
+ doc.head.appendChild(style);
8
+ setHoverVars(doc, vars);
9
+ return ()=>{
10
+ style.remove();
11
+ clearHoverVars(doc);
12
+ };
13
+ };
14
+
15
+ //# sourceMappingURL=installHoverStyles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/preview/installHoverStyles.ts"],"sourcesContent":["import { HOVER_CSS, HOVER_STYLE_ID, clearHoverVars, setHoverVars, type HoverVars } from './hover-css'\n\nexport const installHoverStyles = (doc: Document, vars: HoverVars): (() => void) => {\n doc.getElementById(HOVER_STYLE_ID)?.remove()\n const style = doc.createElement('style')\n style.id = HOVER_STYLE_ID\n style.textContent = HOVER_CSS\n doc.head.appendChild(style)\n setHoverVars(doc, vars)\n return () => {\n style.remove()\n clearHoverVars(doc)\n }\n}\n"],"names":["HOVER_CSS","HOVER_STYLE_ID","clearHoverVars","setHoverVars","installHoverStyles","doc","vars","getElementById","remove","style","createElement","id","textContent","head","appendChild"],"mappings":"AAAA,SAASA,SAAS,EAAEC,cAAc,EAAEC,cAAc,EAAEC,YAAY,QAAwB,cAAa;AAErG,OAAO,MAAMC,qBAAqB,CAACC,KAAeC;IAChDD,IAAIE,cAAc,CAACN,iBAAiBO;IACpC,MAAMC,QAAQJ,IAAIK,aAAa,CAAC;IAChCD,MAAME,EAAE,GAAGV;IACXQ,MAAMG,WAAW,GAAGZ;IACpBK,IAAIQ,IAAI,CAACC,WAAW,CAACL;IACrBN,aAAaE,KAAKC;IAClB,OAAO;QACLG,MAAMD,MAAM;QACZN,eAAeG;IACjB;AACF,EAAC"}
@@ -0,0 +1,11 @@
1
+ export type FocusBlockMessage = {
2
+ type: 'focus-block';
3
+ id: string;
4
+ };
5
+ export type BlockActionMessage = {
6
+ type: 'block-action';
7
+ id: string;
8
+ action: 'move-up' | 'move-down' | 'duplicate' | 'add' | 'delete';
9
+ };
10
+ export type ParentInboundMessage = FocusBlockMessage | BlockActionMessage;
11
+ export declare const isParentInboundMessage: (data: unknown) => data is ParentInboundMessage;
@@ -0,0 +1,19 @@
1
+ const BLOCK_ACTIONS = new Set([
2
+ 'move-up',
3
+ 'move-down',
4
+ 'duplicate',
5
+ 'add',
6
+ 'delete'
7
+ ]);
8
+ export const isParentInboundMessage = (data)=>{
9
+ if (!data || typeof data !== 'object') return false;
10
+ const d = data;
11
+ if (typeof d.id !== 'string') return false;
12
+ if (d.type === 'focus-block') return true;
13
+ if (d.type === 'block-action') {
14
+ return typeof d.action === 'string' && BLOCK_ACTIONS.has(d.action);
15
+ }
16
+ return false;
17
+ };
18
+
19
+ //# sourceMappingURL=protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/preview/protocol.ts"],"sourcesContent":["export type FocusBlockMessage = { type: 'focus-block'; id: string }\nexport type BlockActionMessage = {\n type: 'block-action'\n id: string\n action: 'move-up' | 'move-down' | 'duplicate' | 'add' | 'delete'\n}\nexport type ParentInboundMessage = FocusBlockMessage | BlockActionMessage\n\nconst BLOCK_ACTIONS: ReadonlySet<string> = new Set<BlockActionMessage['action']>([\n 'move-up',\n 'move-down',\n 'duplicate',\n 'add',\n 'delete',\n])\n\nexport const isParentInboundMessage = (data: unknown): data is ParentInboundMessage => {\n if (!data || typeof data !== 'object') return false\n const d = data as Record<string, unknown>\n if (typeof d.id !== 'string') return false\n if (d.type === 'focus-block') return true\n if (d.type === 'block-action') {\n return typeof d.action === 'string' && BLOCK_ACTIONS.has(d.action)\n }\n return false\n}\n"],"names":["BLOCK_ACTIONS","Set","isParentInboundMessage","data","d","id","type","action","has"],"mappings":"AAQA,MAAMA,gBAAqC,IAAIC,IAAkC;IAC/E;IACA;IACA;IACA;IACA;CACD;AAED,OAAO,MAAMC,yBAAyB,CAACC;IACrC,IAAI,CAACA,QAAQ,OAAOA,SAAS,UAAU,OAAO;IAC9C,MAAMC,IAAID;IACV,IAAI,OAAOC,EAAEC,EAAE,KAAK,UAAU,OAAO;IACrC,IAAID,EAAEE,IAAI,KAAK,eAAe,OAAO;IACrC,IAAIF,EAAEE,IAAI,KAAK,gBAAgB;QAC7B,OAAO,OAAOF,EAAEG,MAAM,KAAK,YAAYP,cAAcQ,GAAG,CAACJ,EAAEG,MAAM;IACnE;IACA,OAAO;AACT,EAAC"}
@@ -0,0 +1,20 @@
1
+ import type { HoverToolbarPosition } from '../internal/constants';
2
+ export type ToolbarRect = Pick<DOMRect, 'top' | 'bottom' | 'left' | 'right'>;
3
+ export type ToolbarSize = {
4
+ width: number;
5
+ height: number;
6
+ };
7
+ export type ScrollOffset = {
8
+ scrollX: number;
9
+ scrollY: number;
10
+ };
11
+ export type ToolbarCoords = {
12
+ top: number;
13
+ left: number;
14
+ };
15
+ /**
16
+ * Pure layout math: places a toolbar in one of the 4 corners of a target
17
+ * rect, inset by the outline + a breathing-room gap. Decoupled from the
18
+ * DOM so it stays testable.
19
+ */
20
+ export declare const calculateToolbarPosition: (rect: ToolbarRect, size: ToolbarSize, scroll: ScrollOffset, position: HoverToolbarPosition, outlineWidth: number) => ToolbarCoords;
@@ -0,0 +1,22 @@
1
+ // Mirrors the 1px outline-edge gap in HOVER_CSS so the toolbar stays a
2
+ // consistent visual distance from the outline regardless of outline width.
3
+ const OUTLINE_EDGE_GAP = 1;
4
+ // Visual breathing room between the outline's inner edge and the toolbar.
5
+ const TOOLBAR_BREATHING_ROOM = 3;
6
+ /**
7
+ * Pure layout math: places a toolbar in one of the 4 corners of a target
8
+ * rect, inset by the outline + a breathing-room gap. Decoupled from the
9
+ * DOM so it stays testable.
10
+ */ export const calculateToolbarPosition = (rect, size, scroll, position, outlineWidth)=>{
11
+ const inset = OUTLINE_EDGE_GAP + outlineWidth + TOOLBAR_BREATHING_ROOM;
12
+ const isTop = position.startsWith('top');
13
+ const isRight = position.endsWith('right');
14
+ const top = isTop ? scroll.scrollY + rect.top + inset : scroll.scrollY + rect.bottom - size.height - inset;
15
+ const left = isRight ? scroll.scrollX + rect.right - size.width - inset : scroll.scrollX + rect.left + inset;
16
+ return {
17
+ top,
18
+ left
19
+ };
20
+ };
21
+
22
+ //# sourceMappingURL=toolbar-position.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/preview/toolbar-position.ts"],"sourcesContent":["import type { HoverToolbarPosition } from '../internal/constants'\n\n// Mirrors the 1px outline-edge gap in HOVER_CSS so the toolbar stays a\n// consistent visual distance from the outline regardless of outline width.\nconst OUTLINE_EDGE_GAP = 1\n// Visual breathing room between the outline's inner edge and the toolbar.\nconst TOOLBAR_BREATHING_ROOM = 3\n\nexport type ToolbarRect = Pick<DOMRect, 'top' | 'bottom' | 'left' | 'right'>\nexport type ToolbarSize = { width: number; height: number }\nexport type ScrollOffset = { scrollX: number; scrollY: number }\n\nexport type ToolbarCoords = { top: number; left: number }\n\n/**\n * Pure layout math: places a toolbar in one of the 4 corners of a target\n * rect, inset by the outline + a breathing-room gap. Decoupled from the\n * DOM so it stays testable.\n */\nexport const calculateToolbarPosition = (\n rect: ToolbarRect,\n size: ToolbarSize,\n scroll: ScrollOffset,\n position: HoverToolbarPosition,\n outlineWidth: number,\n): ToolbarCoords => {\n const inset = OUTLINE_EDGE_GAP + outlineWidth + TOOLBAR_BREATHING_ROOM\n const isTop = position.startsWith('top')\n const isRight = position.endsWith('right')\n const top = isTop\n ? scroll.scrollY + rect.top + inset\n : scroll.scrollY + rect.bottom - size.height - inset\n const left = isRight\n ? scroll.scrollX + rect.right - size.width - inset\n : scroll.scrollX + rect.left + inset\n return { top, left }\n}\n"],"names":["OUTLINE_EDGE_GAP","TOOLBAR_BREATHING_ROOM","calculateToolbarPosition","rect","size","scroll","position","outlineWidth","inset","isTop","startsWith","isRight","endsWith","top","scrollY","bottom","height","left","scrollX","right","width"],"mappings":"AAEA,uEAAuE;AACvE,2EAA2E;AAC3E,MAAMA,mBAAmB;AACzB,0EAA0E;AAC1E,MAAMC,yBAAyB;AAQ/B;;;;CAIC,GACD,OAAO,MAAMC,2BAA2B,CACtCC,MACAC,MACAC,QACAC,UACAC;IAEA,MAAMC,QAAQR,mBAAmBO,eAAeN;IAChD,MAAMQ,QAAQH,SAASI,UAAU,CAAC;IAClC,MAAMC,UAAUL,SAASM,QAAQ,CAAC;IAClC,MAAMC,MAAMJ,QACRJ,OAAOS,OAAO,GAAGX,KAAKU,GAAG,GAAGL,QAC5BH,OAAOS,OAAO,GAAGX,KAAKY,MAAM,GAAGX,KAAKY,MAAM,GAAGR;IACjD,MAAMS,OAAON,UACTN,OAAOa,OAAO,GAAGf,KAAKgB,KAAK,GAAGf,KAAKgB,KAAK,GAAGZ,QAC3CH,OAAOa,OAAO,GAAGf,KAAKc,IAAI,GAAGT;IACjC,OAAO;QAAEK;QAAKI;IAAK;AACrB,EAAC"}
@@ -0,0 +1,14 @@
1
+ import React from 'react';
2
+ import { type StorageKeys } from '../internal/storage-keys';
3
+ export type BetterEditorRuntimeConfig = {
4
+ storageKeys: StorageKeys;
5
+ storageNamespace: string;
6
+ adminPortalSelector?: string;
7
+ };
8
+ export declare const useBetterEditorConfig: () => BetterEditorRuntimeConfig;
9
+ export type BetterEditorConfigProviderProps = {
10
+ children: React.ReactNode;
11
+ storageNamespace?: string;
12
+ adminPortalSelector?: string;
13
+ };
14
+ export declare const BetterEditorConfigProvider: React.FC<BetterEditorConfigProviderProps>;
@@ -0,0 +1,26 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React, { createContext, useContext, useMemo } from 'react';
4
+ import { buildStorageKeys, DEFAULT_STORAGE_KEYS, DEFAULT_STORAGE_NAMESPACE } from '../internal/storage-keys';
5
+ const DEFAULT_RUNTIME_CONFIG = {
6
+ storageKeys: DEFAULT_STORAGE_KEYS,
7
+ storageNamespace: DEFAULT_STORAGE_NAMESPACE
8
+ };
9
+ const Ctx = /*#__PURE__*/ createContext(DEFAULT_RUNTIME_CONFIG);
10
+ export const useBetterEditorConfig = ()=>useContext(Ctx);
11
+ export const BetterEditorConfigProvider = ({ children, storageNamespace, adminPortalSelector })=>{
12
+ const value = useMemo(()=>({
13
+ storageKeys: storageNamespace ? buildStorageKeys(storageNamespace) : DEFAULT_STORAGE_KEYS,
14
+ storageNamespace: storageNamespace ?? DEFAULT_STORAGE_NAMESPACE,
15
+ adminPortalSelector
16
+ }), [
17
+ storageNamespace,
18
+ adminPortalSelector
19
+ ]);
20
+ return /*#__PURE__*/ _jsx(Ctx.Provider, {
21
+ value: value,
22
+ children: children
23
+ });
24
+ };
25
+
26
+ //# sourceMappingURL=BetterEditorConfigProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/BetterEditorConfigProvider.tsx"],"sourcesContent":["'use client'\n\nimport React, { createContext, useContext, useMemo } from 'react'\nimport {\n buildStorageKeys,\n DEFAULT_STORAGE_KEYS,\n DEFAULT_STORAGE_NAMESPACE,\n type StorageKeys,\n} from '../internal/storage-keys'\n\nexport type BetterEditorRuntimeConfig = {\n storageKeys: StorageKeys\n storageNamespace: string\n adminPortalSelector?: string\n}\n\nconst DEFAULT_RUNTIME_CONFIG: BetterEditorRuntimeConfig = {\n storageKeys: DEFAULT_STORAGE_KEYS,\n storageNamespace: DEFAULT_STORAGE_NAMESPACE,\n}\n\nconst Ctx = createContext<BetterEditorRuntimeConfig>(DEFAULT_RUNTIME_CONFIG)\n\nexport const useBetterEditorConfig = (): BetterEditorRuntimeConfig => useContext(Ctx)\n\nexport type BetterEditorConfigProviderProps = {\n children: React.ReactNode\n storageNamespace?: string\n adminPortalSelector?: string\n}\n\nexport const BetterEditorConfigProvider: React.FC<BetterEditorConfigProviderProps> = ({\n children,\n storageNamespace,\n adminPortalSelector,\n}) => {\n const value = useMemo<BetterEditorRuntimeConfig>(\n () => ({\n storageKeys: storageNamespace ? buildStorageKeys(storageNamespace) : DEFAULT_STORAGE_KEYS,\n storageNamespace: storageNamespace ?? DEFAULT_STORAGE_NAMESPACE,\n adminPortalSelector,\n }),\n [storageNamespace, adminPortalSelector],\n )\n\n return <Ctx.Provider value={value}>{children}</Ctx.Provider>\n}\n"],"names":["React","createContext","useContext","useMemo","buildStorageKeys","DEFAULT_STORAGE_KEYS","DEFAULT_STORAGE_NAMESPACE","DEFAULT_RUNTIME_CONFIG","storageKeys","storageNamespace","Ctx","useBetterEditorConfig","BetterEditorConfigProvider","children","adminPortalSelector","value","Provider"],"mappings":"AAAA;;AAEA,OAAOA,SAASC,aAAa,EAAEC,UAAU,EAAEC,OAAO,QAAQ,QAAO;AACjE,SACEC,gBAAgB,EAChBC,oBAAoB,EACpBC,yBAAyB,QAEpB,2BAA0B;AAQjC,MAAMC,yBAAoD;IACxDC,aAAaH;IACbI,kBAAkBH;AACpB;AAEA,MAAMI,oBAAMT,cAAyCM;AAErD,OAAO,MAAMI,wBAAwB,IAAiCT,WAAWQ,KAAI;AAQrF,OAAO,MAAME,6BAAwE,CAAC,EACpFC,QAAQ,EACRJ,gBAAgB,EAChBK,mBAAmB,EACpB;IACC,MAAMC,QAAQZ,QACZ,IAAO,CAAA;YACLK,aAAaC,mBAAmBL,iBAAiBK,oBAAoBJ;YACrEI,kBAAkBA,oBAAoBH;YACtCQ;QACF,CAAA,GACA;QAACL;QAAkBK;KAAoB;IAGzC,qBAAO,KAACJ,IAAIM,QAAQ;QAACD,OAAOA;kBAAQF;;AACtC,EAAC"}
@@ -0,0 +1,8 @@
1
+ import React from 'react';
2
+ import { type BetterEditorConfigProviderProps } from './BetterEditorConfigProvider';
3
+ export type OverlayProvidersProps = {
4
+ onClose: () => void;
5
+ onReset?: () => void;
6
+ children: React.ReactNode;
7
+ } & Pick<BetterEditorConfigProviderProps, 'storageNamespace' | 'adminPortalSelector'>;
8
+ export declare const OverlayProviders: React.FC<OverlayProvidersProps>;
@@ -0,0 +1,22 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React from 'react';
4
+ import { OverlayErrorBoundary } from '../admin/ErrorBoundary';
5
+ import { BetterEditorSettingsProvider } from '../state/useBetterEditorSettings';
6
+ import { EditorHistoryProvider } from '../state/useEditorHistory';
7
+ import { BetterEditorConfigProvider } from './BetterEditorConfigProvider';
8
+ export const OverlayProviders = ({ onClose, onReset, children, storageNamespace, adminPortalSelector })=>/*#__PURE__*/ _jsx(OverlayErrorBoundary, {
9
+ onClose: onClose,
10
+ onReset: onReset,
11
+ children: /*#__PURE__*/ _jsx(BetterEditorConfigProvider, {
12
+ storageNamespace: storageNamespace,
13
+ adminPortalSelector: adminPortalSelector,
14
+ children: /*#__PURE__*/ _jsx(BetterEditorSettingsProvider, {
15
+ children: /*#__PURE__*/ _jsx(EditorHistoryProvider, {
16
+ children: children
17
+ })
18
+ })
19
+ })
20
+ });
21
+
22
+ //# sourceMappingURL=OverlayProviders.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/providers/OverlayProviders.tsx"],"sourcesContent":["'use client'\n\nimport React from 'react'\nimport { OverlayErrorBoundary } from '../admin/ErrorBoundary'\nimport { BetterEditorSettingsProvider } from '../state/useBetterEditorSettings'\nimport { EditorHistoryProvider } from '../state/useEditorHistory'\nimport {\n BetterEditorConfigProvider,\n type BetterEditorConfigProviderProps,\n} from './BetterEditorConfigProvider'\n\nexport type OverlayProvidersProps = {\n onClose: () => void\n onReset?: () => void\n children: React.ReactNode\n} & Pick<BetterEditorConfigProviderProps, 'storageNamespace' | 'adminPortalSelector'>\n\nexport const OverlayProviders: React.FC<OverlayProvidersProps> = ({\n onClose,\n onReset,\n children,\n storageNamespace,\n adminPortalSelector,\n}) => (\n <OverlayErrorBoundary onClose={onClose} onReset={onReset}>\n <BetterEditorConfigProvider\n storageNamespace={storageNamespace}\n adminPortalSelector={adminPortalSelector}\n >\n <BetterEditorSettingsProvider>\n <EditorHistoryProvider>{children}</EditorHistoryProvider>\n </BetterEditorSettingsProvider>\n </BetterEditorConfigProvider>\n </OverlayErrorBoundary>\n)\n"],"names":["React","OverlayErrorBoundary","BetterEditorSettingsProvider","EditorHistoryProvider","BetterEditorConfigProvider","OverlayProviders","onClose","onReset","children","storageNamespace","adminPortalSelector"],"mappings":"AAAA;;AAEA,OAAOA,WAAW,QAAO;AACzB,SAASC,oBAAoB,QAAQ,yBAAwB;AAC7D,SAASC,4BAA4B,QAAQ,mCAAkC;AAC/E,SAASC,qBAAqB,QAAQ,4BAA2B;AACjE,SACEC,0BAA0B,QAErB,+BAA8B;AAQrC,OAAO,MAAMC,mBAAoD,CAAC,EAChEC,OAAO,EACPC,OAAO,EACPC,QAAQ,EACRC,gBAAgB,EAChBC,mBAAmB,EACpB,iBACC,KAACT;QAAqBK,SAASA;QAASC,SAASA;kBAC/C,cAAA,KAACH;YACCK,kBAAkBA;YAClBC,qBAAqBA;sBAErB,cAAA,KAACR;0BACC,cAAA,KAACC;8BAAuBK;;;;OAI/B"}
@@ -0,0 +1,18 @@
1
+ import React from 'react';
2
+ import { type HoverToolbarPosition, type SidebarPosition } from '../internal/constants';
3
+ export type { HoverToolbarPosition };
4
+ export type BetterEditorSettings = {
5
+ sidebarPosition: SidebarPosition;
6
+ forceFullWidthFields: boolean;
7
+ tabletWidth: number;
8
+ mobileWidth: number;
9
+ hoverColorTopLevel: string;
10
+ hoverColorNested: string;
11
+ hoverOutlineWidth: number;
12
+ showHoverToolbar: boolean;
13
+ hoverToolbarPosition: HoverToolbarPosition;
14
+ };
15
+ export declare const useBetterEditorSettings: () => BetterEditorSettings;
16
+ export declare const BetterEditorSettingsProvider: React.FC<{
17
+ children: React.ReactNode;
18
+ }>;
@@ -0,0 +1,65 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
4
+ import { BETTER_EDITOR_SETTINGS_SLUG } from '../global';
5
+ import { DEFAULT_BETTER_EDITOR_SETTINGS, HOVER_TOOLBAR_POSITIONS, SIDEBAR_POSITIONS } from '../internal/constants';
6
+ const DEFAULTS = {
7
+ ...DEFAULT_BETTER_EDITOR_SETTINGS
8
+ };
9
+ const Ctx = /*#__PURE__*/ createContext(DEFAULTS);
10
+ export const useBetterEditorSettings = ()=>useContext(Ctx);
11
+ const pick = (value, isValid, fallback)=>isValid(value) ? value : fallback;
12
+ const isOneOf = (allowed)=>(v)=>typeof v === 'string' && allowed.includes(v);
13
+ const isBool = (v)=>typeof v === 'boolean';
14
+ const isFiniteNumber = (v)=>typeof v === 'number' && Number.isFinite(v);
15
+ const isNonEmptyString = (v)=>typeof v === 'string' && v.length > 0;
16
+ const normalizeSettings = (raw)=>{
17
+ if (!raw || typeof raw !== 'object') return DEFAULTS;
18
+ const d = raw;
19
+ return {
20
+ sidebarPosition: pick(d.sidebarPosition, isOneOf(SIDEBAR_POSITIONS), DEFAULTS.sidebarPosition),
21
+ forceFullWidthFields: pick(d.forceFullWidthFields, isBool, DEFAULTS.forceFullWidthFields),
22
+ tabletWidth: pick(d.tabletWidth, isFiniteNumber, DEFAULTS.tabletWidth),
23
+ mobileWidth: pick(d.mobileWidth, isFiniteNumber, DEFAULTS.mobileWidth),
24
+ hoverColorTopLevel: pick(d.hoverColorTopLevel, isNonEmptyString, DEFAULTS.hoverColorTopLevel),
25
+ hoverColorNested: pick(d.hoverColorNested, isNonEmptyString, DEFAULTS.hoverColorNested),
26
+ hoverOutlineWidth: pick(d.hoverOutlineWidth, isFiniteNumber, DEFAULTS.hoverOutlineWidth),
27
+ showHoverToolbar: pick(d.showHoverToolbar, isBool, DEFAULTS.showHoverToolbar),
28
+ hoverToolbarPosition: pick(d.hoverToolbarPosition, isOneOf(HOVER_TOOLBAR_POSITIONS), DEFAULTS.hoverToolbarPosition)
29
+ };
30
+ };
31
+ export const BetterEditorSettingsProvider = ({ children })=>{
32
+ const [settings, setSettings] = useState(DEFAULTS);
33
+ useEffect(()=>{
34
+ const controller = new AbortController();
35
+ const isDev = process.env.NODE_ENV !== 'production';
36
+ fetch(`/api/globals/${BETTER_EDITOR_SETTINGS_SLUG}?depth=0`, {
37
+ credentials: 'include',
38
+ signal: controller.signal
39
+ }).then((r)=>{
40
+ if (r.ok) return r.json();
41
+ if (isDev) {
42
+ console.warn(`[better-editor] settings fetch returned HTTP ${r.status} — falling back to defaults`);
43
+ }
44
+ return null;
45
+ }).then((data)=>{
46
+ if (data != null) setSettings(normalizeSettings(data));
47
+ }).catch((err)=>{
48
+ // AbortError on unmount is expected and silent.
49
+ if (err instanceof DOMException && err.name === 'AbortError') return;
50
+ if (isDev) {
51
+ console.warn('[better-editor] settings fetch failed — falling back to defaults:', err);
52
+ }
53
+ });
54
+ return ()=>controller.abort();
55
+ }, []);
56
+ const value = useMemo(()=>settings, [
57
+ settings
58
+ ]);
59
+ return /*#__PURE__*/ _jsx(Ctx.Provider, {
60
+ value: value,
61
+ children: children
62
+ });
63
+ };
64
+
65
+ //# sourceMappingURL=useBetterEditorSettings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/state/useBetterEditorSettings.tsx"],"sourcesContent":["'use client'\n\nimport React, { createContext, useContext, useEffect, useMemo, useState } from 'react'\nimport { BETTER_EDITOR_SETTINGS_SLUG } from '../global'\nimport {\n DEFAULT_BETTER_EDITOR_SETTINGS,\n HOVER_TOOLBAR_POSITIONS,\n SIDEBAR_POSITIONS,\n type HoverToolbarPosition,\n type SidebarPosition,\n} from '../internal/constants'\n\nexport type { HoverToolbarPosition }\n\nexport type BetterEditorSettings = {\n sidebarPosition: SidebarPosition\n forceFullWidthFields: boolean\n tabletWidth: number\n mobileWidth: number\n hoverColorTopLevel: string\n hoverColorNested: string\n hoverOutlineWidth: number\n showHoverToolbar: boolean\n hoverToolbarPosition: HoverToolbarPosition\n}\n\nconst DEFAULTS: BetterEditorSettings = { ...DEFAULT_BETTER_EDITOR_SETTINGS }\n\nconst Ctx = createContext<BetterEditorSettings>(DEFAULTS)\n\nexport const useBetterEditorSettings = (): BetterEditorSettings => useContext(Ctx)\n\nconst pick = <T,>(value: unknown, isValid: (v: unknown) => v is T, fallback: T): T =>\n isValid(value) ? value : fallback\n\nconst isOneOf = <T extends string>(allowed: readonly T[]) =>\n (v: unknown): v is T => typeof v === 'string' && (allowed as readonly string[]).includes(v)\n\nconst isBool = (v: unknown): v is boolean => typeof v === 'boolean'\nconst isFiniteNumber = (v: unknown): v is number => typeof v === 'number' && Number.isFinite(v)\nconst isNonEmptyString = (v: unknown): v is string => typeof v === 'string' && v.length > 0\n\nconst normalizeSettings = (raw: unknown): BetterEditorSettings => {\n if (!raw || typeof raw !== 'object') return DEFAULTS\n const d = raw as Partial<BetterEditorSettings>\n return {\n sidebarPosition: pick(d.sidebarPosition, isOneOf(SIDEBAR_POSITIONS), DEFAULTS.sidebarPosition),\n forceFullWidthFields: pick(d.forceFullWidthFields, isBool, DEFAULTS.forceFullWidthFields),\n tabletWidth: pick(d.tabletWidth, isFiniteNumber, DEFAULTS.tabletWidth),\n mobileWidth: pick(d.mobileWidth, isFiniteNumber, DEFAULTS.mobileWidth),\n hoverColorTopLevel: pick(d.hoverColorTopLevel, isNonEmptyString, DEFAULTS.hoverColorTopLevel),\n hoverColorNested: pick(d.hoverColorNested, isNonEmptyString, DEFAULTS.hoverColorNested),\n hoverOutlineWidth: pick(d.hoverOutlineWidth, isFiniteNumber, DEFAULTS.hoverOutlineWidth),\n showHoverToolbar: pick(d.showHoverToolbar, isBool, DEFAULTS.showHoverToolbar),\n hoverToolbarPosition: pick(\n d.hoverToolbarPosition,\n isOneOf(HOVER_TOOLBAR_POSITIONS),\n DEFAULTS.hoverToolbarPosition,\n ),\n }\n}\n\nexport const BetterEditorSettingsProvider: React.FC<{ children: React.ReactNode }> = ({\n children,\n}) => {\n const [settings, setSettings] = useState<BetterEditorSettings>(DEFAULTS)\n\n useEffect(() => {\n const controller = new AbortController()\n const isDev = process.env.NODE_ENV !== 'production'\n\n fetch(`/api/globals/${BETTER_EDITOR_SETTINGS_SLUG}?depth=0`, {\n credentials: 'include',\n signal: controller.signal,\n })\n .then((r) => {\n if (r.ok) return r.json()\n if (isDev) {\n console.warn(\n `[better-editor] settings fetch returned HTTP ${r.status} — falling back to defaults`,\n )\n }\n return null\n })\n .then((data: unknown) => {\n if (data != null) setSettings(normalizeSettings(data))\n })\n .catch((err: unknown) => {\n // AbortError on unmount is expected and silent.\n if (err instanceof DOMException && err.name === 'AbortError') return\n if (isDev) {\n console.warn(\n '[better-editor] settings fetch failed — falling back to defaults:',\n err,\n )\n }\n })\n\n return () => controller.abort()\n }, [])\n\n const value = useMemo(() => settings, [settings])\n\n return <Ctx.Provider value={value}>{children}</Ctx.Provider>\n}\n"],"names":["React","createContext","useContext","useEffect","useMemo","useState","BETTER_EDITOR_SETTINGS_SLUG","DEFAULT_BETTER_EDITOR_SETTINGS","HOVER_TOOLBAR_POSITIONS","SIDEBAR_POSITIONS","DEFAULTS","Ctx","useBetterEditorSettings","pick","value","isValid","fallback","isOneOf","allowed","v","includes","isBool","isFiniteNumber","Number","isFinite","isNonEmptyString","length","normalizeSettings","raw","d","sidebarPosition","forceFullWidthFields","tabletWidth","mobileWidth","hoverColorTopLevel","hoverColorNested","hoverOutlineWidth","showHoverToolbar","hoverToolbarPosition","BetterEditorSettingsProvider","children","settings","setSettings","controller","AbortController","isDev","process","env","NODE_ENV","fetch","credentials","signal","then","r","ok","json","console","warn","status","data","catch","err","DOMException","name","abort","Provider"],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ type HistoryContextValue = {
3
+ pushSnapshot: () => void;
4
+ /** Push a snapshot, run the mutation, mark the form modified. */
5
+ commit: (mutation: () => void) => void;
6
+ undo: () => void;
7
+ redo: () => void;
8
+ canUndo: boolean;
9
+ canRedo: boolean;
10
+ mutationToken: number;
11
+ };
12
+ export declare const useEditorHistory: () => HistoryContextValue;
13
+ export declare const EditorHistoryProvider: React.FC<{
14
+ children: React.ReactNode;
15
+ }>;
16
+ export {};
@@ -0,0 +1,157 @@
1
+ 'use client';
2
+ import { jsx as _jsx } from "react/jsx-runtime";
3
+ import React, { createContext, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react';
4
+ import { useAllFormFields, useForm } from '@payloadcms/ui';
5
+ const noop = ()=>{};
6
+ const DEFAULT_VALUE = {
7
+ pushSnapshot: noop,
8
+ commit: (mutation)=>mutation(),
9
+ undo: noop,
10
+ redo: noop,
11
+ canUndo: false,
12
+ canRedo: false,
13
+ mutationToken: 0
14
+ };
15
+ const Ctx = /*#__PURE__*/ createContext(DEFAULT_VALUE);
16
+ export const useEditorHistory = ()=>useContext(Ctx);
17
+ const MAX_HISTORY = 50;
18
+ const initialState = {
19
+ undo: [],
20
+ redo: []
21
+ };
22
+ const reducer = (state, action)=>{
23
+ switch(action.type){
24
+ case 'push':
25
+ {
26
+ const next = state.undo.length >= MAX_HISTORY ? [
27
+ ...state.undo.slice(-(MAX_HISTORY - 1)),
28
+ action.snapshot
29
+ ] : [
30
+ ...state.undo,
31
+ action.snapshot
32
+ ];
33
+ return {
34
+ undo: next,
35
+ redo: []
36
+ };
37
+ }
38
+ case 'undo':
39
+ {
40
+ if (state.undo.length === 0) return state;
41
+ return {
42
+ undo: state.undo.slice(0, -1),
43
+ redo: [
44
+ ...state.redo,
45
+ action.current
46
+ ]
47
+ };
48
+ }
49
+ case 'redo':
50
+ {
51
+ if (state.redo.length === 0) return state;
52
+ return {
53
+ undo: [
54
+ ...state.undo,
55
+ action.current
56
+ ],
57
+ redo: state.redo.slice(0, -1)
58
+ };
59
+ }
60
+ }
61
+ };
62
+ export const EditorHistoryProvider = ({ children })=>{
63
+ const [fields] = useAllFormFields();
64
+ const fieldsRef = useRef(fields);
65
+ fieldsRef.current = fields;
66
+ const { dispatchFields, setModified } = useForm();
67
+ const [state, dispatch] = useReducer(reducer, initialState);
68
+ const [mutationToken, setMutationToken] = useState(0);
69
+ const bumpMutationToken = useCallback(()=>setMutationToken((n)=>n + 1), []);
70
+ const restoringRef = useRef(false);
71
+ const restoreTimerRef = useRef(null);
72
+ useEffect(()=>()=>{
73
+ if (restoreTimerRef.current !== null) clearTimeout(restoreTimerRef.current);
74
+ }, []);
75
+ const pushSnapshot = useCallback(()=>{
76
+ if (restoringRef.current) return;
77
+ dispatch({
78
+ type: 'push',
79
+ snapshot: fieldsRef.current
80
+ });
81
+ }, []);
82
+ const commit = useCallback((mutation)=>{
83
+ pushSnapshot();
84
+ mutation();
85
+ setModified(true);
86
+ bumpMutationToken();
87
+ }, [
88
+ pushSnapshot,
89
+ setModified,
90
+ bumpMutationToken
91
+ ]);
92
+ const restore = useCallback((direction, target)=>{
93
+ dispatch({
94
+ type: direction,
95
+ current: fieldsRef.current
96
+ });
97
+ restoringRef.current = true;
98
+ dispatchFields({
99
+ type: 'REPLACE_STATE',
100
+ state: target
101
+ });
102
+ setModified(true);
103
+ // Cleared after the React commit so a transient pushSnapshot triggered
104
+ // by the REPLACE_STATE effect cannot poison redo.
105
+ if (restoreTimerRef.current !== null) clearTimeout(restoreTimerRef.current);
106
+ restoreTimerRef.current = setTimeout(()=>{
107
+ restoringRef.current = false;
108
+ restoreTimerRef.current = null;
109
+ }, 0);
110
+ bumpMutationToken();
111
+ }, [
112
+ dispatchFields,
113
+ setModified,
114
+ bumpMutationToken
115
+ ]);
116
+ const undo = useCallback(()=>{
117
+ const stack = state.undo;
118
+ if (stack.length === 0) return;
119
+ restore('undo', stack[stack.length - 1]);
120
+ }, [
121
+ state.undo,
122
+ restore
123
+ ]);
124
+ const redo = useCallback(()=>{
125
+ const stack = state.redo;
126
+ if (stack.length === 0) return;
127
+ restore('redo', stack[stack.length - 1]);
128
+ }, [
129
+ state.redo,
130
+ restore
131
+ ]);
132
+ const canUndo = state.undo.length > 0;
133
+ const canRedo = state.redo.length > 0;
134
+ const value = useMemo(()=>({
135
+ pushSnapshot,
136
+ commit,
137
+ undo,
138
+ redo,
139
+ canUndo,
140
+ canRedo,
141
+ mutationToken
142
+ }), [
143
+ pushSnapshot,
144
+ commit,
145
+ undo,
146
+ redo,
147
+ canUndo,
148
+ canRedo,
149
+ mutationToken
150
+ ]);
151
+ return /*#__PURE__*/ _jsx(Ctx.Provider, {
152
+ value: value,
153
+ children: children
154
+ });
155
+ };
156
+
157
+ //# sourceMappingURL=useEditorHistory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/state/useEditorHistory.tsx"],"sourcesContent":["'use client'\n\nimport React, {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useReducer,\n useRef,\n useState,\n} from 'react'\nimport type { FormState } from 'payload'\nimport { useAllFormFields, useForm } from '@payloadcms/ui'\n\ntype HistoryContextValue = {\n pushSnapshot: () => void\n /** Push a snapshot, run the mutation, mark the form modified. */\n commit: (mutation: () => void) => void\n undo: () => void\n redo: () => void\n canUndo: boolean\n canRedo: boolean\n mutationToken: number\n}\n\nconst noop = (): void => {}\n\nconst DEFAULT_VALUE: HistoryContextValue = {\n pushSnapshot: noop,\n commit: (mutation) => mutation(),\n undo: noop,\n redo: noop,\n canUndo: false,\n canRedo: false,\n mutationToken: 0,\n}\n\nconst Ctx = createContext<HistoryContextValue>(DEFAULT_VALUE)\n\nexport const useEditorHistory = (): HistoryContextValue => useContext(Ctx)\n\nconst MAX_HISTORY = 50\n\ntype HistoryState = {\n undo: FormState[]\n redo: FormState[]\n}\n\ntype HistoryAction =\n | { type: 'push'; snapshot: FormState }\n | { type: 'undo'; current: FormState }\n | { type: 'redo'; current: FormState }\n\nconst initialState: HistoryState = { undo: [], redo: [] }\n\nconst reducer = (state: HistoryState, action: HistoryAction): HistoryState => {\n switch (action.type) {\n case 'push': {\n const next =\n state.undo.length >= MAX_HISTORY\n ? [...state.undo.slice(-(MAX_HISTORY - 1)), action.snapshot]\n : [...state.undo, action.snapshot]\n return { undo: next, redo: [] }\n }\n case 'undo': {\n if (state.undo.length === 0) return state\n return {\n undo: state.undo.slice(0, -1),\n redo: [...state.redo, action.current],\n }\n }\n case 'redo': {\n if (state.redo.length === 0) return state\n return {\n undo: [...state.undo, action.current],\n redo: state.redo.slice(0, -1),\n }\n }\n }\n}\n\nexport const EditorHistoryProvider: React.FC<{ children: React.ReactNode }> = ({\n children,\n}) => {\n const [fields] = useAllFormFields()\n const fieldsRef = useRef<FormState>(fields)\n fieldsRef.current = fields\n\n const { dispatchFields, setModified } = useForm()\n const [state, dispatch] = useReducer(reducer, initialState)\n const [mutationToken, setMutationToken] = useState(0)\n const bumpMutationToken = useCallback(() => setMutationToken((n) => n + 1), [])\n const restoringRef = useRef(false)\n const restoreTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)\n\n useEffect(\n () => () => {\n if (restoreTimerRef.current !== null) clearTimeout(restoreTimerRef.current)\n },\n [],\n )\n\n const pushSnapshot = useCallback(() => {\n if (restoringRef.current) return\n dispatch({ type: 'push', snapshot: fieldsRef.current })\n }, [])\n\n const commit = useCallback(\n (mutation: () => void) => {\n pushSnapshot()\n mutation()\n setModified(true)\n bumpMutationToken()\n },\n [pushSnapshot, setModified, bumpMutationToken],\n )\n\n const restore = useCallback(\n (direction: 'undo' | 'redo', target: FormState) => {\n dispatch({ type: direction, current: fieldsRef.current })\n restoringRef.current = true\n dispatchFields({ type: 'REPLACE_STATE', state: target })\n setModified(true)\n // Cleared after the React commit so a transient pushSnapshot triggered\n // by the REPLACE_STATE effect cannot poison redo.\n if (restoreTimerRef.current !== null) clearTimeout(restoreTimerRef.current)\n restoreTimerRef.current = setTimeout(() => {\n restoringRef.current = false\n restoreTimerRef.current = null\n }, 0)\n bumpMutationToken()\n },\n [dispatchFields, setModified, bumpMutationToken],\n )\n\n const undo = useCallback(() => {\n const stack = state.undo\n if (stack.length === 0) return\n restore('undo', stack[stack.length - 1])\n }, [state.undo, restore])\n\n const redo = useCallback(() => {\n const stack = state.redo\n if (stack.length === 0) return\n restore('redo', stack[stack.length - 1])\n }, [state.redo, restore])\n\n const canUndo = state.undo.length > 0\n const canRedo = state.redo.length > 0\n\n const value = useMemo<HistoryContextValue>(\n () => ({ pushSnapshot, commit, undo, redo, canUndo, canRedo, mutationToken }),\n [pushSnapshot, commit, undo, redo, canUndo, canRedo, mutationToken],\n )\n\n return <Ctx.Provider value={value}>{children}</Ctx.Provider>\n}\n"],"names":["React","createContext","useCallback","useContext","useEffect","useMemo","useReducer","useRef","useState","useAllFormFields","useForm","noop","DEFAULT_VALUE","pushSnapshot","commit","mutation","undo","redo","canUndo","canRedo","mutationToken","Ctx","useEditorHistory","MAX_HISTORY","initialState","reducer","state","action","type","next","length","slice","snapshot","current","EditorHistoryProvider","children","fields","fieldsRef","dispatchFields","setModified","dispatch","setMutationToken","bumpMutationToken","n","restoringRef","restoreTimerRef","clearTimeout","restore","direction","target","setTimeout","stack","value","Provider"],"mappings":"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"}