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.
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/dist/admin/ErrorBoundary.d.ts +17 -0
- package/dist/admin/ErrorBoundary.js +62 -0
- package/dist/admin/ErrorBoundary.js.map +1 -0
- package/dist/admin/LiveEditorOverlay.d.ts +12 -0
- package/dist/admin/LiveEditorOverlay.js +160 -0
- package/dist/admin/LiveEditorOverlay.js.map +1 -0
- package/dist/admin/LiveEditorToggle.d.ts +7 -0
- package/dist/admin/LiveEditorToggle.js +84 -0
- package/dist/admin/LiveEditorToggle.js.map +1 -0
- package/dist/admin/PreviewFrame.d.ts +22 -0
- package/dist/admin/PreviewFrame.js +137 -0
- package/dist/admin/PreviewFrame.js.map +1 -0
- package/dist/admin/PreviewToolbar.d.ts +16 -0
- package/dist/admin/PreviewToolbar.js +90 -0
- package/dist/admin/PreviewToolbar.js.map +1 -0
- package/dist/admin/SettingsBanner.d.ts +3 -0
- package/dist/admin/SettingsBanner.js +105 -0
- package/dist/admin/SettingsBanner.js.map +1 -0
- package/dist/admin/ViewportToggle.d.ts +7 -0
- package/dist/admin/ViewportToggle.js +79 -0
- package/dist/admin/ViewportToggle.js.map +1 -0
- package/dist/admin/blocks/AddBlockDrawer.d.ts +9 -0
- package/dist/admin/blocks/AddBlockDrawer.js +16 -0
- package/dist/admin/blocks/AddBlockDrawer.js.map +1 -0
- package/dist/admin/blocks/BlockActionsToolbar.d.ts +15 -0
- package/dist/admin/blocks/BlockActionsToolbar.js +102 -0
- package/dist/admin/blocks/BlockActionsToolbar.js.map +1 -0
- package/dist/admin/blocks/BlockEmptyState.d.ts +6 -0
- package/dist/admin/blocks/BlockEmptyState.js +26 -0
- package/dist/admin/blocks/BlockEmptyState.js.map +1 -0
- package/dist/admin/blocks/BlockHeader.d.ts +7 -0
- package/dist/admin/blocks/BlockHeader.js +32 -0
- package/dist/admin/blocks/BlockHeader.js.map +1 -0
- package/dist/admin/blocks/schema.d.ts +19 -0
- package/dist/admin/blocks/schema.js +80 -0
- package/dist/admin/blocks/schema.js.map +1 -0
- package/dist/admin/blocks/useBlockActions.d.ts +24 -0
- package/dist/admin/blocks/useBlockActions.js +100 -0
- package/dist/admin/blocks/useBlockActions.js.map +1 -0
- package/dist/admin/icons.d.ts +24 -0
- package/dist/admin/icons.js +36 -0
- package/dist/admin/icons.js.map +1 -0
- package/dist/admin/sidebar/BlockSettingsTab.d.ts +10 -0
- package/dist/admin/sidebar/BlockSettingsTab.js +153 -0
- package/dist/admin/sidebar/BlockSettingsTab.js.map +1 -0
- package/dist/admin/sidebar/DocumentFieldsTab.d.ts +8 -0
- package/dist/admin/sidebar/DocumentFieldsTab.js +38 -0
- package/dist/admin/sidebar/DocumentFieldsTab.js.map +1 -0
- package/dist/admin/sidebar/DocumentMetaTab.d.ts +2 -0
- package/dist/admin/sidebar/DocumentMetaTab.js +11 -0
- package/dist/admin/sidebar/DocumentMetaTab.js.map +1 -0
- package/dist/admin/sidebar/DocumentSettingsTab.d.ts +2 -0
- package/dist/admin/sidebar/DocumentSettingsTab.js +48 -0
- package/dist/admin/sidebar/DocumentSettingsTab.js.map +1 -0
- package/dist/admin/sidebar/Sidebar.d.ts +10 -0
- package/dist/admin/sidebar/Sidebar.js +92 -0
- package/dist/admin/sidebar/Sidebar.js.map +1 -0
- package/dist/client.d.ts +34 -0
- package/dist/client.js +30 -0
- package/dist/client.js.map +1 -0
- package/dist/global.d.ts +4 -0
- package/dist/global.js +200 -0
- package/dist/global.js.map +1 -0
- package/dist/hooks/useAddBlockDrawer.d.ts +14 -0
- package/dist/hooks/useAddBlockDrawer.js +26 -0
- package/dist/hooks/useAddBlockDrawer.js.map +1 -0
- package/dist/hooks/useBlockActionMessages.d.ts +8 -0
- package/dist/hooks/useBlockActionMessages.js +107 -0
- package/dist/hooks/useBlockActionMessages.js.map +1 -0
- package/dist/hooks/useDocConfig.d.ts +6 -0
- package/dist/hooks/useDocConfig.js +18 -0
- package/dist/hooks/useDocConfig.js.map +1 -0
- package/dist/hooks/useFocusTrap.d.ts +2 -0
- package/dist/hooks/useFocusTrap.js +84 -0
- package/dist/hooks/useFocusTrap.js.map +1 -0
- package/dist/hooks/useFullscreenOverlay.d.ts +2 -0
- package/dist/hooks/useFullscreenOverlay.js +30 -0
- package/dist/hooks/useFullscreenOverlay.js.map +1 -0
- package/dist/hooks/useIframeResizeObserver.d.ts +2 -0
- package/dist/hooks/useIframeResizeObserver.js +20 -0
- package/dist/hooks/useIframeResizeObserver.js.map +1 -0
- package/dist/hooks/useLatestRef.d.ts +6 -0
- package/dist/hooks/useLatestRef.js +12 -0
- package/dist/hooks/useLatestRef.js.map +1 -0
- package/dist/hooks/useMainWrapperPortal.d.ts +1 -0
- package/dist/hooks/useMainWrapperPortal.js +64 -0
- package/dist/hooks/useMainWrapperPortal.js.map +1 -0
- package/dist/hooks/useOverlayKeyboard.d.ts +6 -0
- package/dist/hooks/useOverlayKeyboard.js +43 -0
- package/dist/hooks/useOverlayKeyboard.js.map +1 -0
- package/dist/hooks/usePreviewBinding.d.ts +28 -0
- package/dist/hooks/usePreviewBinding.js +108 -0
- package/dist/hooks/usePreviewBinding.js.map +1 -0
- package/dist/hooks/usePreviewHandleDrag.d.ts +11 -0
- package/dist/hooks/usePreviewHandleDrag.js +53 -0
- package/dist/hooks/usePreviewHandleDrag.js.map +1 -0
- package/dist/hooks/usePreviewSelectionSync.d.ts +15 -0
- package/dist/hooks/usePreviewSelectionSync.js +80 -0
- package/dist/hooks/usePreviewSelectionSync.js.map +1 -0
- package/dist/hooks/usePreviewSettingsSync.d.ts +17 -0
- package/dist/hooks/usePreviewSettingsSync.js +55 -0
- package/dist/hooks/usePreviewSettingsSync.js.map +1 -0
- package/dist/hooks/useSidebarResize.d.ts +8 -0
- package/dist/hooks/useSidebarResize.js +101 -0
- package/dist/hooks/useSidebarResize.js.map +1 -0
- package/dist/hooks/useViewportState.d.ts +10 -0
- package/dist/hooks/useViewportState.js +44 -0
- package/dist/hooks/useViewportState.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +104 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/constants.d.ts +22 -0
- package/dist/internal/constants.js +38 -0
- package/dist/internal/constants.js.map +1 -0
- package/dist/internal/dom.d.ts +4 -0
- package/dist/internal/dom.js +6 -0
- package/dist/internal/dom.js.map +1 -0
- package/dist/internal/iframe.d.ts +5 -0
- package/dist/internal/iframe.js +12 -0
- package/dist/internal/iframe.js.map +1 -0
- package/dist/internal/limits.d.ts +9 -0
- package/dist/internal/limits.js +11 -0
- package/dist/internal/limits.js.map +1 -0
- package/dist/internal/path.d.ts +5 -0
- package/dist/internal/path.js +12 -0
- package/dist/internal/path.js.map +1 -0
- package/dist/internal/postmessage.d.ts +3 -0
- package/dist/internal/postmessage.js +21 -0
- package/dist/internal/postmessage.js.map +1 -0
- package/dist/internal/storage-keys.d.ts +8 -0
- package/dist/internal/storage-keys.js +9 -0
- package/dist/internal/storage-keys.js.map +1 -0
- package/dist/internal/storage.d.ts +2 -0
- package/dist/internal/storage.js +20 -0
- package/dist/internal/storage.js.map +1 -0
- package/dist/preview/HoverToolbar.d.ts +8 -0
- package/dist/preview/HoverToolbar.js +48 -0
- package/dist/preview/HoverToolbar.js.map +1 -0
- package/dist/preview/HoverToolbarController.d.ts +31 -0
- package/dist/preview/HoverToolbarController.js +160 -0
- package/dist/preview/HoverToolbarController.js.map +1 -0
- package/dist/preview/hover-css.d.ts +11 -0
- package/dist/preview/hover-css.js +94 -0
- package/dist/preview/hover-css.js.map +1 -0
- package/dist/preview/installClickToFocus.d.ts +6 -0
- package/dist/preview/installClickToFocus.js +21 -0
- package/dist/preview/installClickToFocus.js.map +1 -0
- package/dist/preview/installHoverStyles.d.ts +2 -0
- package/dist/preview/installHoverStyles.js +15 -0
- package/dist/preview/installHoverStyles.js.map +1 -0
- package/dist/preview/protocol.d.ts +11 -0
- package/dist/preview/protocol.js +19 -0
- package/dist/preview/protocol.js.map +1 -0
- package/dist/preview/toolbar-position.d.ts +20 -0
- package/dist/preview/toolbar-position.js +22 -0
- package/dist/preview/toolbar-position.js.map +1 -0
- package/dist/providers/BetterEditorConfigProvider.d.ts +14 -0
- package/dist/providers/BetterEditorConfigProvider.js +26 -0
- package/dist/providers/BetterEditorConfigProvider.js.map +1 -0
- package/dist/providers/OverlayProviders.d.ts +8 -0
- package/dist/providers/OverlayProviders.js +22 -0
- package/dist/providers/OverlayProviders.js.map +1 -0
- package/dist/state/useBetterEditorSettings.d.ts +18 -0
- package/dist/state/useBetterEditorSettings.js +65 -0
- package/dist/state/useBetterEditorSettings.js.map +1 -0
- package/dist/state/useEditorHistory.d.ts +16 -0
- package/dist/state/useEditorHistory.js +157 -0
- package/dist/state/useEditorHistory.js.map +1 -0
- package/dist/styles/blocks-tab.css +163 -0
- package/dist/styles/overlay.css +133 -0
- package/dist/styles/preview.css +211 -0
- package/dist/styles/settings-banner.css +73 -0
- package/dist/styles/sidebar.css +88 -0
- package/dist/types.d.ts +41 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +1 -0
- package/dist/version.js +6 -0
- package/dist/version.js.map +1 -0
- package/package.json +117 -0
|
@@ -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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"}
|