@nordcraft/runtime 1.0.58 → 1.0.60
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/dist/components/createElement.js +1 -1
- package/dist/components/createElement.js.map +1 -1
- package/dist/components/createNode.js.map +1 -1
- package/dist/custom-element.main.esm.js +19 -19
- package/dist/custom-element.main.esm.js.map +3 -3
- package/dist/editor/input.d.ts +1 -0
- package/dist/editor/input.js +16 -0
- package/dist/editor/input.js.map +1 -0
- package/dist/editor/links.d.ts +6 -0
- package/dist/editor/links.js +15 -0
- package/dist/editor/links.js.map +1 -0
- package/dist/editor/overlay.d.ts +12 -0
- package/dist/editor/overlay.js +20 -0
- package/dist/editor/overlay.js.map +1 -0
- package/dist/editor/types.d.ts +254 -0
- package/dist/editor/types.js +42 -0
- package/dist/editor/types.js.map +1 -0
- package/dist/editor-preview.main.js +203 -291
- package/dist/editor-preview.main.js.map +1 -1
- package/dist/page.main.esm.js +2 -2
- package/dist/page.main.esm.js.map +3 -3
- package/dist/styles/CustomPropertyStyleSheet.test.js +12 -3
- package/dist/styles/CustomPropertyStyleSheet.test.js.map +1 -1
- package/package.json +4 -4
- package/src/components/createElement.ts +1 -1
- package/src/components/createNode.ts +0 -1
- package/src/editor/input.ts +17 -0
- package/src/editor/links.ts +16 -0
- package/src/editor/overlay.ts +21 -0
- package/src/editor/types.ts +271 -0
- package/src/editor-preview.main.ts +220 -498
- package/src/styles/CustomPropertyStyleSheet.test.ts +12 -3
- package/src/editor/types.d.ts +0 -36
|
@@ -3,12 +3,11 @@
|
|
|
3
3
|
/* eslint-disable no-case-declarations */
|
|
4
4
|
/* eslint-disable no-fallthrough */
|
|
5
5
|
import { isLegacyApi } from '@nordcraft/core/dist/api/api';
|
|
6
|
+
import { isLegacyPluginAction } from '@nordcraft/core/dist/component/actionUtils';
|
|
6
7
|
import { HeadTagTypes, } from '@nordcraft/core/dist/component/component.types';
|
|
7
8
|
import { isPageComponent } from '@nordcraft/core/dist/component/isPageComponent';
|
|
8
9
|
import { applyFormula, isToddleFormula, } from '@nordcraft/core/dist/formula/formula';
|
|
9
10
|
import {} from '@nordcraft/core/dist/formula/formulaTypes';
|
|
10
|
-
import { valueFormula } from '@nordcraft/core/dist/formula/formulaUtils';
|
|
11
|
-
import { getClassName } from '@nordcraft/core/dist/styling/className';
|
|
12
11
|
import { appendUnit } from '@nordcraft/core/dist/styling/customProperty';
|
|
13
12
|
import { getThemeCss, renderTheme } from '@nordcraft/core/dist/styling/theme';
|
|
14
13
|
import { mapObject, omitKeys } from '@nordcraft/core/dist/utils/collections';
|
|
@@ -28,55 +27,17 @@ import { dragMove } from './editor/drag-drop/dragMove';
|
|
|
28
27
|
import { dragReorder } from './editor/drag-drop/dragReorder';
|
|
29
28
|
import { dragStarted } from './editor/drag-drop/dragStarted';
|
|
30
29
|
import { introspectApiRequest } from './editor/graphql';
|
|
30
|
+
import { isInputTarget } from './editor/input';
|
|
31
|
+
import { updateComponentLinks } from './editor/links';
|
|
32
|
+
import { getRectData } from './editor/overlay';
|
|
33
|
+
import { TextNodeComputedStyles, } from './editor/types';
|
|
31
34
|
import { handleAction } from './events/handleAction';
|
|
32
35
|
import { signal } from './signal/signal';
|
|
33
36
|
import { insertStyles, styleToCss } from './styles/style';
|
|
34
37
|
import { createFormulaCache } from './utils/createFormulaCache';
|
|
35
38
|
import { getNodeAndAncestors, isNodeOrAncestorConditional } from './utils/nodes';
|
|
36
|
-
import { omitSubnodeStyleForComponent } from './utils/omitStyle';
|
|
37
39
|
import { rectHasPoint } from './utils/rectHasPoint';
|
|
38
40
|
import { getScrollStateRestorer, storeScrollState, } from './utils/storeScrollState';
|
|
39
|
-
/**
|
|
40
|
-
* Styles required for rendering the same exact text again somewhere else (on a overlay rect in the editor)
|
|
41
|
-
*/
|
|
42
|
-
var TextNodeComputedStyles;
|
|
43
|
-
(function (TextNodeComputedStyles) {
|
|
44
|
-
// Caret color is important as it is the only visible part of the text node (when text is not highlighted)
|
|
45
|
-
TextNodeComputedStyles["CARET_COLOR"] = "caret-color";
|
|
46
|
-
TextNodeComputedStyles["DISPLAY"] = "display";
|
|
47
|
-
TextNodeComputedStyles["FONT_FAMILY"] = "font-family";
|
|
48
|
-
TextNodeComputedStyles["FONT_SIZE"] = "font-size";
|
|
49
|
-
TextNodeComputedStyles["FONT_WEIGHT"] = "font-weight";
|
|
50
|
-
TextNodeComputedStyles["FONT_STYLE"] = "font-style";
|
|
51
|
-
TextNodeComputedStyles["FONT_VARIANT"] = "font-variant";
|
|
52
|
-
TextNodeComputedStyles["FONT_STRETCH"] = "font-stretch";
|
|
53
|
-
TextNodeComputedStyles["LINE_HEIGHT"] = "line-height";
|
|
54
|
-
TextNodeComputedStyles["TEXT_ALIGN"] = "text-align";
|
|
55
|
-
TextNodeComputedStyles["TEXT_TRANSFORM"] = "text-transform";
|
|
56
|
-
TextNodeComputedStyles["LETTER_SPACING"] = "letter-spacing";
|
|
57
|
-
TextNodeComputedStyles["WHITE_SPACE"] = "white-space";
|
|
58
|
-
TextNodeComputedStyles["WORD_SPACING"] = "word-spacing";
|
|
59
|
-
TextNodeComputedStyles["TEXT_INDENT"] = "text-indent";
|
|
60
|
-
TextNodeComputedStyles["TEXT_OVERFLOW"] = "text-overflow";
|
|
61
|
-
TextNodeComputedStyles["TEXT_RENDERING"] = "text-rendering";
|
|
62
|
-
TextNodeComputedStyles["WORD_BREAK"] = "word-break";
|
|
63
|
-
TextNodeComputedStyles["WORD_WRAP"] = "word-wrap";
|
|
64
|
-
TextNodeComputedStyles["DIRECTION"] = "direction";
|
|
65
|
-
TextNodeComputedStyles["UNICODE_BIDI"] = "unicode-bidi";
|
|
66
|
-
TextNodeComputedStyles["VERTICAL_ALIGN"] = "vertical-align";
|
|
67
|
-
TextNodeComputedStyles["FONT_KERNING"] = "font-kerning";
|
|
68
|
-
TextNodeComputedStyles["FONT_FEATURE_SETTINGS"] = "font-feature-settings";
|
|
69
|
-
TextNodeComputedStyles["FONT_VARIATION_SETTINGS"] = "font-variation-settings";
|
|
70
|
-
TextNodeComputedStyles["FONT_SMOOTHING"] = "-webkit-font-smoothing";
|
|
71
|
-
TextNodeComputedStyles["ANTI_ALIASING"] = "-moz-osx-font-smoothing";
|
|
72
|
-
TextNodeComputedStyles["FONT_OPTICAL_SIZING"] = "font-optical-sizing";
|
|
73
|
-
TextNodeComputedStyles["TAB_SIZE"] = "tab-size";
|
|
74
|
-
TextNodeComputedStyles["HYPHENS"] = "hyphens";
|
|
75
|
-
TextNodeComputedStyles["TEXT_ORIENTATION"] = "text-orientation";
|
|
76
|
-
TextNodeComputedStyles["WRITING_MODE"] = "writing-mode";
|
|
77
|
-
TextNodeComputedStyles["LINE_BREAK"] = "line-break";
|
|
78
|
-
TextNodeComputedStyles["OVERFLOW_WRAP"] = "overflow-wrap";
|
|
79
|
-
})(TextNodeComputedStyles || (TextNodeComputedStyles = {}));
|
|
80
41
|
let env;
|
|
81
42
|
export const initGlobalObject = () => {
|
|
82
43
|
env = {
|
|
@@ -159,37 +120,23 @@ export const initGlobalObject = () => {
|
|
|
159
120
|
: undefined));
|
|
160
121
|
Object.entries(libActions).forEach(([name, module]) => window.toddle.registerAction('@toddle/' + name, module.default));
|
|
161
122
|
};
|
|
123
|
+
const EMPTY_COMPONENT_DATA = {
|
|
124
|
+
Location: {
|
|
125
|
+
query: {},
|
|
126
|
+
params: {},
|
|
127
|
+
page: '/',
|
|
128
|
+
path: '/',
|
|
129
|
+
hash: '',
|
|
130
|
+
},
|
|
131
|
+
Attributes: {},
|
|
132
|
+
Variables: {},
|
|
133
|
+
};
|
|
162
134
|
// imported by "/.toddle/preview" (see worker/src/preview.ts)
|
|
163
135
|
export const createRoot = (domNode = document.getElementById('App')) => {
|
|
164
136
|
if (!domNode) {
|
|
165
137
|
throw new Error('Cant find root domNode');
|
|
166
138
|
}
|
|
167
|
-
const
|
|
168
|
-
const target = event.target;
|
|
169
|
-
if (target instanceof HTMLElement) {
|
|
170
|
-
if (target.tagName === 'INPUT' ||
|
|
171
|
-
target.tagName === 'TEXTAREA' ||
|
|
172
|
-
target.tagName === 'SELECT' ||
|
|
173
|
-
target.tagName === 'STYLE-EDITOR') {
|
|
174
|
-
return true;
|
|
175
|
-
}
|
|
176
|
-
if (target.contentEditable?.toLocaleLowerCase() === 'true') {
|
|
177
|
-
return true;
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
return false;
|
|
181
|
-
};
|
|
182
|
-
const dataSignal = signal({
|
|
183
|
-
Location: {
|
|
184
|
-
query: {},
|
|
185
|
-
params: {},
|
|
186
|
-
page: '/',
|
|
187
|
-
path: '/',
|
|
188
|
-
hash: '',
|
|
189
|
-
},
|
|
190
|
-
Attributes: {},
|
|
191
|
-
Variables: {},
|
|
192
|
-
});
|
|
139
|
+
const dataSignal = signal(EMPTY_COMPONENT_DATA);
|
|
193
140
|
let ctxDataSignal;
|
|
194
141
|
let ctx = null;
|
|
195
142
|
let mode = 'design';
|
|
@@ -219,63 +166,23 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
219
166
|
let metaKey = false;
|
|
220
167
|
let previewStyleAnimationFrame = -1;
|
|
221
168
|
let timelineTimeAnimationFrame = -1;
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
const registerActions = (allActions, packageName) => {
|
|
236
|
-
const actions = {};
|
|
237
|
-
Object.entries(allActions ?? {}).forEach(([name, action]) => {
|
|
238
|
-
if (typeof action.name === 'string' && action.version === undefined) {
|
|
239
|
-
// Legacy actions are self-registering. We need to execute them to register them
|
|
240
|
-
Function(action.handler)();
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
// We need to convert the handler string into a real function
|
|
244
|
-
actions[name] = {
|
|
245
|
-
...action,
|
|
246
|
-
handler: typeof action.handler === 'string'
|
|
247
|
-
? new Function('args, ctx', `${action.handler}
|
|
248
|
-
return ${safeFunctionName(action.name)}(args, ctx)`)
|
|
249
|
-
: action.handler,
|
|
250
|
-
};
|
|
251
|
-
});
|
|
252
|
-
window.toddle.actions[packageName ?? window.__toddle.project] = actions;
|
|
253
|
-
};
|
|
254
|
-
const registerFormulas = (allFormulas, packageName) => {
|
|
255
|
-
const formulas = {};
|
|
256
|
-
Object.entries(allFormulas ?? {}).forEach(([name, formula]) => {
|
|
257
|
-
if (!isToddleFormula(formula) &&
|
|
258
|
-
typeof formula.name === 'string' &&
|
|
259
|
-
formula.version === undefined) {
|
|
260
|
-
// Legacy formulas are self-registering. We need to execute them to register them
|
|
261
|
-
Function(formula.handler)();
|
|
262
|
-
return;
|
|
263
|
-
}
|
|
264
|
-
else if (!isToddleFormula(formula)) {
|
|
265
|
-
// For code formulas we need to convert the handler string into a real function
|
|
266
|
-
formulas[name] = {
|
|
267
|
-
...formula,
|
|
268
|
-
handler: typeof formula.handler === 'string'
|
|
269
|
-
? new Function('args, ctx', `${formula.handler}
|
|
270
|
-
return ${safeFunctionName(formula.name)}(args, ctx)`)
|
|
271
|
-
: formula.handler,
|
|
272
|
-
};
|
|
273
|
-
return;
|
|
169
|
+
const setupDataSignalSubscribers = () => {
|
|
170
|
+
dataSignal.subscribe((data) => {
|
|
171
|
+
if (component && components && packageComponents && data) {
|
|
172
|
+
try {
|
|
173
|
+
postMessageToEditor({ type: 'data', data });
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// If we're unable to send the data, let's try to JSON serialize it
|
|
177
|
+
postMessageToEditor({
|
|
178
|
+
type: 'data',
|
|
179
|
+
data: JSON.parse(JSON.stringify(data)),
|
|
180
|
+
});
|
|
181
|
+
}
|
|
274
182
|
}
|
|
275
|
-
formulas[name] = formula;
|
|
276
183
|
});
|
|
277
|
-
window.toddle.formulas[packageName ?? window.__toddle.project] = formulas;
|
|
278
184
|
};
|
|
185
|
+
setupDataSignalSubscribers();
|
|
279
186
|
window.addEventListener('message', async (message) => {
|
|
280
187
|
if (!message.isTrusted) {
|
|
281
188
|
console.error('UNTRUSTED MESSAGE');
|
|
@@ -287,9 +194,20 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
287
194
|
}
|
|
288
195
|
let scrollStateRestorer;
|
|
289
196
|
if (message.data.component.name !== component?.name) {
|
|
197
|
+
// Store scroll state for the previous component
|
|
290
198
|
storeScrollState(component?.name);
|
|
199
|
+
// Remove all subscribers from the previous showSignal
|
|
291
200
|
showSignal.cleanSubscribers();
|
|
201
|
+
// Clear any previously overridden conditional elements
|
|
202
|
+
showSignal.set({ displayedNodes: [], testMode: mode === 'test' });
|
|
203
|
+
// Restore scroll state for the new component
|
|
292
204
|
scrollStateRestorer = getScrollStateRestorer(message.data.component.name);
|
|
205
|
+
// Destroy the dataSignal (including subscribers) for the previous component
|
|
206
|
+
dataSignal.destroy();
|
|
207
|
+
// Re-subscribe all dataSignal subscribers
|
|
208
|
+
setupDataSignalSubscribers();
|
|
209
|
+
// Re-initialize the data signal for the new component
|
|
210
|
+
ctxDataSignal?.destroy();
|
|
293
211
|
}
|
|
294
212
|
component = updateComponentLinks(message.data.component);
|
|
295
213
|
if (components && packageComponents && ctx) {
|
|
@@ -339,7 +257,7 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
339
257
|
if (ctx) {
|
|
340
258
|
ctx.components = allComponents;
|
|
341
259
|
}
|
|
342
|
-
updateStyle();
|
|
260
|
+
updateStyle(component);
|
|
343
261
|
update();
|
|
344
262
|
}
|
|
345
263
|
break;
|
|
@@ -366,7 +284,7 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
366
284
|
if (ctx) {
|
|
367
285
|
ctx.components = allComponents;
|
|
368
286
|
}
|
|
369
|
-
updateStyle();
|
|
287
|
+
updateStyle(component);
|
|
370
288
|
update();
|
|
371
289
|
}
|
|
372
290
|
Object.values(message.data.packages ?? {}).forEach((pkg) => {
|
|
@@ -878,7 +796,7 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
878
796
|
window.addEventListener('beforeunload', () => {
|
|
879
797
|
storeScrollState(component?.name);
|
|
880
798
|
});
|
|
881
|
-
const updateStyle = () => {
|
|
799
|
+
const updateStyle = (component) => {
|
|
882
800
|
if (component) {
|
|
883
801
|
insertStyles(document.head, component, getAllComponents());
|
|
884
802
|
}
|
|
@@ -1157,68 +1075,49 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
1157
1075
|
}
|
|
1158
1076
|
}
|
|
1159
1077
|
if (fastDeepEqual(newCtx.component.nodes, ctx?.component?.nodes) === false) {
|
|
1160
|
-
updateStyle();
|
|
1078
|
+
updateStyle(newCtx.component);
|
|
1161
1079
|
// Remove preview styles automatically when the component changes
|
|
1162
1080
|
document.head.querySelector('[data-id="selected-node-styles"]')?.remove();
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
}
|
|
1081
|
+
Array.from(domNode.children).forEach((child) => {
|
|
1082
|
+
if (child.tagName !== 'SCRIPT') {
|
|
1083
|
+
child.remove();
|
|
1084
|
+
}
|
|
1085
|
+
});
|
|
1086
|
+
// Clear old root signal and create a new one to not keep old signals with previous root around
|
|
1087
|
+
ctxDataSignal?.destroy();
|
|
1088
|
+
ctxDataSignal = dataSignal.map((data) => data);
|
|
1089
|
+
try {
|
|
1090
|
+
const rootElem = createNode({
|
|
1091
|
+
id: 'root',
|
|
1092
|
+
path: '0',
|
|
1093
|
+
dataSignal: ctxDataSignal,
|
|
1094
|
+
ctx: newCtx,
|
|
1095
|
+
parentElement: domNode,
|
|
1096
|
+
instance: { [newCtx.component.name]: 'root' },
|
|
1179
1097
|
});
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
if (child.tagName !== 'SCRIPT') {
|
|
1184
|
-
child.remove();
|
|
1185
|
-
}
|
|
1098
|
+
newCtx.component.onLoad?.actions.forEach((action) => {
|
|
1099
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1100
|
+
handleAction(action, dataSignal.get(), newCtx);
|
|
1186
1101
|
});
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
1201
|
-
handleAction(action, dataSignal.get(), newCtx);
|
|
1202
|
-
});
|
|
1203
|
-
rootElem.forEach((elem) => domNode.appendChild(elem));
|
|
1102
|
+
rootElem.forEach((elem) => domNode.appendChild(elem));
|
|
1103
|
+
}
|
|
1104
|
+
catch (error) {
|
|
1105
|
+
const isPage = isPageComponent(newCtx.component);
|
|
1106
|
+
let name = `Unexpected error while rendering ${isPage ? 'page' : 'component'}`;
|
|
1107
|
+
let message = error instanceof Error ? error.message : String(error);
|
|
1108
|
+
let panic = false;
|
|
1109
|
+
if (error instanceof RangeError) {
|
|
1110
|
+
// RangeError is unrecoverable
|
|
1111
|
+
panic = true;
|
|
1112
|
+
name = 'Infinite loop detected';
|
|
1113
|
+
message =
|
|
1114
|
+
'RangeError (Maximum call stack size exceeded): Remove any circular dependencies or recursive calls (Try undoing your last change). This is most likely caused by a component, formula or action using itself.';
|
|
1204
1115
|
}
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
if (error instanceof RangeError) {
|
|
1211
|
-
// RangeError is unrecoverable
|
|
1212
|
-
panic = true;
|
|
1213
|
-
name = 'Infinite loop detected';
|
|
1214
|
-
message =
|
|
1215
|
-
'RangeError (Maximum call stack size exceeded): Remove any circular dependencies or recursive calls (Try undoing your last change). This is most likely caused by a component, formula or action using itself.';
|
|
1216
|
-
}
|
|
1217
|
-
// This can be triggered by setting "type" on a select etc.
|
|
1218
|
-
if (error instanceof TypeError) {
|
|
1219
|
-
panic = true;
|
|
1220
|
-
name = 'TypeError';
|
|
1221
|
-
message = `Type errors are often caused by:
|
|
1116
|
+
// This can be triggered by setting "type" on a select etc.
|
|
1117
|
+
if (error instanceof TypeError) {
|
|
1118
|
+
panic = true;
|
|
1119
|
+
name = 'TypeError';
|
|
1120
|
+
message = `Type errors are often caused by:
|
|
1222
1121
|
|
|
1223
1122
|
• Trying to set a read-only property (like "type" on a select element).
|
|
1224
1123
|
|
|
@@ -1227,34 +1126,33 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
1227
1126
|
• Trying to access a property on an undefined or null value.
|
|
1228
1127
|
|
|
1229
1128
|
• Trying to call a method on an undefined or null value.`;
|
|
1230
|
-
}
|
|
1231
|
-
console.error(name, message, error);
|
|
1232
|
-
if (panic) {
|
|
1233
|
-
// Show error overlay in the editor until next update
|
|
1234
|
-
const panicScreen = createPanicScreen({
|
|
1235
|
-
name: name,
|
|
1236
|
-
message,
|
|
1237
|
-
isPage,
|
|
1238
|
-
cause: error,
|
|
1239
|
-
});
|
|
1240
|
-
// Replace the inner HTML of the editor preview with the panic screen
|
|
1241
|
-
domNode.innerHTML = '';
|
|
1242
|
-
domNode.appendChild(panicScreen);
|
|
1243
|
-
}
|
|
1244
|
-
else {
|
|
1245
|
-
// Otherwise send a toast to the editor with the error (unknown errors may be recoverable), if not please add the error-type to the above
|
|
1246
|
-
sendEditorToast(name, message, {
|
|
1247
|
-
type: 'critical',
|
|
1248
|
-
});
|
|
1249
|
-
}
|
|
1250
1129
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1130
|
+
console.error(name, message, error);
|
|
1131
|
+
if (panic) {
|
|
1132
|
+
// Show error overlay in the editor until next update
|
|
1133
|
+
const panicScreen = createPanicScreen({
|
|
1134
|
+
name: name,
|
|
1135
|
+
message,
|
|
1136
|
+
isPage,
|
|
1137
|
+
cause: error,
|
|
1138
|
+
});
|
|
1139
|
+
// Replace the inner HTML of the editor preview with the panic screen
|
|
1140
|
+
domNode.innerHTML = '';
|
|
1141
|
+
domNode.appendChild(panicScreen);
|
|
1142
|
+
}
|
|
1143
|
+
else {
|
|
1144
|
+
// Otherwise send a toast to the editor with the error (unknown errors may be recoverable), if not please add the error-type to the above
|
|
1145
|
+
sendEditorToast(name, message, {
|
|
1146
|
+
type: 'critical',
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1257
1149
|
}
|
|
1150
|
+
postMessageToEditor({
|
|
1151
|
+
type: 'style',
|
|
1152
|
+
time: new Intl.DateTimeFormat('en-GB', {
|
|
1153
|
+
timeStyle: 'long',
|
|
1154
|
+
}).format(new Date()),
|
|
1155
|
+
});
|
|
1258
1156
|
}
|
|
1259
1157
|
ctx = newCtx;
|
|
1260
1158
|
scrollStateRestorer((nodeId) => document.querySelector(`[data-id="${nodeId}"]`));
|
|
@@ -1312,68 +1210,7 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
1312
1210
|
}
|
|
1313
1211
|
return ctx;
|
|
1314
1212
|
};
|
|
1315
|
-
|
|
1316
|
-
if (isInputTarget(event)) {
|
|
1317
|
-
return;
|
|
1318
|
-
}
|
|
1319
|
-
switch (event.key) {
|
|
1320
|
-
case 'k':
|
|
1321
|
-
if (event.metaKey) {
|
|
1322
|
-
event.preventDefault();
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
postMessageToEditor({
|
|
1326
|
-
type: 'keydown',
|
|
1327
|
-
event: {
|
|
1328
|
-
key: event.key,
|
|
1329
|
-
metaKey: event.metaKey,
|
|
1330
|
-
shiftKey: event.shiftKey,
|
|
1331
|
-
altKey: event.altKey,
|
|
1332
|
-
},
|
|
1333
|
-
});
|
|
1334
|
-
});
|
|
1335
|
-
document.addEventListener('keyup', (event) => {
|
|
1336
|
-
if (isInputTarget(event)) {
|
|
1337
|
-
return;
|
|
1338
|
-
}
|
|
1339
|
-
postMessageToEditor({
|
|
1340
|
-
type: 'keyup',
|
|
1341
|
-
event: {
|
|
1342
|
-
key: event.key,
|
|
1343
|
-
metaKey: event.metaKey,
|
|
1344
|
-
shiftKey: event.shiftKey,
|
|
1345
|
-
altKey: event.altKey,
|
|
1346
|
-
},
|
|
1347
|
-
});
|
|
1348
|
-
});
|
|
1349
|
-
document.addEventListener('keypress', (event) => {
|
|
1350
|
-
if (isInputTarget(event)) {
|
|
1351
|
-
return;
|
|
1352
|
-
}
|
|
1353
|
-
postMessageToEditor({
|
|
1354
|
-
type: 'keypress',
|
|
1355
|
-
event: {
|
|
1356
|
-
key: event.key,
|
|
1357
|
-
metaKey: event.metaKey,
|
|
1358
|
-
shiftKey: event.shiftKey,
|
|
1359
|
-
altKey: event.altKey,
|
|
1360
|
-
},
|
|
1361
|
-
});
|
|
1362
|
-
});
|
|
1363
|
-
dataSignal.subscribe((data) => {
|
|
1364
|
-
if (component && components && packageComponents && data) {
|
|
1365
|
-
try {
|
|
1366
|
-
postMessageToEditor({ type: 'data', data });
|
|
1367
|
-
}
|
|
1368
|
-
catch {
|
|
1369
|
-
// If we're unable to send the data, let's try to JSON serialize it
|
|
1370
|
-
postMessageToEditor({
|
|
1371
|
-
type: 'data',
|
|
1372
|
-
data: JSON.parse(JSON.stringify(data)),
|
|
1373
|
-
});
|
|
1374
|
-
}
|
|
1375
|
-
}
|
|
1376
|
-
});
|
|
1213
|
+
initKeyListeners();
|
|
1377
1214
|
const clearSelectedStyleVariant = () => {
|
|
1378
1215
|
if (styleVariantSelection) {
|
|
1379
1216
|
const styleElem = document.head.querySelector(`[data-hash="${styleVariantSelection.nodeId}"]`);
|
|
@@ -1420,25 +1257,6 @@ export const createRoot = (domNode = document.getElementById('App')) => {
|
|
|
1420
1257
|
requestAnimationFrame(() => syncOverlayRects(selectionRect, highlightRect));
|
|
1421
1258
|
})();
|
|
1422
1259
|
};
|
|
1423
|
-
function getRectData(selectedNode) {
|
|
1424
|
-
if (!selectedNode) {
|
|
1425
|
-
return null;
|
|
1426
|
-
}
|
|
1427
|
-
const { borderRadius, rotate } = window.getComputedStyle(selectedNode);
|
|
1428
|
-
const rect = selectedNode.getBoundingClientRect();
|
|
1429
|
-
return {
|
|
1430
|
-
left: rect.left,
|
|
1431
|
-
right: rect.right,
|
|
1432
|
-
top: rect.top,
|
|
1433
|
-
bottom: rect.bottom,
|
|
1434
|
-
width: rect.width,
|
|
1435
|
-
height: rect.height,
|
|
1436
|
-
x: rect.x,
|
|
1437
|
-
y: rect.y,
|
|
1438
|
-
borderRadius: borderRadius.split(' '),
|
|
1439
|
-
rotate,
|
|
1440
|
-
};
|
|
1441
|
-
}
|
|
1442
1260
|
const insertOrReplaceHeadNode = (id, node) => {
|
|
1443
1261
|
const existing = document.head.querySelector(`[data-meta-id="${id}"]`);
|
|
1444
1262
|
if (existing) {
|
|
@@ -1514,6 +1332,100 @@ const insertTheme = (parent, themes) => {
|
|
|
1514
1332
|
});
|
|
1515
1333
|
parent.appendChild(styleElem);
|
|
1516
1334
|
};
|
|
1335
|
+
const initKeyListeners = () => {
|
|
1336
|
+
document.addEventListener('keydown', (event) => {
|
|
1337
|
+
if (isInputTarget(event)) {
|
|
1338
|
+
return;
|
|
1339
|
+
}
|
|
1340
|
+
switch (event.key) {
|
|
1341
|
+
case 'k':
|
|
1342
|
+
if (event.metaKey) {
|
|
1343
|
+
event.preventDefault();
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
postMessageToEditor({
|
|
1347
|
+
type: 'keydown',
|
|
1348
|
+
event: {
|
|
1349
|
+
key: event.key,
|
|
1350
|
+
metaKey: event.metaKey,
|
|
1351
|
+
shiftKey: event.shiftKey,
|
|
1352
|
+
altKey: event.altKey,
|
|
1353
|
+
},
|
|
1354
|
+
});
|
|
1355
|
+
});
|
|
1356
|
+
document.addEventListener('keyup', (event) => {
|
|
1357
|
+
if (isInputTarget(event)) {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
postMessageToEditor({
|
|
1361
|
+
type: 'keyup',
|
|
1362
|
+
event: {
|
|
1363
|
+
key: event.key,
|
|
1364
|
+
metaKey: event.metaKey,
|
|
1365
|
+
shiftKey: event.shiftKey,
|
|
1366
|
+
altKey: event.altKey,
|
|
1367
|
+
},
|
|
1368
|
+
});
|
|
1369
|
+
});
|
|
1370
|
+
document.addEventListener('keypress', (event) => {
|
|
1371
|
+
if (isInputTarget(event)) {
|
|
1372
|
+
return;
|
|
1373
|
+
}
|
|
1374
|
+
postMessageToEditor({
|
|
1375
|
+
type: 'keypress',
|
|
1376
|
+
event: {
|
|
1377
|
+
key: event.key,
|
|
1378
|
+
metaKey: event.metaKey,
|
|
1379
|
+
shiftKey: event.shiftKey,
|
|
1380
|
+
altKey: event.altKey,
|
|
1381
|
+
},
|
|
1382
|
+
});
|
|
1383
|
+
});
|
|
1384
|
+
};
|
|
1385
|
+
const registerActions = (allActions, packageName) => {
|
|
1386
|
+
const actions = {};
|
|
1387
|
+
Object.entries(allActions ?? {}).forEach(([name, action]) => {
|
|
1388
|
+
if (isLegacyPluginAction(action)) {
|
|
1389
|
+
// Legacy actions are self-registering. We need to execute them to register them
|
|
1390
|
+
Function(action.handler)();
|
|
1391
|
+
return;
|
|
1392
|
+
}
|
|
1393
|
+
// We need to convert the handler string into a real function
|
|
1394
|
+
actions[name] = {
|
|
1395
|
+
...action,
|
|
1396
|
+
handler: typeof action.handler === 'string'
|
|
1397
|
+
? new Function('args, ctx', `${action.handler}
|
|
1398
|
+
return ${safeFunctionName(action.name)}(args, ctx)`)
|
|
1399
|
+
: action.handler,
|
|
1400
|
+
};
|
|
1401
|
+
});
|
|
1402
|
+
window.toddle.actions[packageName ?? window.__toddle.project] = actions;
|
|
1403
|
+
};
|
|
1404
|
+
const registerFormulas = (allFormulas, packageName) => {
|
|
1405
|
+
const formulas = {};
|
|
1406
|
+
Object.entries(allFormulas ?? {}).forEach(([name, formula]) => {
|
|
1407
|
+
if (!isToddleFormula(formula) &&
|
|
1408
|
+
typeof formula.name === 'string' &&
|
|
1409
|
+
formula.version === undefined) {
|
|
1410
|
+
// Legacy formulas are self-registering. We need to execute them to register them
|
|
1411
|
+
Function(formula.handler)();
|
|
1412
|
+
return;
|
|
1413
|
+
}
|
|
1414
|
+
else if (!isToddleFormula(formula)) {
|
|
1415
|
+
// For code formulas we need to convert the handler string into a real function
|
|
1416
|
+
formulas[name] = {
|
|
1417
|
+
...formula,
|
|
1418
|
+
handler: typeof formula.handler === 'string'
|
|
1419
|
+
? new Function('args, ctx', `${formula.handler}
|
|
1420
|
+
return ${safeFunctionName(formula.name)}(args, ctx)`)
|
|
1421
|
+
: formula.handler,
|
|
1422
|
+
};
|
|
1423
|
+
return;
|
|
1424
|
+
}
|
|
1425
|
+
formulas[name] = formula;
|
|
1426
|
+
});
|
|
1427
|
+
window.toddle.formulas[packageName ?? window.__toddle.project] = formulas;
|
|
1428
|
+
};
|
|
1517
1429
|
const postMessageToEditor = (message) => {
|
|
1518
1430
|
window.parent?.postMessage(message, '*');
|
|
1519
1431
|
};
|