@payload-onpage/react 0.2.1 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/OnPageClient.d.ts.map +1 -1
- package/dist/OnPageClient.js +9 -5
- package/dist/OnPageClient.js.map +1 -1
- package/dist/annotations.d.ts +1 -1
- package/dist/annotations.d.ts.map +1 -1
- package/dist/context.d.ts +19 -5
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +31 -7
- package/dist/context.js.map +1 -1
- package/dist/dom.d.ts +16 -12
- package/dist/dom.d.ts.map +1 -1
- package/dist/dom.js +16 -16
- package/dist/dom.js.map +1 -1
- package/dist/editor/FieldHost.d.ts.map +1 -1
- package/dist/editor/FieldHost.js +18 -11
- package/dist/editor/FieldHost.js.map +1 -1
- package/dist/editor/OnPageEditor.d.ts +15 -8
- package/dist/editor/OnPageEditor.d.ts.map +1 -1
- package/dist/editor/OnPageEditor.js +73 -103
- package/dist/editor/OnPageEditor.js.map +1 -1
- package/dist/editor/editTarget.d.ts +28 -0
- package/dist/editor/editTarget.d.ts.map +1 -0
- package/dist/editor/editTarget.js +20 -0
- package/dist/editor/editTarget.js.map +1 -0
- package/dist/editor/useClientDocs.d.ts +4 -0
- package/dist/editor/useClientDocs.d.ts.map +1 -0
- package/dist/editor/useClientDocs.js +16 -0
- package/dist/editor/useClientDocs.js.map +1 -0
- package/dist/editor/useEditorSession.d.ts +13 -0
- package/dist/editor/useEditorSession.d.ts.map +1 -0
- package/dist/editor/useEditorSession.js +30 -0
- package/dist/editor/useEditorSession.js.map +1 -0
- package/dist/editor/useFlash.d.ts +4 -0
- package/dist/editor/useFlash.d.ts.map +1 -0
- package/dist/editor/useFlash.js +16 -0
- package/dist/editor/useFlash.js.map +1 -0
- package/dist/editor/useGhosts.d.ts +5 -7
- package/dist/editor/useGhosts.d.ts.map +1 -1
- package/dist/editor/useGhosts.js.map +1 -1
- package/dist/editor/usePageEvents.d.ts.map +1 -1
- package/dist/editor/usePageEvents.js +16 -16
- package/dist/editor/usePageEvents.js.map +1 -1
- package/dist/editor-kit.d.ts +10 -6
- package/dist/editor-kit.d.ts.map +1 -1
- package/dist/editor-kit.js +8 -5
- package/dist/editor-kit.js.map +1 -1
- package/dist/editors/CheckboxEditor.d.ts +6 -1
- package/dist/editors/CheckboxEditor.d.ts.map +1 -1
- package/dist/editors/CheckboxEditor.js +6 -3
- package/dist/editors/CheckboxEditor.js.map +1 -1
- package/dist/editors/ColorEditor.d.ts +3 -1
- package/dist/editors/ColorEditor.d.ts.map +1 -1
- package/dist/editors/ColorEditor.js +9 -15
- package/dist/editors/ColorEditor.js.map +1 -1
- package/dist/editors/DateEditor.d.ts +3 -1
- package/dist/editors/DateEditor.d.ts.map +1 -1
- package/dist/editors/DateEditor.js +10 -12
- package/dist/editors/DateEditor.js.map +1 -1
- package/dist/editors/InlineText.d.ts +2 -2
- package/dist/editors/InlineText.d.ts.map +1 -1
- package/dist/editors/InlineText.js +2 -3
- package/dist/editors/InlineText.js.map +1 -1
- package/dist/editors/NumberEditor.d.ts +3 -1
- package/dist/editors/NumberEditor.d.ts.map +1 -1
- package/dist/editors/NumberEditor.js +9 -17
- package/dist/editors/NumberEditor.js.map +1 -1
- package/dist/editors/RelationshipEditor.d.ts +7 -1
- package/dist/editors/RelationshipEditor.d.ts.map +1 -1
- package/dist/editors/RelationshipEditor.js +10 -18
- package/dist/editors/RelationshipEditor.js.map +1 -1
- package/dist/editors/SelectEditor.d.ts +4 -1
- package/dist/editors/SelectEditor.d.ts.map +1 -1
- package/dist/editors/SelectEditor.js +8 -13
- package/dist/editors/SelectEditor.js.map +1 -1
- package/dist/editors/UploadEditor.d.ts +7 -1
- package/dist/editors/UploadEditor.d.ts.map +1 -1
- package/dist/editors/UploadEditor.js +5 -5
- package/dist/editors/UploadEditor.js.map +1 -1
- package/dist/editors/index.d.ts +0 -1
- package/dist/editors/index.d.ts.map +1 -1
- package/dist/editors/index.js +56 -16
- package/dist/editors/index.js.map +1 -1
- package/dist/editors/kit.d.ts +39 -0
- package/dist/editors/kit.d.ts.map +1 -0
- package/dist/editors/kit.js +44 -0
- package/dist/editors/kit.js.map +1 -0
- package/dist/editors/useDebouncedSearch.d.ts +10 -6
- package/dist/editors/useDebouncedSearch.d.ts.map +1 -1
- package/dist/editors/useDebouncedSearch.js +11 -7
- package/dist/editors/useDebouncedSearch.js.map +1 -1
- package/dist/geometry.d.ts +49 -0
- package/dist/geometry.d.ts.map +1 -0
- package/dist/geometry.js +48 -0
- package/dist/geometry.js.map +1 -0
- package/dist/hub.d.ts +4 -4
- package/dist/hub.d.ts.map +1 -1
- package/dist/hub.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/layout.d.ts.map +1 -1
- package/dist/layout.js +4 -2
- package/dist/layout.js.map +1 -1
- package/dist/locators.d.ts +0 -2
- package/dist/locators.d.ts.map +1 -1
- package/dist/locators.js +10 -16
- package/dist/locators.js.map +1 -1
- package/dist/messages.d.ts +15 -2
- package/dist/messages.d.ts.map +1 -1
- package/dist/messages.js +5 -0
- package/dist/messages.js.map +1 -1
- package/dist/registry.d.ts +21 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +31 -6
- package/dist/registry.js.map +1 -1
- package/dist/rowOps.d.ts +20 -0
- package/dist/rowOps.d.ts.map +1 -0
- package/dist/rowOps.js +48 -0
- package/dist/rowOps.js.map +1 -0
- package/dist/sanitize.d.ts +2 -0
- package/dist/sanitize.d.ts.map +1 -1
- package/dist/sanitize.js +3 -0
- package/dist/sanitize.js.map +1 -1
- package/dist/settings.d.ts +10 -0
- package/dist/settings.d.ts.map +1 -0
- package/dist/settings.js +30 -0
- package/dist/settings.js.map +1 -0
- package/dist/styles.d.ts +1 -5
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +5 -4
- package/dist/styles.js.map +1 -1
- package/dist/targets.d.ts +1 -1
- package/dist/targets.d.ts.map +1 -1
- package/dist/types.d.ts +71 -46
- package/dist/types.d.ts.map +1 -1
- package/dist/ui/BlockPicker.d.ts.map +1 -1
- package/dist/ui/BlockPicker.js +6 -5
- package/dist/ui/BlockPicker.js.map +1 -1
- package/dist/ui/Dialog.d.ts +0 -5
- package/dist/ui/Dialog.d.ts.map +1 -1
- package/dist/ui/Dialog.js +10 -6
- package/dist/ui/Dialog.js.map +1 -1
- package/dist/ui/Dock.d.ts +1 -6
- package/dist/ui/Dock.d.ts.map +1 -1
- package/dist/ui/Dock.js +46 -28
- package/dist/ui/Dock.js.map +1 -1
- package/dist/ui/Overlay.d.ts.map +1 -1
- package/dist/ui/Overlay.js +39 -37
- package/dist/ui/Overlay.js.map +1 -1
- package/dist/ui/PreviewToolbar.d.ts +3 -3
- package/dist/ui/PreviewToolbar.d.ts.map +1 -1
- package/dist/ui/PreviewToolbar.js +4 -6
- package/dist/ui/PreviewToolbar.js.map +1 -1
- package/dist/ui/SettingsPanel.d.ts +0 -9
- package/dist/ui/SettingsPanel.d.ts.map +1 -1
- package/dist/ui/SettingsPanel.js +36 -41
- package/dist/ui/SettingsPanel.js.map +1 -1
- package/dist/ui/ToolbarButton.d.ts +12 -0
- package/dist/ui/ToolbarButton.d.ts.map +1 -0
- package/dist/ui/ToolbarButton.js +7 -0
- package/dist/ui/ToolbarButton.js.map +1 -0
- package/dist/useEvent.d.ts +1 -1
- package/dist/useEvent.d.ts.map +1 -1
- package/dist/useEvent.js +3 -1
- package/dist/useEvent.js.map +1 -1
- package/dist/useIsClient.d.ts +5 -0
- package/dist/useIsClient.d.ts.map +1 -0
- package/dist/useIsClient.js +8 -0
- package/dist/useIsClient.js.map +1 -0
- package/package.json +15 -4
- package/src/OnPageClient.tsx +9 -5
- package/src/annotations.ts +1 -1
- package/src/context.tsx +53 -10
- package/src/dom.ts +17 -18
- package/src/editor/FieldHost.tsx +26 -11
- package/src/editor/OnPageEditor.tsx +103 -160
- package/src/editor/editTarget.ts +41 -0
- package/src/editor/useClientDocs.ts +19 -0
- package/src/editor/useEditorSession.ts +36 -0
- package/src/editor/useFlash.ts +18 -0
- package/src/editor/useGhosts.ts +5 -7
- package/src/editor/usePageEvents.ts +13 -14
- package/src/editor-kit.ts +10 -6
- package/src/editors/CheckboxEditor.tsx +11 -12
- package/src/editors/ColorEditor.tsx +15 -35
- package/src/editors/DateEditor.tsx +18 -37
- package/src/editors/InlineText.tsx +4 -5
- package/src/editors/NumberEditor.tsx +15 -36
- package/src/editors/RelationshipEditor.tsx +18 -36
- package/src/editors/SelectEditor.tsx +14 -22
- package/src/editors/UploadEditor.tsx +6 -6
- package/src/editors/index.ts +56 -16
- package/src/editors/kit.tsx +97 -0
- package/src/editors/useDebouncedSearch.ts +18 -10
- package/src/geometry.ts +62 -0
- package/src/hub.ts +5 -5
- package/src/index.ts +5 -2
- package/src/layout.ts +5 -2
- package/src/locators.ts +11 -14
- package/src/messages.ts +26 -5
- package/src/registry.ts +42 -8
- package/src/rowOps.ts +64 -0
- package/src/sanitize.ts +6 -0
- package/src/settings.ts +49 -0
- package/src/styles.ts +5 -4
- package/src/targets.ts +1 -1
- package/src/types.ts +78 -45
- package/src/ui/BlockPicker.tsx +6 -7
- package/src/ui/Dialog.tsx +9 -5
- package/src/ui/Dock.tsx +67 -50
- package/src/ui/Overlay.tsx +75 -102
- package/src/ui/PreviewToolbar.tsx +7 -15
- package/src/ui/SettingsPanel.tsx +84 -81
- package/src/ui/ToolbarButton.tsx +36 -0
- package/src/useEvent.ts +4 -2
- package/src/useIsClient.ts +15 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** False during SSR and hydration, true after: for UI that only exists in the browser. */
|
|
2
|
+
export declare const useIsClient: () => boolean;
|
|
3
|
+
/** Adds the editor's stylesheet to the page while mounted. */
|
|
4
|
+
export declare const useEditorStyles: () => void;
|
|
5
|
+
//# sourceMappingURL=useIsClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIsClient.d.ts","sourceRoot":"","sources":["../src/useIsClient.ts"],"names":[],"mappings":"AAKA,0FAA0F;AAC1F,eAAO,MAAM,WAAW,QAAO,OAK5B,CAAA;AAEH,8DAA8D;AAC9D,eAAO,MAAM,eAAe,QAAO,IAA2C,CAAA"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useEffect, useSyncExternalStore } from 'react';
|
|
2
|
+
import { injectStyles } from "./styles.js";
|
|
3
|
+
const noopSubscribe = () => () => { };
|
|
4
|
+
/** False during SSR and hydration, true after: for UI that only exists in the browser. */
|
|
5
|
+
export const useIsClient = () => useSyncExternalStore(noopSubscribe, () => true, () => false);
|
|
6
|
+
/** Adds the editor's stylesheet to the page while mounted. */
|
|
7
|
+
export const useEditorStyles = () => useEffect(() => injectStyles(), []);
|
|
8
|
+
//# sourceMappingURL=useIsClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useIsClient.js","sourceRoot":"","sources":["../src/useIsClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,GAAG,EAAE,GAAE,CAAC,CAAA;AAEpC,0FAA0F;AAC1F,MAAM,CAAC,MAAM,WAAW,GAAG,GAAY,EAAE,CACvC,oBAAoB,CAClB,aAAa,EACb,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACZ,CAAA;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,eAAe,GAAG,GAAS,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,CAAC,YAAY,EAAE,EAAE,EAAE,CAAC,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@payload-onpage/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "payload-onpage React editor: overlay, toolbars, field editors, annotations and client mode.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -15,12 +15,23 @@
|
|
|
15
15
|
"keywords": [
|
|
16
16
|
"payload",
|
|
17
17
|
"payloadcms",
|
|
18
|
+
"payload-cms",
|
|
18
19
|
"payload-plugin",
|
|
19
20
|
"nextjs",
|
|
21
|
+
"next.js",
|
|
22
|
+
"app-router",
|
|
20
23
|
"visual-editing",
|
|
21
|
-
"
|
|
24
|
+
"visual-editor",
|
|
22
25
|
"inline-editing",
|
|
23
|
-
"
|
|
26
|
+
"front-end-editing",
|
|
27
|
+
"live-preview",
|
|
28
|
+
"draft-preview",
|
|
29
|
+
"preview-links",
|
|
30
|
+
"page-builder",
|
|
31
|
+
"wysiwyg",
|
|
32
|
+
"headless-cms",
|
|
33
|
+
"cms",
|
|
34
|
+
"react"
|
|
24
35
|
],
|
|
25
36
|
"exports": {
|
|
26
37
|
".": {
|
|
@@ -61,7 +72,7 @@
|
|
|
61
72
|
"provenance": true
|
|
62
73
|
},
|
|
63
74
|
"dependencies": {
|
|
64
|
-
"@payload-onpage/core": "0.
|
|
75
|
+
"@payload-onpage/core": "0.3.1"
|
|
65
76
|
},
|
|
66
77
|
"peerDependencies": {
|
|
67
78
|
"react": "^19.0.0",
|
package/src/OnPageClient.tsx
CHANGED
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
* invisible markers (turn off with `autoMap={false}`).
|
|
13
13
|
*/
|
|
14
14
|
import { useEvent } from './useEvent.ts'
|
|
15
|
+
import { toRef } from './annotations.ts'
|
|
15
16
|
import { encodeDocument, refKey, type DocRef } from '@payload-onpage/core'
|
|
16
17
|
import { useEffect, useMemo, type ReactNode } from 'react'
|
|
17
18
|
import { editable, editableOff, type Editable } from './annotations.ts'
|
|
18
|
-
import { useOnPageOptional } from './context.tsx'
|
|
19
|
+
import { useOnPageOptional, useSessionSnapshot } from './context.tsx'
|
|
19
20
|
|
|
20
21
|
export type OnPageClientProps<T> = {
|
|
21
22
|
doc: T
|
|
@@ -33,9 +34,9 @@ export function OnPageClient<T extends { id?: string | number } | null | undefin
|
|
|
33
34
|
const ref = useMemo<DocRef | null>(
|
|
34
35
|
() =>
|
|
35
36
|
globalSlug
|
|
36
|
-
? {
|
|
37
|
-
: collection
|
|
38
|
-
? {
|
|
37
|
+
? toRef({ global: globalSlug })
|
|
38
|
+
: collection
|
|
39
|
+
? toRef({ collection, doc: { id } })
|
|
39
40
|
: null,
|
|
40
41
|
[globalSlug, collection, id],
|
|
41
42
|
)
|
|
@@ -51,7 +52,8 @@ export function OnPageClient<T extends { id?: string | number } | null | undefin
|
|
|
51
52
|
})
|
|
52
53
|
useEffect(() => (enabled && ref ? join(ref) : undefined), [enabled, ref, join])
|
|
53
54
|
|
|
54
|
-
const
|
|
55
|
+
const snap = useSessionSnapshot(ctx?.session)
|
|
56
|
+
const state = key ? snap.docs[key] : undefined
|
|
55
57
|
const stateDoc = state?.doc
|
|
56
58
|
const fields = state?.schema?.fields
|
|
57
59
|
const autoMap = props.autoMap !== false
|
|
@@ -63,5 +65,7 @@ export function OnPageClient<T extends { id?: string | number } | null | undefin
|
|
|
63
65
|
() => (enabled && ref ? editable(ref, { enabled: true }) : editableOff),
|
|
64
66
|
[enabled, ref],
|
|
65
67
|
)
|
|
68
|
+
// The session's copy started as this `doc` (same document, edited, held as plain JSON),
|
|
69
|
+
// so it is handed back as the page's own type.
|
|
66
70
|
return <>{render(current as T, e)}</>
|
|
67
71
|
}
|
package/src/annotations.ts
CHANGED
|
@@ -51,7 +51,7 @@ export const editableOff: Editable = {
|
|
|
51
51
|
|
|
52
52
|
export type EditableTarget =
|
|
53
53
|
| DocRef
|
|
54
|
-
| { collection: string; doc: { id?: string | number } | null | undefined }
|
|
54
|
+
| { collection: string; doc: { id?: string | number | undefined } | null | undefined }
|
|
55
55
|
| { global: string }
|
|
56
56
|
|
|
57
57
|
export function toRef(t: EditableTarget): DocRef | null {
|
package/src/context.tsx
CHANGED
|
@@ -1,23 +1,66 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { createContext, useContext, useSyncExternalStore } from 'react'
|
|
3
|
+
import { createContext, useContext, useSyncExternalStore, type ReactNode } from 'react'
|
|
4
|
+
import type { EditorSession, SessionSnapshot } from '@payload-onpage/core'
|
|
4
5
|
import { hub } from './hub.ts'
|
|
5
|
-
import type { OnPageContextValue } from './types.ts'
|
|
6
|
+
import type { OnPageApi, OnPageContextValue, OnPageState } from './types.ts'
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
const ApiContext = createContext<OnPageApi | null>(null)
|
|
9
|
+
const StateContext = createContext<OnPageState | null>(null)
|
|
8
10
|
|
|
9
|
-
/**
|
|
11
|
+
/** Provides the editor to everything it renders (two contexts: the stable API and the changing state). */
|
|
12
|
+
export function OnPageProvider({
|
|
13
|
+
api,
|
|
14
|
+
state,
|
|
15
|
+
children,
|
|
16
|
+
}: {
|
|
17
|
+
api: OnPageApi
|
|
18
|
+
state: OnPageState
|
|
19
|
+
children: ReactNode
|
|
20
|
+
}) {
|
|
21
|
+
return (
|
|
22
|
+
<ApiContext.Provider value={api}>
|
|
23
|
+
<StateContext.Provider value={state}>{children}</StateContext.Provider>
|
|
24
|
+
</ApiContext.Provider>
|
|
25
|
+
)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The editor, for code rendered inside it (field editors, panels): its API and state. */
|
|
10
29
|
export function useOnPage(): OnPageContextValue {
|
|
11
|
-
const
|
|
12
|
-
|
|
13
|
-
|
|
30
|
+
const api = useContext(ApiContext)
|
|
31
|
+
const state = useContext(StateContext)
|
|
32
|
+
if (!api || !state) throw new Error('useOnPage must be used inside <OnPageEditor>')
|
|
33
|
+
return { ...api, ...state }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Only the editor's API (session, actions): re-renders when the editor is reconfigured, not on every edit. */
|
|
37
|
+
export function useOnPageApi(): OnPageApi {
|
|
38
|
+
const api = useContext(ApiContext)
|
|
39
|
+
if (!api) throw new Error('useOnPageApi must be used inside <OnPageEditor>')
|
|
40
|
+
return api
|
|
14
41
|
}
|
|
15
42
|
|
|
16
43
|
const getNull = () => null
|
|
17
44
|
|
|
18
|
-
/**
|
|
19
|
-
|
|
20
|
-
|
|
45
|
+
/**
|
|
46
|
+
* The editor's API from inside it or anywhere on the page; null when no editor
|
|
47
|
+
* is mounted (public pages). Read documents with `useSessionSnapshot(api?.session)`.
|
|
48
|
+
*/
|
|
49
|
+
export function useOnPageOptional(): OnPageApi | null {
|
|
50
|
+
const inside = useContext(ApiContext)
|
|
21
51
|
const outside = useSyncExternalStore(hub.subscribe, hub.get, getNull)
|
|
22
52
|
return inside ?? outside
|
|
23
53
|
}
|
|
54
|
+
|
|
55
|
+
const EMPTY: SessionSnapshot = { docs: {}, canUndo: false, canRedo: false, busy: false }
|
|
56
|
+
const noopSubscribe = () => () => {}
|
|
57
|
+
const getEmpty = () => EMPTY
|
|
58
|
+
|
|
59
|
+
/** A session's documents, re-rendering when they change (an empty snapshot without a session). */
|
|
60
|
+
export function useSessionSnapshot(session: EditorSession | null | undefined): SessionSnapshot {
|
|
61
|
+
return useSyncExternalStore(
|
|
62
|
+
session?.subscribe ?? noopSubscribe,
|
|
63
|
+
session?.getSnapshot ?? getEmpty,
|
|
64
|
+
getEmpty,
|
|
65
|
+
)
|
|
66
|
+
}
|
package/src/dom.ts
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
1
|
/** DOM helpers shared by the editor UI (browser-only, no React). */
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
export const
|
|
5
|
-
/**
|
|
6
|
-
|
|
3
|
+
/** Every DOM attribute the editor sets (annotations, which sites write, are `ATTR`). */
|
|
4
|
+
export const DOM_ATTR = {
|
|
5
|
+
/** Hides a page element while an editor or ghost stands in for it. */
|
|
6
|
+
hidden: 'data-onpage-hidden',
|
|
7
|
+
/** Marks the editor's own UI, which locators and click handling ignore. */
|
|
8
|
+
ui: 'data-onpage-ui',
|
|
9
|
+
/** A page target the editor made keyboard-focusable. */
|
|
10
|
+
focusable: 'data-onpage-focusable',
|
|
11
|
+
/** On <html> while editing. */
|
|
12
|
+
editing: 'data-onpage-editing',
|
|
13
|
+
/** The editor's injected stylesheet. */
|
|
14
|
+
styles: 'data-onpage-styles',
|
|
15
|
+
} as const
|
|
16
|
+
|
|
17
|
+
export const HIDDEN = DOM_ATTR.hidden
|
|
18
|
+
export const UI = DOM_ATTR.ui
|
|
7
19
|
|
|
8
20
|
/** Computed styles copied onto an inline editor so it looks like the element it replaces. */
|
|
9
21
|
export const TYPOGRAPHY = [
|
|
@@ -94,20 +106,7 @@ export function placeCaret(el: HTMLElement, point?: { x: number; y: number }): v
|
|
|
94
106
|
sel.addRange(range)
|
|
95
107
|
}
|
|
96
108
|
|
|
97
|
-
|
|
98
|
-
export function popoverPosition(
|
|
99
|
-
el: Element | null,
|
|
100
|
-
size = { width: 300, height: 320 },
|
|
101
|
-
): { top: number; left: number } {
|
|
102
|
-
const vw = window.innerWidth
|
|
103
|
-
const vh = window.innerHeight
|
|
104
|
-
if (!el) return { top: 80, left: Math.max(8, vw / 2 - size.width / 2) }
|
|
105
|
-
const r = el.getBoundingClientRect()
|
|
106
|
-
const below = r.bottom + 8
|
|
107
|
-
const top = below + size.height < vh ? below : Math.max(8, r.top - 8 - size.height)
|
|
108
|
-
const left = Math.min(Math.max(8, r.left), vw - size.width - 8)
|
|
109
|
-
return { top, left }
|
|
110
|
-
}
|
|
109
|
+
export { popoverPosition } from './geometry.ts'
|
|
111
110
|
|
|
112
111
|
const FOCUSABLE =
|
|
113
112
|
'a[href],button:not([disabled]),input:not([disabled]),select:not([disabled]),textarea:not([disabled]),[tabindex]:not([tabindex="-1"])'
|
package/src/editor/FieldHost.tsx
CHANGED
|
@@ -1,19 +1,34 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
|
-
import { fieldAtPath, getAt } from '@payload-onpage/core'
|
|
3
|
+
import { fieldAtPath, getAt, isReady, type ReadyDocumentState } from '@payload-onpage/core'
|
|
4
4
|
import { Suspense, useCallback } from 'react'
|
|
5
5
|
import { useOnPage } from '../context.tsx'
|
|
6
|
-
import
|
|
6
|
+
import { canEdit } from '../registry.ts'
|
|
7
|
+
import type { EditingState, FieldEditorDef, FieldEditorProps } from '../types.ts'
|
|
7
8
|
|
|
8
9
|
/** Renders the open field editor, if it belongs to this layer. */
|
|
9
10
|
export function FieldHost({ mode }: { mode: 'inline' | 'popover' }) {
|
|
10
|
-
const { editing, editors,
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
|
|
11
|
+
const { editing, editors, snap } = useOnPage()
|
|
12
|
+
if (!editing) return null
|
|
13
|
+
const def = editors[editing.editor]
|
|
14
|
+
const state = snap.docs[editing.key]
|
|
15
|
+
if (!def || def.mode !== mode || !isReady(state)) return null
|
|
16
|
+
return <OpenEditor editing={editing} def={def} state={state} />
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** The editor for one field of a loaded document. */
|
|
20
|
+
function OpenEditor({
|
|
21
|
+
editing,
|
|
22
|
+
def,
|
|
23
|
+
state,
|
|
24
|
+
}: {
|
|
25
|
+
editing: EditingState
|
|
26
|
+
def: FieldEditorDef
|
|
27
|
+
state: ReadyDocumentState
|
|
28
|
+
}) {
|
|
29
|
+
const { session, targets, setEditing, addGhost, isLive, t } = useOnPage()
|
|
30
|
+
const { key, path, el: clicked } = editing
|
|
15
31
|
const live = isLive(key)
|
|
16
|
-
const clicked = editing?.el
|
|
17
32
|
|
|
18
33
|
const element = useCallback(
|
|
19
34
|
() => (clicked?.isConnected ? clicked : (targets.find(key, path)?.el ?? null)),
|
|
@@ -39,10 +54,10 @@ export function FieldHost({ mode }: { mode: 'inline' | 'popover' }) {
|
|
|
39
54
|
[addGhost, key, path],
|
|
40
55
|
)
|
|
41
56
|
|
|
42
|
-
if (!editing || !def || def.mode !== mode || !state?.schema || !state.doc) return null
|
|
43
57
|
const field = fieldAtPath(state.schema.fields, state.doc, path)?.field
|
|
44
|
-
if (!field) return null
|
|
58
|
+
if (!field || !canEdit(def, field)) return null
|
|
45
59
|
const Editor = def.component
|
|
60
|
+
const raw = getAt(state.doc, path)
|
|
46
61
|
// Editors may be lazy (the rich-text editor is): render nothing until they've loaded.
|
|
47
62
|
return (
|
|
48
63
|
<Suspense fallback={null}>
|
|
@@ -52,7 +67,7 @@ export function FieldHost({ mode }: { mode: 'inline' | 'popover' }) {
|
|
|
52
67
|
path={path}
|
|
53
68
|
field={field}
|
|
54
69
|
element={element}
|
|
55
|
-
value={
|
|
70
|
+
value={def.normalize ? def.normalize(raw, field) : raw}
|
|
56
71
|
commit={commit}
|
|
57
72
|
preview={preview}
|
|
58
73
|
close={close}
|