@cloudcannon/editable-regions 0.0.9 → 0.0.11
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/components/editable-snippet-component.ts +1 -1
- package/components/index.ts +0 -13
- package/components/ui/editable-array-item-controls.ts +9 -0
- package/components/ui/editable-component-controls.ts +67 -11
- package/helpers/checks.ts +14 -37
- package/helpers/cloudcannon.mjs +10 -2
- package/helpers/hydrate-editable-regions.ts +7 -1
- package/integrations/astro/astro-integration.mjs +109 -100
- package/integrations/astro/index.mjs +21 -8
- package/integrations/astro/modules/content.js +7 -1
- package/integrations/astro/modules/secrets.js +4 -0
- package/nodes/editable-array-item.ts +9 -9
- package/nodes/editable-array.ts +74 -28
- package/nodes/editable-component.ts +155 -97
- package/nodes/editable-source.ts +8 -2
- package/nodes/editable.ts +197 -33
- package/package.json +3 -3
- package/styles/editable-array-item.css +5 -3
- package/styles/editable-component.css +5 -3
- package/styles/ui/editable-component-controls.css +21 -0
- package/helpers/loading.ts +0 -7
- package/integrations/astro/modules/actions.js +0 -74
- package/integrations/astro/modules/client-router.astro +0 -5
- package/integrations/astro/modules/i18n.js +0 -76
- package/integrations/astro/modules/middleware.js +0 -27
- package/integrations/astro/modules/transitions.js +0 -63
|
@@ -9,7 +9,7 @@ export default class EditableSnippetComponent extends HTMLElement {
|
|
|
9
9
|
}
|
|
10
10
|
|
|
11
11
|
set snippetData(value: unknown) {
|
|
12
|
-
this.editable.pushValue(value);
|
|
12
|
+
this.editable.pushValue(value, {}, { path: "", editable: this.editable });
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
connectedCallback(): void {
|
package/components/index.ts
CHANGED
|
@@ -6,12 +6,10 @@ export { default as EditableSnippetComponent } from "./editable-snippet-componen
|
|
|
6
6
|
export { default as EditableSourceComponent } from "./editable-source-component.js";
|
|
7
7
|
export { default as EditableTextComponent } from "./editable-text-component.js";
|
|
8
8
|
|
|
9
|
-
import { apiLoadedPromise } from "../helpers/cloudcannon.mjs";
|
|
10
9
|
import {
|
|
11
10
|
dehydrateDataEditableRegions,
|
|
12
11
|
hydrateDataEditableRegions,
|
|
13
12
|
} from "../helpers/hydrate-editable-regions";
|
|
14
|
-
import { completeLoading } from "../helpers/loading.js";
|
|
15
13
|
|
|
16
14
|
const observer = new MutationObserver((mutations) => {
|
|
17
15
|
mutations.forEach((mutation) => {
|
|
@@ -32,14 +30,3 @@ const observer = new MutationObserver((mutations) => {
|
|
|
32
30
|
hydrateDataEditableRegions(document.body);
|
|
33
31
|
|
|
34
32
|
observer.observe(document, { childList: true, subtree: true });
|
|
35
|
-
|
|
36
|
-
Promise.all([
|
|
37
|
-
apiLoadedPromise,
|
|
38
|
-
customElements.whenDefined("editable-array-item"),
|
|
39
|
-
customElements.whenDefined("editable-array"),
|
|
40
|
-
customElements.whenDefined("editable-text"),
|
|
41
|
-
customElements.whenDefined("editable-component"),
|
|
42
|
-
customElements.whenDefined("editable-image"),
|
|
43
|
-
customElements.whenDefined("editable-source"),
|
|
44
|
-
customElements.whenDefined("editable-snippet"),
|
|
45
|
-
]).then(() => completeLoading());
|
|
@@ -93,7 +93,16 @@ export default class EditableArrayItemControls extends EditableComponentControls
|
|
|
93
93
|
|
|
94
94
|
this.dragHandle = document.createElement("button");
|
|
95
95
|
this.dragHandle.type = "button";
|
|
96
|
+
|
|
97
|
+
if (this.usePopoverAPI) {
|
|
98
|
+
//@ts-expect-error: Typescript doesn't yet support the popover API
|
|
99
|
+
this.dragHandle.style.anchorName = this.anchorName;
|
|
100
|
+
}
|
|
101
|
+
|
|
96
102
|
this.dragHandle.onclick = (e) => {
|
|
103
|
+
if (this.hasAttribute("open")) {
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
97
106
|
e.stopPropagation();
|
|
98
107
|
e.preventDefault();
|
|
99
108
|
this.toggleContextMenu();
|
|
@@ -6,13 +6,28 @@ export default class EditableComponentControls extends HTMLElement {
|
|
|
6
6
|
protected buttonRow?: HTMLDivElement;
|
|
7
7
|
|
|
8
8
|
private editButton?: HTMLButtonElement;
|
|
9
|
+
protected usePopoverAPI = false;
|
|
10
|
+
protected contextMenuId =
|
|
11
|
+
`context-menu-popover-${Math.random().toString(36).substring(2, 11)}`;
|
|
12
|
+
protected anchorName = `--${this.contextMenuId}`;
|
|
13
|
+
protected hostAnchorName =
|
|
14
|
+
`--cc-editable-host-${Math.random().toString(36).substring(2, 11)}`;
|
|
9
15
|
|
|
10
16
|
toggleContextMenu() {
|
|
11
|
-
if (this.contextMenu
|
|
12
|
-
|
|
17
|
+
if (!this.contextMenu || this.contextMenu.childElementCount === 0) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (this.usePopoverAPI) {
|
|
22
|
+
this.contextMenu.togglePopover();
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (this.contextMenu.classList.contains("open")) {
|
|
27
|
+
this.contextMenu.classList.remove("open");
|
|
13
28
|
this.removeAttribute("open");
|
|
14
|
-
} else
|
|
15
|
-
this.contextMenu
|
|
29
|
+
} else {
|
|
30
|
+
this.contextMenu.classList.add("open");
|
|
16
31
|
this.setAttribute("open", "true");
|
|
17
32
|
}
|
|
18
33
|
}
|
|
@@ -28,6 +43,13 @@ export default class EditableComponentControls extends HTMLElement {
|
|
|
28
43
|
|
|
29
44
|
this.contextMenu = document.createElement("ul");
|
|
30
45
|
this.contextMenu.classList.add("context-menu");
|
|
46
|
+
|
|
47
|
+
if (this.usePopoverAPI) {
|
|
48
|
+
this.contextMenu.setAttribute("popover", "auto");
|
|
49
|
+
//@ts-expect-error: Typescript doesn't yet support the popover API
|
|
50
|
+
this.contextMenu.style.positionAnchor = this.anchorName;
|
|
51
|
+
}
|
|
52
|
+
|
|
31
53
|
shadow.appendChild(this.contextMenu);
|
|
32
54
|
|
|
33
55
|
this.editButton = document.createElement("button");
|
|
@@ -40,17 +62,32 @@ export default class EditableComponentControls extends HTMLElement {
|
|
|
40
62
|
|
|
41
63
|
this.onclick = (e) => {
|
|
42
64
|
e.preventDefault();
|
|
43
|
-
this.contextMenu?.classList.remove("open");
|
|
44
65
|
this.removeAttribute("open");
|
|
45
|
-
};
|
|
46
66
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
67
|
+
if (this.usePopoverAPI) {
|
|
68
|
+
this.contextMenu?.hidePopover();
|
|
69
|
+
} else {
|
|
70
|
+
this.contextMenu?.classList.remove("open");
|
|
50
71
|
}
|
|
51
|
-
this.contextMenu?.classList.remove("open");
|
|
52
|
-
this.removeAttribute("open");
|
|
53
72
|
};
|
|
73
|
+
|
|
74
|
+
if (this.usePopoverAPI && this.contextMenu) {
|
|
75
|
+
this.contextMenu.ontoggle = (e: ToggleEvent) => {
|
|
76
|
+
if (e.newState === "open") {
|
|
77
|
+
this.setAttribute("open", "true");
|
|
78
|
+
} else {
|
|
79
|
+
this.removeAttribute("open");
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
} else {
|
|
83
|
+
this.onblur = (e) => {
|
|
84
|
+
if ((e.relatedTarget as HTMLElement)?.tagName === "A") {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
this.removeAttribute("open");
|
|
88
|
+
this.contextMenu?.classList.remove("open");
|
|
89
|
+
};
|
|
90
|
+
}
|
|
54
91
|
}
|
|
55
92
|
|
|
56
93
|
connectedCallback() {
|
|
@@ -58,8 +95,27 @@ export default class EditableComponentControls extends HTMLElement {
|
|
|
58
95
|
return;
|
|
59
96
|
}
|
|
60
97
|
|
|
98
|
+
this.usePopoverAPI =
|
|
99
|
+
"popover" in HTMLElement.prototype && CSS.supports("anchor-name", "--a");
|
|
100
|
+
|
|
61
101
|
this.shadow = this.attachShadow({ mode: "open" });
|
|
62
102
|
this.render(this.shadow);
|
|
103
|
+
|
|
104
|
+
if (this.usePopoverAPI && this.parentElement) {
|
|
105
|
+
const existing = getComputedStyle(this.parentElement)
|
|
106
|
+
.getPropertyValue("anchor-name")
|
|
107
|
+
.trim();
|
|
108
|
+
|
|
109
|
+
if (existing && existing !== "none") {
|
|
110
|
+
this.hostAnchorName = existing.split(",")[0].trim();
|
|
111
|
+
} else {
|
|
112
|
+
// @ts-expect-error
|
|
113
|
+
this.parentElement.style.anchorName = this.hostAnchorName;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// @ts-expect-error
|
|
117
|
+
this.style.positionAnchor = this.hostAnchorName;
|
|
118
|
+
}
|
|
63
119
|
}
|
|
64
120
|
}
|
|
65
121
|
|
package/helpers/checks.ts
CHANGED
|
@@ -2,32 +2,11 @@ import Editable from "../nodes/editable.js";
|
|
|
2
2
|
import EditableArrayItem from "../nodes/editable-array-item.js";
|
|
3
3
|
import EditableText from "../nodes/editable-text.js";
|
|
4
4
|
|
|
5
|
-
const
|
|
6
|
-
"EDITABLE-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"EDITABLE-IMAGE",
|
|
11
|
-
"EDITABLE-SOURCE",
|
|
12
|
-
"EDITABLE-SNIPPET",
|
|
13
|
-
];
|
|
14
|
-
|
|
15
|
-
const EDITABLE_REGION_TYPES = [
|
|
16
|
-
"text",
|
|
17
|
-
"component",
|
|
18
|
-
"array",
|
|
19
|
-
"array-item",
|
|
20
|
-
"image",
|
|
21
|
-
"source",
|
|
22
|
-
];
|
|
23
|
-
|
|
24
|
-
const CORRESPONDING_NAME: Record<string, string> = {
|
|
25
|
-
"EDITABLE-TEXT": "text",
|
|
26
|
-
"EDITABLE-COMPONENT": "component",
|
|
27
|
-
"EDITABLE-ARRAY-ITEM": "array-item",
|
|
28
|
-
"EDITABLE-ARRAY": "array",
|
|
29
|
-
"EDITABLE-IMAGE": "image",
|
|
30
|
-
"EDITABLE-SOURCE": "source",
|
|
5
|
+
const getEditableType = (el: HTMLElement): string | undefined => {
|
|
6
|
+
if (el.tagName.startsWith("EDITABLE-")) {
|
|
7
|
+
return el.tagName.slice(9).toLowerCase();
|
|
8
|
+
}
|
|
9
|
+
return el.dataset.editable;
|
|
31
10
|
};
|
|
32
11
|
|
|
33
12
|
export const hasEditable = <T extends object>(
|
|
@@ -53,7 +32,7 @@ export const isEditableWebcomponent = (el: unknown): boolean => {
|
|
|
53
32
|
return false;
|
|
54
33
|
}
|
|
55
34
|
|
|
56
|
-
return
|
|
35
|
+
return el.tagName.startsWith("EDITABLE-");
|
|
57
36
|
};
|
|
58
37
|
|
|
59
38
|
export const isEditableElement = (el: unknown): boolean => {
|
|
@@ -62,19 +41,17 @@ export const isEditableElement = (el: unknown): boolean => {
|
|
|
62
41
|
}
|
|
63
42
|
|
|
64
43
|
return (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
EDITABLE_REGION_TYPES.includes(el.dataset.editable))
|
|
44
|
+
el.tagName.startsWith("EDITABLE-") ||
|
|
45
|
+
typeof el.dataset.editable === "string"
|
|
68
46
|
);
|
|
69
47
|
};
|
|
70
48
|
|
|
71
|
-
export const areEqualEditables = (a:
|
|
72
|
-
if (
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
) {
|
|
49
|
+
export const areEqualEditables = (a: Element, b: Element) => {
|
|
50
|
+
if (!(a instanceof HTMLElement) || !(b instanceof HTMLElement)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (getEditableType(a) !== getEditableType(b)) {
|
|
78
55
|
return false;
|
|
79
56
|
}
|
|
80
57
|
|
package/helpers/cloudcannon.mjs
CHANGED
|
@@ -55,7 +55,6 @@ export const apiLoadedPromise = new Promise((resolve) => {
|
|
|
55
55
|
export const addEditableComponentRenderer = (key, renderer) => {
|
|
56
56
|
extendedWindow.cc_components = extendedWindow.cc_components || {};
|
|
57
57
|
extendedWindow.cc_components[key] = renderer;
|
|
58
|
-
document.dispatchEvent(new CustomEvent(`editable-regions:registered-${key}`));
|
|
59
58
|
};
|
|
60
59
|
|
|
61
60
|
/**
|
|
@@ -67,7 +66,6 @@ export const addEditableComponentRenderer = (key, renderer) => {
|
|
|
67
66
|
export const addEditableSnippetRenderer = (key, renderer) => {
|
|
68
67
|
extendedWindow.cc_snippets = extendedWindow.cc_snippets || {};
|
|
69
68
|
extendedWindow.cc_snippets[key] = renderer;
|
|
70
|
-
document.dispatchEvent(new CustomEvent(`editable-regions:registered-${key}`));
|
|
71
69
|
};
|
|
72
70
|
|
|
73
71
|
/**
|
|
@@ -107,4 +105,14 @@ export const realizeAPIValue = async (value) => {
|
|
|
107
105
|
return value;
|
|
108
106
|
};
|
|
109
107
|
|
|
108
|
+
export const addCustomEditableRegion = (key, region) => {
|
|
109
|
+
extendedWindow.editableRegionMap ??= {};
|
|
110
|
+
extendedWindow.editableRegionMap[key] = region;
|
|
111
|
+
extendedWindow.hydrateDataEditableRegions(document.body);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export const getCustomEditableRegions = () => {
|
|
115
|
+
return extendedWindow.editableRegionMap ?? {};
|
|
116
|
+
};
|
|
117
|
+
|
|
110
118
|
export { _cloudcannon as CloudCannon };
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "../nodes";
|
|
10
10
|
import { hasEditable, isEditableWebcomponent } from "./checks";
|
|
11
11
|
|
|
12
|
-
const
|
|
12
|
+
const baseEditableMap: Record<string, typeof Editable | undefined> = {
|
|
13
13
|
array: EditableArray,
|
|
14
14
|
"array-item": EditableArrayItem,
|
|
15
15
|
component: EditableComponent,
|
|
@@ -31,6 +31,10 @@ export const dehydrateDataEditableRegions = (root: Element) => {
|
|
|
31
31
|
};
|
|
32
32
|
|
|
33
33
|
export const hydrateDataEditableRegions = (root: Element) => {
|
|
34
|
+
const editableMap: Record<string, typeof Editable | undefined> = {
|
|
35
|
+
...baseEditableMap,
|
|
36
|
+
...((window as any).editableRegionMap ?? {}),
|
|
37
|
+
};
|
|
34
38
|
if (
|
|
35
39
|
root instanceof HTMLElement &&
|
|
36
40
|
root.dataset.editable &&
|
|
@@ -89,3 +93,5 @@ export const hydrateDataEditableRegions = (root: Element) => {
|
|
|
89
93
|
}
|
|
90
94
|
});
|
|
91
95
|
};
|
|
96
|
+
|
|
97
|
+
(window as any).hydrateDataEditableRegions = hydrateDataEditableRegions;
|
|
@@ -1,127 +1,136 @@
|
|
|
1
1
|
import { dirname, join } from "node:path";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
/** @type{string[]} */
|
|
5
|
+
const SUPPORTED_VIRTUAL_MODULES = ["assets", "content"];
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {*} original
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
function wrapTransform(original) {
|
|
12
|
+
/**
|
|
13
|
+
* @this {*}
|
|
14
|
+
* @param {*} source
|
|
15
|
+
* @param {*} id
|
|
16
|
+
* @param {*} options
|
|
17
|
+
*/
|
|
18
|
+
return function (source, id, options) {
|
|
19
|
+
if (this.environment?.name === "client") {
|
|
20
|
+
const proxy = new Proxy(this, {
|
|
21
|
+
get(target, prop) {
|
|
22
|
+
if (prop === "environment") {
|
|
23
|
+
return { ...target.environment, name: "ssr" };
|
|
24
|
+
}
|
|
25
|
+
return Reflect.get(target, prop);
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
return original.call(proxy, source, id, { ...options, ssr: true });
|
|
29
|
+
}
|
|
30
|
+
return original.call(this, source, id, options);
|
|
31
|
+
};
|
|
32
|
+
}
|
|
12
33
|
|
|
13
34
|
/**
|
|
14
35
|
* @return {import("astro").AstroIntegration}
|
|
15
36
|
*/
|
|
16
37
|
export default () => {
|
|
17
|
-
/** @type {import("astro").AstroConfig} */
|
|
18
|
-
let astroConfig;
|
|
19
|
-
|
|
20
38
|
return {
|
|
21
39
|
name: "editable-regions",
|
|
22
40
|
hooks: {
|
|
23
|
-
"astro:config:setup": ({
|
|
41
|
+
"astro:config:setup": ({ updateConfig }) => {
|
|
24
42
|
updateConfig({
|
|
25
43
|
vite: {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
vite.plugins ??= [];
|
|
36
|
-
vite.define ??= {};
|
|
37
|
-
vite.define.ENV_CLIENT = true;
|
|
44
|
+
plugins: [
|
|
45
|
+
{
|
|
46
|
+
enforce: "pre",
|
|
47
|
+
name: "vite-plugin-editable-regions",
|
|
48
|
+
applyToEnvironment(environment) {
|
|
49
|
+
return environment.name === "client";
|
|
50
|
+
},
|
|
51
|
+
config(config) {
|
|
52
|
+
config.environments ??= {};
|
|
38
53
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
obj &&
|
|
43
|
-
typeof obj === "object" &&
|
|
44
|
-
"name" in obj &&
|
|
45
|
-
obj.name === "astro:build"
|
|
46
|
-
);
|
|
47
|
-
});
|
|
54
|
+
config.environments.ssr ??= {};
|
|
55
|
+
config.environments.ssr.define ??= {};
|
|
56
|
+
config.environments.ssr.define.ENV_CLIENT = false;
|
|
48
57
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
typeof astroBuildPlugin.transform === "function"
|
|
53
|
-
) {
|
|
54
|
-
const original = astroBuildPlugin.transform;
|
|
55
|
-
astroBuildPlugin.transform = function (source, id, options) {
|
|
56
|
-
return original.bind(this)(source, id, { ...options, ssr: true });
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
vite.plugins.unshift({
|
|
61
|
-
name: "vite-plugin-editable-regions",
|
|
62
|
-
enforce: "pre",
|
|
63
|
-
|
|
64
|
-
resolveId(id) {
|
|
65
|
-
if (id.startsWith("astro:")) {
|
|
66
|
-
const type = id
|
|
67
|
-
.replace("astro:", "")
|
|
68
|
-
.replace("/client", "")
|
|
69
|
-
.replace("/server", "");
|
|
58
|
+
config.environments.astro ??= {};
|
|
59
|
+
config.environments.astro.define ??= {};
|
|
60
|
+
config.environments.astro.define.ENV_CLIENT = false;
|
|
70
61
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
config.environments.prerender ??= {};
|
|
63
|
+
config.environments.prerender.define ??= {};
|
|
64
|
+
config.environments.prerender.define.ENV_CLIENT = false;
|
|
74
65
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
66
|
+
config.environments.client ??= {};
|
|
67
|
+
config.environments.client.define ??= {};
|
|
68
|
+
config.environments.client.define.ENV_CLIENT = true;
|
|
69
|
+
},
|
|
70
|
+
configResolved(config) {
|
|
71
|
+
const flatPlugins = config.plugins?.flat(10);
|
|
72
|
+
const astroBuildPlugin = flatPlugins?.find((obj) => {
|
|
73
|
+
return (
|
|
74
|
+
obj &&
|
|
75
|
+
typeof obj === "object" &&
|
|
76
|
+
"name" in obj &&
|
|
77
|
+
obj.name === "astro:build"
|
|
78
|
+
);
|
|
79
|
+
});
|
|
78
80
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
if (
|
|
82
|
+
astroBuildPlugin &&
|
|
83
|
+
"transform" in astroBuildPlugin &&
|
|
84
|
+
typeof astroBuildPlugin.transform === "object" &&
|
|
85
|
+
astroBuildPlugin.transform &&
|
|
86
|
+
"handler" in astroBuildPlugin.transform &&
|
|
87
|
+
typeof astroBuildPlugin.transform.handler === "function"
|
|
88
|
+
) {
|
|
89
|
+
astroBuildPlugin.transform.handler = wrapTransform(
|
|
90
|
+
astroBuildPlugin.transform.handler,
|
|
91
|
+
);
|
|
92
|
+
} else if (
|
|
93
|
+
astroBuildPlugin &&
|
|
94
|
+
"transform" in astroBuildPlugin &&
|
|
95
|
+
typeof astroBuildPlugin.transform === "function"
|
|
96
|
+
) {
|
|
97
|
+
astroBuildPlugin.transform = wrapTransform(
|
|
98
|
+
astroBuildPlugin.transform,
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
},
|
|
102
|
+
resolveId: {
|
|
103
|
+
order: "pre",
|
|
104
|
+
handler(id) {
|
|
105
|
+
if (id.startsWith("astro:")) {
|
|
106
|
+
const type = id
|
|
107
|
+
.replace("astro:", "")
|
|
108
|
+
.replace("/client", "")
|
|
109
|
+
.replace("/server", "");
|
|
85
110
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
111
|
+
let dir = "";
|
|
112
|
+
if (typeof __dirname !== "undefined") {
|
|
113
|
+
dir = __dirname;
|
|
114
|
+
} else {
|
|
115
|
+
dir = dirname(fileURLToPath(import.meta.url));
|
|
116
|
+
}
|
|
89
117
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
Object.entries(astroConfig?.env?.schema ?? {}).forEach(
|
|
94
|
-
([key, schema]) => {
|
|
95
|
-
if (
|
|
96
|
-
schema.context !== "client" ||
|
|
97
|
-
schema.access !== "public"
|
|
98
|
-
) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
118
|
+
if (type === "env" && id.endsWith("/server")) {
|
|
119
|
+
return join(dir, "modules", "secrets.js");
|
|
120
|
+
}
|
|
101
121
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
case "boolean":
|
|
105
|
-
contents += `export const ${key} = ${!!process.env[key]};\n`;
|
|
106
|
-
break;
|
|
107
|
-
case "number":
|
|
108
|
-
contents += `export const ${key} = ${Number(process.env[key])};\n`;
|
|
109
|
-
break;
|
|
110
|
-
default:
|
|
111
|
-
contents += `export const ${key} = ${JSON.stringify(process.env[key] ?? "")};\n`;
|
|
122
|
+
if (!SUPPORTED_VIRTUAL_MODULES.includes(type)) {
|
|
123
|
+
return;
|
|
112
124
|
}
|
|
113
|
-
|
|
114
|
-
|
|
125
|
+
|
|
126
|
+
return join(dir, "modules", `${type}.js`);
|
|
115
127
|
}
|
|
116
128
|
},
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
},
|
|
123
|
-
});
|
|
124
|
-
}
|
|
129
|
+
},
|
|
130
|
+
},
|
|
131
|
+
],
|
|
132
|
+
},
|
|
133
|
+
});
|
|
125
134
|
},
|
|
126
135
|
},
|
|
127
136
|
};
|
|
@@ -131,31 +131,44 @@ export const registerAstroComponent = (key, component) => {
|
|
|
131
131
|
props,
|
|
132
132
|
resolve: () => "editable-region-placeholder",
|
|
133
133
|
/**
|
|
134
|
-
* @param {*}
|
|
135
|
-
* @param {*} props
|
|
136
|
-
* @param {*} slots
|
|
134
|
+
* @param {*} args
|
|
137
135
|
*/
|
|
138
|
-
createAstro(
|
|
136
|
+
createAstro(...args) {
|
|
137
|
+
if (args.length < 2 || args.length > 3) {
|
|
138
|
+
console.warn(
|
|
139
|
+
`[CloudCannon] createAstro called with unexpected number of arguments (${args.length})`,
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
let astroGlobal = SSRResult;
|
|
144
|
+
let componentProps, componentSlots;
|
|
145
|
+
|
|
146
|
+
if (args.length === 2) {
|
|
147
|
+
[componentProps, componentSlots] = args;
|
|
148
|
+
} else {
|
|
149
|
+
[astroGlobal, componentProps, componentSlots] = args;
|
|
150
|
+
}
|
|
151
|
+
|
|
139
152
|
const astroSlots = {
|
|
140
153
|
/**
|
|
141
154
|
* @param {string} name
|
|
142
155
|
* @returns boolean
|
|
143
156
|
*/
|
|
144
157
|
has: (name) => {
|
|
145
|
-
if (!
|
|
146
|
-
return Boolean(
|
|
158
|
+
if (!componentSlots) return false;
|
|
159
|
+
return Boolean(componentSlots[name]);
|
|
147
160
|
},
|
|
148
161
|
/**
|
|
149
162
|
* @param {string} name
|
|
150
163
|
* @returns string
|
|
151
164
|
*/
|
|
152
165
|
render: (name) => {
|
|
153
|
-
return renderSlotToString(SSRResult,
|
|
166
|
+
return renderSlotToString(SSRResult, componentSlots[name]);
|
|
154
167
|
},
|
|
155
168
|
};
|
|
156
169
|
return {
|
|
157
170
|
__proto__: astroGlobal,
|
|
158
|
-
props,
|
|
171
|
+
props: componentProps,
|
|
159
172
|
slots: astroSlots,
|
|
160
173
|
request: new Request(window.location.href),
|
|
161
174
|
};
|
|
@@ -26,12 +26,18 @@ export const getCollection = async (collectionKey, filter) => {
|
|
|
26
26
|
slug = data.slug;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
const body = await file.get();
|
|
29
30
|
return {
|
|
30
31
|
collection: collectionKey,
|
|
31
32
|
id: id,
|
|
32
33
|
data: data,
|
|
33
34
|
slug: slug,
|
|
34
|
-
body:
|
|
35
|
+
body: body,
|
|
36
|
+
render: () => ({
|
|
37
|
+
Content: () => body ?? "Content is not available when live editing",
|
|
38
|
+
headings: [],
|
|
39
|
+
remarkPluginFrontmatter: {},
|
|
40
|
+
}),
|
|
35
41
|
};
|
|
36
42
|
});
|
|
37
43
|
|
|
@@ -249,8 +249,8 @@ export default class EditableArrayItem extends EditableComponent {
|
|
|
249
249
|
);
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
-
async update(): Promise<void> {
|
|
253
|
-
await super.update();
|
|
252
|
+
async update(partialSubtree?: ChildNode | null): Promise<void> {
|
|
253
|
+
await super.update(partialSubtree);
|
|
254
254
|
this.updateControls();
|
|
255
255
|
}
|
|
256
256
|
|
|
@@ -485,12 +485,12 @@ export default class EditableArrayItem extends EditableComponent {
|
|
|
485
485
|
}
|
|
486
486
|
}
|
|
487
487
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
}
|
|
488
|
+
getSpecialProps(
|
|
489
|
+
incomingSpecialProps: Record<string, unknown> = {},
|
|
490
|
+
): Record<string, unknown> {
|
|
491
|
+
return {
|
|
492
|
+
...super.getSpecialProps(incomingSpecialProps),
|
|
493
|
+
"@index": Number(this.element.dataset.prop),
|
|
494
|
+
};
|
|
495
495
|
}
|
|
496
496
|
}
|