eddev 2.0.0-beta.115 → 2.0.0-beta.117
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/css/editor-styles.css +4 -0
- package/dist/app/entry/ssr-root-client.js +3 -2
- package/dist/app/entry/ssr-root.js +13 -13
- package/dist/app/lib/blocks/EditableText.d.ts +14 -1
- package/dist/app/lib/blocks/EditableText.js +8 -2
- package/dist/app/lib/blocks/InnerBlocks.d.ts +9 -5
- package/dist/app/lib/blocks/InnerBlocks.js +66 -27
- package/dist/app/lib/blocks/defineBlock.d.ts +3 -0
- package/dist/app/lib/blocks/defineBlock.js +7 -0
- package/dist/app/lib/blocks/editor/EditorHighlights.js +43 -9
- package/dist/app/lib/blocks/editor/EditorSupport.js +13 -7
- package/dist/app/lib/blocks/editor/block-templates.d.ts +6 -0
- package/dist/app/lib/blocks/editor/block-templates.js +64 -0
- package/dist/app/lib/blocks/editor/create-block.d.ts +9 -0
- package/dist/app/lib/blocks/editor/create-block.js +13 -0
- package/dist/app/lib/blocks/editor/editor-config.d.ts +38 -3
- package/dist/app/lib/blocks/editor/editor-config.js +19 -74
- package/dist/app/lib/blocks/editor/installGutenbergHooks.d.ts +3 -0
- package/dist/app/lib/blocks/editor/installGutenbergHooks.js +82 -3
- package/dist/app/lib/blocks/index.d.ts +5 -4
- package/dist/app/lib/blocks/index.js +5 -4
- package/dist/app/lib/blocks/inline-editing.d.ts +8 -0
- package/dist/app/lib/devtools/hooks/useTailwind.d.ts +5 -5
- package/dist/app/lib/routing/components/BrowserRouter.d.ts +1 -0
- package/dist/app/lib/routing/components/BrowserRouter.js +3 -0
- package/dist/app/server/render-ssr-page.js +1 -0
- package/dist/app/server/server-context.d.ts +2 -0
- package/dist/app/server/server-context.js +107 -0
- package/dist/app/utils/query-monitor.d.ts +25 -0
- package/dist/app/utils/query-monitor.js +7 -0
- package/dist/node/cli/cli.js +8 -6
- package/dist/node/cli/version.d.ts +1 -1
- package/dist/node/cli/version.js +1 -1
- package/dist/node/compiler/get-vite-config.d.ts +5 -1
- package/dist/node/compiler/get-vite-config.js +48 -6
- package/dist/node/compiler/vinxi-codegen.js +3 -0
- package/dist/node/types/block-type.d.ts +2 -2
- package/package.json +1 -1
- package/types.meta.d.ts +105 -0
package/css/editor-styles.css
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect } from "react";
|
|
3
3
|
import { useSnapshot } from "valtio";
|
|
4
4
|
import { BrowserRouter } from "../lib/routing/components/BrowserRouter.js";
|
|
5
5
|
import { clientMetaTags } from "../lib/routing/context.js";
|
|
6
6
|
import { APIProvider } from "../utils/APIProvider.js";
|
|
7
|
+
import { DevUILoader } from "../lib/devtools/loader.js";
|
|
7
8
|
export function SSRClientRoot(props) {
|
|
8
|
-
return (_jsxs(APIProvider, { children: [_jsx(DynamicMetaTags, {}), _jsx(
|
|
9
|
+
return (_jsxs(APIProvider, { children: [_jsx(BrowserRouter, {}), _jsxs(_Fragment, { children: [_jsx(DynamicMetaTags, {}), _jsx(DevUILoader, {})] })] }));
|
|
9
10
|
}
|
|
10
11
|
function DynamicMetaTags() {
|
|
11
12
|
const dynamicTags = useSnapshot(clientMetaTags).tags;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { SSRRouter } from "../lib/routing/components/SSRRouter.js";
|
|
3
3
|
import { getRouteMeta, normalizeRoute } from "../lib/routing/utils.js";
|
|
4
4
|
import { APIProvider } from "../utils/APIProvider.js";
|
|
@@ -6,16 +6,16 @@ export function SSRRoot(props) {
|
|
|
6
6
|
const loader = props.loader;
|
|
7
7
|
loader.setAppData(props.initialData.appData.data);
|
|
8
8
|
loader.populateRouteData(props.pathname, props.initialData);
|
|
9
|
-
return (
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
9
|
+
return (_jsxs(APIProvider, { children: [_jsx(SSRRouter, { loader: loader, route: normalizeRoute({
|
|
10
|
+
id: "initial",
|
|
11
|
+
component: loader.getRouteComponent(props.initialData.view),
|
|
12
|
+
key: "",
|
|
13
|
+
props: props.initialData.viewData.data,
|
|
14
|
+
view: props.initialData.view,
|
|
15
|
+
search: "",
|
|
16
|
+
pathname: props.pathname,
|
|
17
|
+
query: {},
|
|
18
|
+
hash: "",
|
|
19
|
+
meta: getRouteMeta(props.initialData),
|
|
20
|
+
}) }), _jsx(_Fragment, {})] }));
|
|
21
21
|
}
|
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import { ElementType } from "react";
|
|
2
2
|
import { InlineValueStore } from "./inline-editing.js";
|
|
3
3
|
export type InlineTextValueStore = InlineValueStore<string>;
|
|
4
|
+
type BuiltinFormats = "core/bold" | "core/code" | "core/italic" | "core/link" | "core/strikethrough" | "core/underline" | "core/subscript" | "core/superscript" | "core/unknown" | "core/non-breaking-space" | "core/footnote";
|
|
4
5
|
type Props<T extends ElementType> = {
|
|
5
6
|
/** Specify a tag name or React component */
|
|
6
7
|
as?: T;
|
|
7
8
|
/** Prevents this text element from being multi-line */
|
|
8
9
|
disableLineBreaks?: boolean;
|
|
9
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Specify which formatting options are allowed in this text element (bold, italics etc).
|
|
12
|
+
*
|
|
13
|
+
* By default, all options are enabled.
|
|
14
|
+
*
|
|
15
|
+
* Set to an empty array to disable formatting options.
|
|
16
|
+
*
|
|
17
|
+
* You can register new formats in `_editor.tsx` using the `defineEditorConfig` function.
|
|
18
|
+
**/
|
|
19
|
+
allowedFormats?: (BuiltinFormats | (string & {}))[];
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated use `allowedFormats` instead
|
|
22
|
+
*/
|
|
10
23
|
inlineToolbar?: boolean;
|
|
11
24
|
/** Specify default content to use on the frontend if nothing has been entered */
|
|
12
25
|
defaultValue?: string;
|
|
@@ -6,8 +6,13 @@ export function EditableText({ id, as, appendOnEnter, store, ...props }) {
|
|
|
6
6
|
const readOnly = useBlockContext()?.readonly;
|
|
7
7
|
if (!readOnly) {
|
|
8
8
|
const [value, setValue] = useValueStore(store ?? id);
|
|
9
|
+
// const defaultFormats = wp.data.useSelect((select) => {
|
|
10
|
+
// const formats = (select(wp.richText.store) as any).getFormatTypes()
|
|
11
|
+
// console.log("U", formats)
|
|
12
|
+
// return formats.map((f: any) => f.name)
|
|
13
|
+
// }, [])
|
|
9
14
|
const appendBlocks = useBlockAppender();
|
|
10
|
-
return (_jsx(wp.blockEditor.RichText, { ...props, placeholder: props.placeholder ?? props.defaultValue, tagName: as, value: value || "", onChange: setValue, inlineToolbar: props.
|
|
15
|
+
return (_jsx(wp.blockEditor.RichText, { ...props, placeholder: props.placeholder ?? props.defaultValue, tagName: as, value: value || "", onChange: setValue, allowedFormats: props.inlineToolbar === false ? [] : props.allowedFormats, disableLineBreaks: props.disableLineBreaks, "data-allowed-formats": props.allowedFormats?.join(" "), onKeyDownCapture: (e) => {
|
|
11
16
|
if (e.key === "Enter" && appendOnEnter && appendBlocks) {
|
|
12
17
|
appendBlocks([
|
|
13
18
|
wp.blocks.createBlock(typeof appendOnEnter === "string" ? appendOnEnter : "core/paragraph"),
|
|
@@ -21,11 +26,12 @@ export function EditableText({ id, as, appendOnEnter, store, ...props }) {
|
|
|
21
26
|
let [value] = useValueStore(store ?? id);
|
|
22
27
|
const handleClickEvent = useRouter((r) => r.handleClickEvent);
|
|
23
28
|
const otherProps = { ...props };
|
|
24
|
-
delete otherProps.inlineToolbar;
|
|
25
29
|
delete otherProps.disableLineBreaks;
|
|
26
30
|
delete otherProps.id;
|
|
27
31
|
otherProps.as = otherProps.asProp ?? undefined;
|
|
28
32
|
delete otherProps.asProp;
|
|
33
|
+
delete otherProps.allowedFormats;
|
|
34
|
+
delete otherProps.disableLineBreaks;
|
|
29
35
|
delete otherProps.placeholder;
|
|
30
36
|
if (value === "" || typeof value !== "string") {
|
|
31
37
|
if (props.defaultValue) {
|
|
@@ -2,7 +2,7 @@ import { FunctionComponent } from "react";
|
|
|
2
2
|
import { ContentBlockLayoutProps } from "./ContentBlocks.js";
|
|
3
3
|
import { BlockTemplate } from "./editor/block-templates.js";
|
|
4
4
|
type AppenderConfig = {
|
|
5
|
-
type: "default" | "button" | CustomBlockAppender;
|
|
5
|
+
type: "default" | "button" | "simple" | CustomBlockAppender;
|
|
6
6
|
className?: string;
|
|
7
7
|
};
|
|
8
8
|
export type CustomBlockAppender = FunctionComponent<{
|
|
@@ -26,9 +26,13 @@ type InnerBlocksProps = {
|
|
|
26
26
|
* NOTE: This will have no effect on the frontend, since no wrapper div is created on the frontend.
|
|
27
27
|
**/
|
|
28
28
|
adminClassName?: string;
|
|
29
|
-
/**
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
/** The default blocks to insert when there are no (non-templated) blocks */
|
|
30
|
+
defaultBlocks?: BlockTemplate;
|
|
31
|
+
/** Blocks to ensure are inserted at the top of the page */
|
|
32
|
+
headerTemplate?: BlockTemplate;
|
|
33
|
+
/** Blocks to ensure are inserted at the bottom of the page */
|
|
34
|
+
footerTemplate?: BlockTemplate;
|
|
35
|
+
/** A full-page block template */
|
|
32
36
|
template?: BlockTemplate;
|
|
33
37
|
/**
|
|
34
38
|
* `false` allows all operations
|
|
@@ -41,7 +45,7 @@ type InnerBlocksProps = {
|
|
|
41
45
|
* @default false
|
|
42
46
|
*
|
|
43
47
|
*/
|
|
44
|
-
templateLock?: "all" | "insert" | "contentOnly" | false;
|
|
48
|
+
templateLock?: "all" | "insert" | "contentOnly" | "none" | false;
|
|
45
49
|
appender?: AppenderConfig;
|
|
46
50
|
prioritizedInserterBlocks?: ChildBlockTypeName[];
|
|
47
51
|
} & ContentBlockLayoutProps;
|
|
@@ -1,25 +1,58 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useMemo } from "react";
|
|
2
3
|
import { ContentBlocks } from "./ContentBlocks.js";
|
|
3
|
-
import { transformBlockTemplate } from "./editor/block-templates.js";
|
|
4
|
+
import { applyTemplateBlocks, transformBlockTemplate } from "./editor/block-templates.js";
|
|
4
5
|
import { blocksByTag } from "./editor/blocks-by-tag.js";
|
|
5
6
|
import { useBlockContext, useInnerBlocks } from "./inline-editing.js";
|
|
6
|
-
|
|
7
|
+
import { hash } from "object-code";
|
|
8
|
+
const Appender = ({ config, ...props }) => {
|
|
7
9
|
const clientId = useBlockContext()?.block[1].clientId;
|
|
8
|
-
if (
|
|
9
|
-
return _jsx(wp.blockEditor.ButtonBlockAppender, {
|
|
10
|
+
if (config?.type === "button") {
|
|
11
|
+
return _jsx(wp.blockEditor.ButtonBlockAppender, { ...props, rootClientId: clientId, className: config.className });
|
|
10
12
|
}
|
|
11
|
-
else if (
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
else if (config?.type === "simple") {
|
|
14
|
+
return (_jsx(wp.blockEditor.ButtonBlockAppender, { ...props, rootClientId: clientId, className: (props.className || "") + " block-editor-inserter__toggle has-icon simple-appender" }));
|
|
15
|
+
}
|
|
16
|
+
else if (typeof config?.type === "function") {
|
|
17
|
+
const Type = config?.type;
|
|
18
|
+
return (_jsx(wp.blockEditor.Inserter, { rootClientId: clientId, renderToggle: (p) => {
|
|
14
19
|
return _jsx(Type, { ...p });
|
|
15
|
-
},
|
|
20
|
+
}, isAppender: true,
|
|
21
|
+
// @ts-ignore
|
|
22
|
+
__experimentalIsQuick: true }));
|
|
23
|
+
// } else if (config?.type === "simple") {
|
|
24
|
+
// return (
|
|
25
|
+
// <wp.blockEditor.Inserter
|
|
26
|
+
// clientId={clientId}
|
|
27
|
+
// rootClientId={clientId}
|
|
28
|
+
// renderToggle={(p: any) => {
|
|
29
|
+
// return (
|
|
30
|
+
// <button
|
|
31
|
+
// className="simple-appender components-button block-editor-inserter__toggle !inline-flex has-icon"
|
|
32
|
+
// onClick={() => p.onToggle()}
|
|
33
|
+
// >
|
|
34
|
+
// <svg
|
|
35
|
+
// xmlns="http://www.w3.org/2000/svg"
|
|
36
|
+
// viewBox="0 0 24 24"
|
|
37
|
+
// width="24"
|
|
38
|
+
// height="24"
|
|
39
|
+
// aria-hidden="true"
|
|
40
|
+
// focusable="false"
|
|
41
|
+
// >
|
|
42
|
+
// <path d="M11 12.5V17.5H12.5V12.5H17.5V11H12.5V6H11V11H6V12.5H11Z"></path>
|
|
43
|
+
// </svg>
|
|
44
|
+
// </button>
|
|
45
|
+
// )
|
|
46
|
+
// }}
|
|
47
|
+
// isAppender
|
|
48
|
+
// // @ts-ignore
|
|
49
|
+
// __experimentalIsQuick
|
|
50
|
+
// />
|
|
51
|
+
// )
|
|
16
52
|
}
|
|
17
53
|
else {
|
|
18
|
-
return (_jsx(wp.blockEditor.DefaultBlockAppender
|
|
19
54
|
// @ts-ignore
|
|
20
|
-
, {
|
|
21
|
-
// @ts-ignore
|
|
22
|
-
className: props.className, rootClientId: clientId, lastBlockClientId: clientId }));
|
|
55
|
+
return _jsx(wp.blockEditor.InnerBlocks.DefaultBlockAppender, { ...props });
|
|
23
56
|
}
|
|
24
57
|
};
|
|
25
58
|
export function createAppender(comp) {
|
|
@@ -33,29 +66,35 @@ export function createAppender(comp) {
|
|
|
33
66
|
export function InnerBlocks(props) {
|
|
34
67
|
if (env.admin) {
|
|
35
68
|
const inlineContext = useBlockContext();
|
|
69
|
+
const appender = useMemo(() => {
|
|
70
|
+
return (p) => _jsx(Appender, { config: props.appender, ...p });
|
|
71
|
+
}, [props.appender]);
|
|
36
72
|
if (!inlineContext?.readonly) {
|
|
37
73
|
const innerBlocksProps = wp.blockEditor.useInnerBlocksProps({}, {
|
|
38
74
|
orientation: props.orientation ?? "vertical",
|
|
39
75
|
allowedBlocks: props.allowedBlocks ? blocksByTag.expand(props.allowedBlocks) : undefined,
|
|
40
76
|
prioritizedInserterBlocks: props.prioritizedInserterBlocks,
|
|
41
|
-
renderAppender:
|
|
42
|
-
|
|
43
|
-
: wp.blockEditor.InnerBlocks.ButtonBlockAppender,
|
|
44
|
-
templateLock: props.templateLock ?? false,
|
|
77
|
+
renderAppender: appender,
|
|
78
|
+
templateLock: props.templateLock === "none" ? false : (props.templateLock ?? false),
|
|
45
79
|
template: props.template ? transformBlockTemplate(props.template) : undefined,
|
|
46
80
|
});
|
|
81
|
+
/**
|
|
82
|
+
* A little bit experimental
|
|
83
|
+
*
|
|
84
|
+
* Adds support for headerTemplate/defaultBlocks/footerTemplate, which was first introduced in `_editor.tsx` for generate templates.
|
|
85
|
+
*/
|
|
86
|
+
const blockId = inlineContext?.block[1].clientId;
|
|
87
|
+
useEffect(() => {
|
|
88
|
+
if (props.defaultBlocks || props.headerTemplate || props.footerTemplate) {
|
|
89
|
+
const newBlocks = applyTemplateBlocks(inlineContext?.innerBlocks ?? [], props);
|
|
90
|
+
wp.data.dispatch(wp.blockEditor.store).replaceInnerBlocks(blockId, newBlocks);
|
|
91
|
+
}
|
|
92
|
+
}, [
|
|
93
|
+
hash(inlineContext?.innerBlocks.map((b) => [b.blockName, b.clientId])),
|
|
94
|
+
hash([props.template, props.defaultBlocks, props.headerTemplate, props.footerTemplate]),
|
|
95
|
+
blockId,
|
|
96
|
+
]);
|
|
47
97
|
return (_jsx("div", { ...innerBlocksProps, className: [innerBlocksProps.className, props.adminClassName].filter(Boolean).join(" ") }));
|
|
48
|
-
// return (
|
|
49
|
-
// <wp.blockEditor.InnerBlocks
|
|
50
|
-
// // @ts-ignore
|
|
51
|
-
// orientation={props.orientation}
|
|
52
|
-
// prioritizedInserterBlocks={props.prioritizedInserterBlocks}
|
|
53
|
-
// allowedBlocks={props.allowedBlocks ? blocksByTag.expand(props.allowedBlocks) : undefined}
|
|
54
|
-
// renderAppender={props.appender ? () => <Appender {...props.appender!} /> : undefined}
|
|
55
|
-
// templateLock={(props.templateLock as any) ?? false}
|
|
56
|
-
// template={props.template ? transformBlockTemplate(props.template) : undefined}
|
|
57
|
-
// />
|
|
58
|
-
// )
|
|
59
98
|
}
|
|
60
99
|
}
|
|
61
100
|
const blocks = useInnerBlocks();
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import { ComponentType, ReactNode } from "react";
|
|
2
2
|
export declare function defineBlock<TName extends keyof BlockProps>(name: TName, component: (props: BlockProps[TName]) => ReactNode): ComponentType<BlockProps[TName]>;
|
|
3
|
+
export declare namespace defineBlock {
|
|
4
|
+
var meta: (name: string, meta: any) => void;
|
|
5
|
+
}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
import { blockMetaDescriptors } from "./editor/installGutenbergHooks";
|
|
2
|
+
import { resolveAcfBlockName } from "./editor/block-templates";
|
|
1
3
|
export function defineBlock(name, component) {
|
|
2
4
|
return component;
|
|
3
5
|
}
|
|
6
|
+
defineBlock.meta = (name, meta) => {
|
|
7
|
+
if (env.admin) {
|
|
8
|
+
blockMetaDescriptors.set(resolveAcfBlockName(name), meta);
|
|
9
|
+
}
|
|
10
|
+
};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { useEffect,
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from "react";
|
|
3
3
|
export function EditorHighlights(props) {
|
|
4
|
-
const
|
|
4
|
+
const [element, setElement] = useState(null);
|
|
5
5
|
const [controller, setController] = useState(null);
|
|
6
6
|
// wp.data.select('core/editor').isBlockSelected
|
|
7
7
|
// const isSelected = wp.data.useSelect(
|
|
@@ -9,12 +9,12 @@ export function EditorHighlights(props) {
|
|
|
9
9
|
// [props.clientId]
|
|
10
10
|
// )
|
|
11
11
|
useEffect(() => {
|
|
12
|
-
if (!props.enabled)
|
|
12
|
+
if (!props.enabled || !element)
|
|
13
13
|
return;
|
|
14
|
-
const controller = new HighlightController(
|
|
14
|
+
const controller = new HighlightController(element);
|
|
15
15
|
setController(controller);
|
|
16
16
|
return () => controller.teardown();
|
|
17
|
-
}, [props.enabled]);
|
|
17
|
+
}, [props.enabled, element]);
|
|
18
18
|
useEffect(() => {
|
|
19
19
|
if (controller) {
|
|
20
20
|
controller.isSelected = false;
|
|
@@ -22,7 +22,38 @@ export function EditorHighlights(props) {
|
|
|
22
22
|
controller.update();
|
|
23
23
|
}
|
|
24
24
|
}, [controller, false]);
|
|
25
|
-
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
const element = document.getElementById(`block-${props.clientId}`);
|
|
27
|
+
if (element) {
|
|
28
|
+
setElement(element);
|
|
29
|
+
}
|
|
30
|
+
else {
|
|
31
|
+
setElement(null);
|
|
32
|
+
}
|
|
33
|
+
}, [props.clientId]);
|
|
34
|
+
useEffect(() => {
|
|
35
|
+
if (controller && element) {
|
|
36
|
+
const onPointerEnter = () => controller.enable();
|
|
37
|
+
const onPointerLeave = () => controller.disable();
|
|
38
|
+
element.addEventListener("pointerenter", onPointerEnter);
|
|
39
|
+
element.addEventListener("pointerleave", onPointerLeave);
|
|
40
|
+
return () => {
|
|
41
|
+
element.removeEventListener("pointerenter", onPointerEnter);
|
|
42
|
+
element.removeEventListener("pointerleave", onPointerLeave);
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}, [element, controller]);
|
|
46
|
+
return _jsx(_Fragment, { children: props.children });
|
|
47
|
+
// return (
|
|
48
|
+
// <div
|
|
49
|
+
// ref={ref}
|
|
50
|
+
// style={{ display: "contents" }}
|
|
51
|
+
// // onPointerEnter={() => controller?.enable()}
|
|
52
|
+
// // onPointerLeave={() => controller?.disable()}
|
|
53
|
+
// >
|
|
54
|
+
// {props.children}
|
|
55
|
+
// </div>
|
|
56
|
+
// )
|
|
26
57
|
}
|
|
27
58
|
class HighlightController {
|
|
28
59
|
root;
|
|
@@ -40,7 +71,7 @@ class HighlightController {
|
|
|
40
71
|
let editables = Array.from(this.root.querySelectorAll("[contenteditable=true], .editable-slot"));
|
|
41
72
|
let childBlocks = Array.from(this.root.querySelectorAll(".wp-block"));
|
|
42
73
|
const childIsSelected = this.root.querySelectorAll(".editor-highlighter-root-selected").length > 0;
|
|
43
|
-
this.block =
|
|
74
|
+
this.block = this.root;
|
|
44
75
|
childBlocks = childBlocks.slice(1);
|
|
45
76
|
editables = childIsSelected
|
|
46
77
|
? []
|
|
@@ -96,7 +127,10 @@ class HighlightController {
|
|
|
96
127
|
el.style.position = "absolute";
|
|
97
128
|
el.style.pointerEvents = "none";
|
|
98
129
|
el.style.zIndex = "20";
|
|
99
|
-
el.
|
|
130
|
+
el.classList.add("editor-highlight");
|
|
131
|
+
if (target.getAttribute("data-editor-higlight-class")) {
|
|
132
|
+
el.classList.add(target.getAttribute("data-editor-higlight-class"));
|
|
133
|
+
}
|
|
100
134
|
this.block.appendChild(el);
|
|
101
135
|
return el;
|
|
102
136
|
}
|
|
@@ -1,17 +1,23 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
import { createContext, Suspense, useContext } from "react";
|
|
2
|
+
import { createContext, Suspense, useContext, useEffect } from "react";
|
|
3
3
|
import { blockManifestReader } from "../../internal/read-block-manifest.js";
|
|
4
4
|
import { APIProvider } from "../../../utils/APIProvider.js";
|
|
5
5
|
import { ErrorBoundaryEditor } from "./ErrorBoundaryEditor.js";
|
|
6
6
|
export const BlockContext = createContext(undefined);
|
|
7
7
|
export function EditableBlock({ payload }) {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
if (!env.admin)
|
|
9
|
+
throw new Error("`EditableBlock` can only be used in the admin environment");
|
|
10
|
+
const info = useContext(BlockContext);
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
const block = wp.data.select("core/block-editor").getBlock(info?.props.clientId);
|
|
13
|
+
if (block && block.attributes) {
|
|
14
|
+
// @ts-ignore
|
|
15
|
+
block.attributes.props = payload;
|
|
16
|
+
}
|
|
17
|
+
}, [payload, info?.props.clientId]);
|
|
18
|
+
if (!info)
|
|
10
19
|
return null;
|
|
11
|
-
const
|
|
12
|
-
return blockManifestReader.value[block.name];
|
|
13
|
-
};
|
|
14
|
-
const BlockComponent = getBlock();
|
|
20
|
+
const BlockComponent = blockManifestReader.value[info.name];
|
|
15
21
|
if (!BlockComponent)
|
|
16
22
|
return _jsx("div", { children: "Unable to load block component" });
|
|
17
23
|
return (_jsx(ErrorBoundaryEditor, { children: _jsx(APIProvider, { children: _jsx(Suspense, { children: _jsx(BlockComponent, { ...payload }) }) }) }));
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
export type BlockTemplate = [name: ChildBlockTypeName, props: any, children?: BlockTemplate][];
|
|
2
2
|
export declare function resolveAcfBlockName(name: string): string;
|
|
3
3
|
export declare function transformBlockTemplate(template: BlockTemplate): BlockTemplate;
|
|
4
|
+
export declare function applyTemplateBlocks(currentBlocks: any[], config: {
|
|
5
|
+
defaultBlocks?: BlockTemplate;
|
|
6
|
+
headerTemplate?: BlockTemplate;
|
|
7
|
+
footerTemplate?: BlockTemplate;
|
|
8
|
+
}): any[];
|
|
9
|
+
export declare function transformTemplateToBlocks(template: BlockTemplate, locked?: boolean, isFromTemplate?: boolean): any;
|
|
@@ -7,3 +7,67 @@ export function transformBlockTemplate(template) {
|
|
|
7
7
|
return [resolveAcfBlockName(name), props, children ? transformBlockTemplate(children) : undefined];
|
|
8
8
|
});
|
|
9
9
|
}
|
|
10
|
+
export function applyTemplateBlocks(currentBlocks, config) {
|
|
11
|
+
const templateBlocks = currentBlocks.filter((block) => block.attributes.isFromTemplate);
|
|
12
|
+
let header = config.headerTemplate ? syncBlocks(transformTemplateToBlocks(config.headerTemplate)) : [];
|
|
13
|
+
let footer = config.footerTemplate ? syncBlocks(transformTemplateToBlocks(config.footerTemplate)) : [];
|
|
14
|
+
let blocks = currentBlocks.filter((block) => !header.includes(block) && !footer.includes(block));
|
|
15
|
+
blocks.forEach((block) => {
|
|
16
|
+
delete block.attributes.lock;
|
|
17
|
+
delete block.isFromTemplate;
|
|
18
|
+
});
|
|
19
|
+
// const blocksToDelete = currentBlocks.filter((block: any) => {
|
|
20
|
+
// return !header.includes(block) && !footer.includes(block) && !blocks.includes(block)
|
|
21
|
+
// })
|
|
22
|
+
// blocksToDelete.forEach((block: any) => {
|
|
23
|
+
// delete block.attributes.lock
|
|
24
|
+
// delete block.isFromTemplate
|
|
25
|
+
// })
|
|
26
|
+
// blocks = [...blocks, ...blocksToDelete]
|
|
27
|
+
// console.log("blocks", blocks)
|
|
28
|
+
// console.log("blocksToDelete", blocksToDelete)
|
|
29
|
+
if (!blocks.length && config.defaultBlocks) {
|
|
30
|
+
blocks = transformTemplateToBlocks(config.defaultBlocks, false, false);
|
|
31
|
+
}
|
|
32
|
+
let newBlocks = [...header, ...blocks, ...footer];
|
|
33
|
+
function syncBlocks(blocks) {
|
|
34
|
+
return blocks.map((block) => {
|
|
35
|
+
const matched = templateBlocks.find((templateBlock) => templateBlock.name === block.name);
|
|
36
|
+
templateBlocks.splice(templateBlocks.indexOf(matched), 1);
|
|
37
|
+
if (matched) {
|
|
38
|
+
matched.attributes.lock = block.attributes.lock;
|
|
39
|
+
return matched;
|
|
40
|
+
}
|
|
41
|
+
return block;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return newBlocks;
|
|
45
|
+
}
|
|
46
|
+
export function transformTemplateToBlocks(template, locked = true, isFromTemplate = true) {
|
|
47
|
+
return template.map(([name, props, children]) => {
|
|
48
|
+
const attributes = {
|
|
49
|
+
data: {},
|
|
50
|
+
inline: {},
|
|
51
|
+
isFromTemplate: isFromTemplate,
|
|
52
|
+
lock: undefined,
|
|
53
|
+
};
|
|
54
|
+
if (props.locked === false) {
|
|
55
|
+
attributes.lock = { move: false, remove: false };
|
|
56
|
+
}
|
|
57
|
+
else if (locked || props.locked === true || props.locked === "all") {
|
|
58
|
+
attributes.lock = { move: true, remove: true };
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
attributes.lock = props.lock;
|
|
62
|
+
}
|
|
63
|
+
Object.assign(attributes, props);
|
|
64
|
+
return {
|
|
65
|
+
clientId: "block-" + Math.random().toString(36),
|
|
66
|
+
name: resolveAcfBlockName(name),
|
|
67
|
+
attributes: attributes,
|
|
68
|
+
innerBlocks: children ? transformTemplateToBlocks(children, false, isFromTemplate) : [],
|
|
69
|
+
isValid: true,
|
|
70
|
+
validationIssues: [],
|
|
71
|
+
};
|
|
72
|
+
});
|
|
73
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BlockInstance } from "../inline-editing";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a block instance for the editor. This doesn't add the block to the editor on it's own.
|
|
4
|
+
* @param name The name of the block
|
|
5
|
+
* @param attributes
|
|
6
|
+
* @param innerBlocks
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export declare function createBlock(name: ChildBlockTypeName, attributes?: Record<string, any>, innerBlocks?: BlockInstance[]): BlockInstance;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a block instance for the editor. This doesn't add the block to the editor on it's own.
|
|
3
|
+
* @param name The name of the block
|
|
4
|
+
* @param attributes
|
|
5
|
+
* @param innerBlocks
|
|
6
|
+
* @returns
|
|
7
|
+
*/
|
|
8
|
+
export function createBlock(name, attributes = {}, innerBlocks = []) {
|
|
9
|
+
if (!env.admin) {
|
|
10
|
+
throw new Error("`createBlock` can only be used in the admin environment");
|
|
11
|
+
}
|
|
12
|
+
return wp.blocks.createBlock(name, attributes, innerBlocks);
|
|
13
|
+
}
|
|
@@ -44,7 +44,6 @@ export declare const editorConfigStore: {
|
|
|
44
44
|
currentBlocksConfig: EditorConfigItem;
|
|
45
45
|
};
|
|
46
46
|
export declare function configureEditorBlocks(config: EditorConfigItem): void;
|
|
47
|
-
export declare function transformTemplateToBlocks(template: BlockTemplate, locked?: boolean, isFromTemplate?: boolean): any;
|
|
48
47
|
type PostInfo = {
|
|
49
48
|
type: PostTypeName;
|
|
50
49
|
isPattern: false;
|
|
@@ -72,9 +71,45 @@ type Matcher = {
|
|
|
72
71
|
/** Configuration for the editor, when the post type and template match */
|
|
73
72
|
config: EditorConfigItem | ((post: PostInfo) => EditorConfigItem);
|
|
74
73
|
};
|
|
74
|
+
export type BlockTransform = {
|
|
75
|
+
from: ChildBlockTypeName[];
|
|
76
|
+
to: ChildBlockTypeName;
|
|
77
|
+
};
|
|
78
|
+
export type CustomRichTextFormat = {
|
|
79
|
+
/** The ID of the format, eg. `"custom/fancy"` */
|
|
80
|
+
id: string;
|
|
81
|
+
/** The title of the format, shown on the tooltip */
|
|
82
|
+
title: string;
|
|
83
|
+
/**
|
|
84
|
+
* The HTML tag name to use.
|
|
85
|
+
* @default `"span"`
|
|
86
|
+
**/
|
|
87
|
+
tagName?: string;
|
|
88
|
+
/**
|
|
89
|
+
* The class name to apply to the element.
|
|
90
|
+
* @default `undefined`
|
|
91
|
+
**/
|
|
92
|
+
className?: string;
|
|
93
|
+
/**
|
|
94
|
+
* The icon to use in the toolbar.
|
|
95
|
+
*/
|
|
96
|
+
icon?: string;
|
|
97
|
+
/**
|
|
98
|
+
* Whether format makes content interactive or not.
|
|
99
|
+
* @default `false`
|
|
100
|
+
*/
|
|
101
|
+
interactive?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Whether to disable this format by default. If `true`, you must pass the format ID to `allowedFormats` on a `EditableText` component.
|
|
104
|
+
*
|
|
105
|
+
* @default `false`
|
|
106
|
+
*/
|
|
107
|
+
disabledByDefault?: boolean;
|
|
108
|
+
};
|
|
75
109
|
type EditorConfig = {
|
|
76
|
-
|
|
77
|
-
matchers
|
|
110
|
+
customRichTextFormats?: CustomRichTextFormat[];
|
|
111
|
+
/** A list of template/post type matchers, and resulting editor config that they will apply */
|
|
112
|
+
matchers?: Matcher[];
|
|
78
113
|
};
|
|
79
114
|
/**
|
|
80
115
|
* This call should be placed in blocks/_editor.tsx
|