@no-mess/client 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -3
- package/dist/client.d.ts +5 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +237 -41
- package/dist/client.js.map +1 -1
- package/dist/error-utils.d.ts +20 -0
- package/dist/error-utils.d.ts.map +1 -0
- package/dist/error-utils.js +67 -0
- package/dist/error-utils.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +148 -22
- package/dist/index.js.map +1 -1
- package/dist/live-edit.d.ts.map +1 -1
- package/dist/live-edit.js +241 -102
- package/dist/live-edit.js.map +1 -1
- package/dist/logging.d.ts +6 -0
- package/dist/logging.d.ts.map +1 -0
- package/dist/logging.js +58 -0
- package/dist/logging.js.map +1 -0
- package/dist/react/index.d.ts +1 -1
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react/no-mess-preview.d.ts +2 -6
- package/dist/react/no-mess-preview.d.ts.map +1 -1
- package/dist/react/no-mess-preview.js.map +1 -1
- package/dist/react/use-no-mess-live-edit.d.ts.map +1 -1
- package/dist/react/use-no-mess-live-edit.js +32 -2
- package/dist/react/use-no-mess-live-edit.js.map +1 -1
- package/dist/react/use-no-mess-preview.d.ts.map +1 -1
- package/dist/react/use-no-mess-preview.js +29 -6
- package/dist/react/use-no-mess-preview.js.map +1 -1
- package/dist/types.d.ts +49 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +22 -4
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,6 +2,8 @@ export { NoMessClient } from "./client.js";
|
|
|
2
2
|
export { createLiveEditHandler } from "./live-edit.js";
|
|
3
3
|
export { DEFAULT_ADMIN_ORIGIN, DEFAULT_API_URL, isPublishableKey, isSecretKey, NoMessError, } from "./types.js";
|
|
4
4
|
import { NoMessClient } from "./client.js";
|
|
5
|
+
import { createNoMessProtocolError, normalizeNoMessError, } from "./error-utils.js";
|
|
6
|
+
import { createSdkLogger } from "./logging.js";
|
|
5
7
|
/**
|
|
6
8
|
* Create a no-mess client instance.
|
|
7
9
|
*/
|
|
@@ -25,48 +27,172 @@ export function createNoMessClient(config) {
|
|
|
25
27
|
* ```
|
|
26
28
|
*/
|
|
27
29
|
export function createPreviewHandler(config) {
|
|
30
|
+
const logger = createSdkLogger(config.logger);
|
|
28
31
|
let sessionAuth = null;
|
|
32
|
+
let disposed = false;
|
|
33
|
+
let inFlightRequestId = 0;
|
|
34
|
+
let latestCompletedRequestId = 0;
|
|
35
|
+
const logEvent = (level, code, message, context, error) => {
|
|
36
|
+
logger({
|
|
37
|
+
level,
|
|
38
|
+
code,
|
|
39
|
+
message,
|
|
40
|
+
scope: "preview",
|
|
41
|
+
operation: "createPreviewHandler",
|
|
42
|
+
error: error instanceof Error ? error : undefined,
|
|
43
|
+
timestamp: new Date().toISOString(),
|
|
44
|
+
context,
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const invokeOnError = (error) => {
|
|
48
|
+
try {
|
|
49
|
+
config.onError?.(error);
|
|
50
|
+
}
|
|
51
|
+
catch (callbackError) {
|
|
52
|
+
logEvent("error", "preview_exchange_failed", "Preview onError callback threw unexpectedly", {}, normalizeNoMessError(callbackError, {
|
|
53
|
+
kind: "runtime",
|
|
54
|
+
code: "preview_exchange_failed",
|
|
55
|
+
operation: "preview.onError",
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const postToParent = (message, origin, context) => {
|
|
60
|
+
try {
|
|
61
|
+
window.parent.postMessage(message, origin);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const normalized = normalizeNoMessError(error, {
|
|
66
|
+
kind: "runtime",
|
|
67
|
+
code: "preview_postmessage_failed",
|
|
68
|
+
operation: "preview.postMessage",
|
|
69
|
+
details: context,
|
|
70
|
+
});
|
|
71
|
+
logEvent("error", normalized.code, "Failed to post preview message to parent window", {
|
|
72
|
+
...context,
|
|
73
|
+
targetOrigin: origin,
|
|
74
|
+
}, normalized);
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
const emitPreviewError = (error, origin, context) => {
|
|
79
|
+
invokeOnError(error);
|
|
80
|
+
const normalized = normalizeNoMessError(error, {
|
|
81
|
+
kind: "runtime",
|
|
82
|
+
code: "preview_exchange_failed",
|
|
83
|
+
operation: "preview.emitError",
|
|
84
|
+
details: context,
|
|
85
|
+
});
|
|
86
|
+
logEvent("error", normalized.code, normalized.message, context, normalized);
|
|
87
|
+
postToParent({
|
|
88
|
+
type: "no-mess:preview-error",
|
|
89
|
+
error: normalized.message,
|
|
90
|
+
code: normalized.code,
|
|
91
|
+
status: normalized.status,
|
|
92
|
+
retryable: normalized.retryable,
|
|
93
|
+
}, origin, context);
|
|
94
|
+
};
|
|
95
|
+
const runExchange = async (reason, origin) => {
|
|
96
|
+
if (!sessionAuth) {
|
|
97
|
+
logEvent("debug", "preview_message_invalid", "Preview refresh ignored because no session is available", {
|
|
98
|
+
reason,
|
|
99
|
+
});
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const requestId = ++inFlightRequestId;
|
|
103
|
+
try {
|
|
104
|
+
const result = await config.client.exchangePreviewSession(sessionAuth);
|
|
105
|
+
if (disposed ||
|
|
106
|
+
requestId < inFlightRequestId ||
|
|
107
|
+
requestId <= latestCompletedRequestId) {
|
|
108
|
+
logEvent("debug", "preview_exchange_failed", "Discarded stale preview exchange result", {
|
|
109
|
+
reason,
|
|
110
|
+
requestId,
|
|
111
|
+
inFlightRequestId,
|
|
112
|
+
latestCompletedRequestId,
|
|
113
|
+
});
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
latestCompletedRequestId = requestId;
|
|
117
|
+
try {
|
|
118
|
+
config.onEntry(result.entry);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
emitPreviewError(normalizeNoMessError(error, {
|
|
122
|
+
kind: "runtime",
|
|
123
|
+
code: "preview_exchange_failed",
|
|
124
|
+
operation: "preview.onEntry",
|
|
125
|
+
details: { reason },
|
|
126
|
+
}), origin, { reason, requestId, phase: "onEntry" });
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
postToParent({ type: "no-mess:preview-loaded" }, origin, { reason, requestId, phase: "loaded" });
|
|
130
|
+
}
|
|
131
|
+
catch (error) {
|
|
132
|
+
if (disposed ||
|
|
133
|
+
requestId < inFlightRequestId ||
|
|
134
|
+
requestId <= latestCompletedRequestId) {
|
|
135
|
+
logEvent("debug", "preview_exchange_failed", "Discarded stale preview exchange error", {
|
|
136
|
+
reason,
|
|
137
|
+
requestId,
|
|
138
|
+
inFlightRequestId,
|
|
139
|
+
latestCompletedRequestId,
|
|
140
|
+
});
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
latestCompletedRequestId = requestId;
|
|
144
|
+
emitPreviewError(normalizeNoMessError(error, {
|
|
145
|
+
kind: "runtime",
|
|
146
|
+
code: "preview_exchange_failed",
|
|
147
|
+
operation: "preview.exchange",
|
|
148
|
+
details: { reason },
|
|
149
|
+
}), origin, { reason, requestId, phase: "exchange" });
|
|
150
|
+
}
|
|
151
|
+
};
|
|
29
152
|
const handleMessage = async (event) => {
|
|
30
|
-
if (event.origin !== config.adminOrigin)
|
|
153
|
+
if (disposed || event.origin !== config.adminOrigin)
|
|
31
154
|
return;
|
|
32
155
|
const data = event.data;
|
|
33
156
|
if (!data || typeof data.type !== "string")
|
|
34
157
|
return;
|
|
35
158
|
if (data.type === "no-mess:session-auth") {
|
|
159
|
+
if (typeof data.sessionId !== "string" ||
|
|
160
|
+
typeof data.sessionSecret !== "string") {
|
|
161
|
+
emitPreviewError(createNoMessProtocolError("Received invalid preview session credentials", {
|
|
162
|
+
kind: "protocol",
|
|
163
|
+
code: "preview_message_invalid",
|
|
164
|
+
operation: "preview.session-auth",
|
|
165
|
+
details: {
|
|
166
|
+
receivedKeys: data && typeof data === "object" ? Object.keys(data) : [],
|
|
167
|
+
},
|
|
168
|
+
}), event.origin, { type: data.type });
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
36
171
|
sessionAuth = {
|
|
37
172
|
sessionId: data.sessionId,
|
|
38
173
|
sessionSecret: data.sessionSecret,
|
|
39
174
|
};
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
config.onEntry(result.entry);
|
|
43
|
-
window.parent.postMessage({ type: "no-mess:preview-loaded" }, event.origin);
|
|
44
|
-
}
|
|
45
|
-
catch (err) {
|
|
46
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
47
|
-
config.onError?.(error);
|
|
48
|
-
window.parent.postMessage({ type: "no-mess:preview-error", error: error.message }, event.origin);
|
|
49
|
-
}
|
|
175
|
+
await runExchange("session-auth", event.origin);
|
|
176
|
+
return;
|
|
50
177
|
}
|
|
51
|
-
if (data.type === "no-mess:refresh"
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
catch (err) {
|
|
58
|
-
const error = err instanceof Error ? err : new Error(String(err));
|
|
59
|
-
config.onError?.(error);
|
|
60
|
-
window.parent.postMessage({ type: "no-mess:preview-error", error: error.message }, event.origin);
|
|
178
|
+
if (data.type === "no-mess:refresh") {
|
|
179
|
+
if (!sessionAuth) {
|
|
180
|
+
logEvent("debug", "preview_message_invalid", "Ignored preview refresh before session authentication", {
|
|
181
|
+
type: data.type,
|
|
182
|
+
});
|
|
183
|
+
return;
|
|
61
184
|
}
|
|
185
|
+
await runExchange("refresh", event.origin);
|
|
62
186
|
}
|
|
63
187
|
};
|
|
64
188
|
return {
|
|
65
189
|
start: () => {
|
|
190
|
+
disposed = false;
|
|
66
191
|
window.addEventListener("message", handleMessage);
|
|
67
|
-
|
|
192
|
+
postToParent({ type: "no-mess:preview-ready" }, "*", { phase: "ready" });
|
|
68
193
|
},
|
|
69
194
|
cleanup: () => {
|
|
195
|
+
disposed = true;
|
|
70
196
|
window.removeEventListener("message", handleMessage);
|
|
71
197
|
},
|
|
72
198
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/live-edit.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live-edit.d.ts","sourceRoot":"","sources":["../src/live-edit.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"live-edit.d.ts","sourceRoot":"","sources":["../src/live-edit.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAyFjE;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,cAAc,GAAG,cAAc,CA+Y5E"}
|
package/dist/live-edit.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { normalizeNoMessError } from "./error-utils.js";
|
|
2
|
+
import { createSdkLogger } from "./logging.js";
|
|
1
3
|
const OVERLAY_CONTAINER_ID = "no-mess-live-edit-overlays";
|
|
2
4
|
const OVERLAY_ATTR = "data-no-mess-overlay-for";
|
|
3
5
|
const FIELD_ATTR = "data-no-mess-field";
|
|
@@ -45,6 +47,22 @@ const OVERLAY_CSS = `
|
|
|
45
47
|
background: oklch(0.546 0.245 262.9);
|
|
46
48
|
}
|
|
47
49
|
`;
|
|
50
|
+
function serializeRect(rect) {
|
|
51
|
+
const rectWithJson = rect;
|
|
52
|
+
if (typeof rectWithJson.toJSON === "function") {
|
|
53
|
+
return rectWithJson.toJSON();
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
x: rect.x,
|
|
57
|
+
y: rect.y,
|
|
58
|
+
width: rect.width,
|
|
59
|
+
height: rect.height,
|
|
60
|
+
top: rect.top,
|
|
61
|
+
right: rect.right,
|
|
62
|
+
bottom: rect.bottom,
|
|
63
|
+
left: rect.left,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
48
66
|
/**
|
|
49
67
|
* Create a live edit handler that manages overlay highlights on annotated DOM
|
|
50
68
|
* elements and communicates with the admin dashboard via postMessage.
|
|
@@ -58,6 +76,7 @@ const OVERLAY_CSS = `
|
|
|
58
76
|
* ```
|
|
59
77
|
*/
|
|
60
78
|
export function createLiveEditHandler(config) {
|
|
79
|
+
const logger = createSdkLogger(config.logger);
|
|
61
80
|
let active = false;
|
|
62
81
|
let container = null;
|
|
63
82
|
let styleEl = null;
|
|
@@ -66,6 +85,55 @@ export function createLiveEditHandler(config) {
|
|
|
66
85
|
let mutationObserver = null;
|
|
67
86
|
let scrollListener = null;
|
|
68
87
|
let rafId = null;
|
|
88
|
+
const emitLog = (level, message, context, error) => {
|
|
89
|
+
logger({
|
|
90
|
+
level,
|
|
91
|
+
code: "live_edit_runtime_failed",
|
|
92
|
+
message,
|
|
93
|
+
scope: "live-edit",
|
|
94
|
+
operation: "createLiveEditHandler",
|
|
95
|
+
error: error instanceof Error ? error : undefined,
|
|
96
|
+
timestamp: new Date().toISOString(),
|
|
97
|
+
context,
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
const reportRuntimeError = (error, context, message = "Live edit runtime failure") => {
|
|
101
|
+
const normalized = normalizeNoMessError(error, {
|
|
102
|
+
kind: "runtime",
|
|
103
|
+
code: "live_edit_runtime_failed",
|
|
104
|
+
operation: "live-edit",
|
|
105
|
+
details: context,
|
|
106
|
+
});
|
|
107
|
+
try {
|
|
108
|
+
config.onError?.(normalized);
|
|
109
|
+
}
|
|
110
|
+
catch (callbackError) {
|
|
111
|
+
emitLog("error", "Live edit onError callback threw unexpectedly", context, normalizeNoMessError(callbackError, {
|
|
112
|
+
kind: "runtime",
|
|
113
|
+
code: "live_edit_runtime_failed",
|
|
114
|
+
operation: "live-edit.onError",
|
|
115
|
+
}));
|
|
116
|
+
}
|
|
117
|
+
emitLog("error", message, context, normalized);
|
|
118
|
+
};
|
|
119
|
+
const safeInvoke = (callback, context, message) => {
|
|
120
|
+
if (!callback)
|
|
121
|
+
return;
|
|
122
|
+
try {
|
|
123
|
+
callback();
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
reportRuntimeError(error, context, message);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
const safePostMessage = (message, context) => {
|
|
130
|
+
try {
|
|
131
|
+
window.parent.postMessage(message, config.adminOrigin);
|
|
132
|
+
}
|
|
133
|
+
catch (error) {
|
|
134
|
+
reportRuntimeError(error, context, "Failed to post live edit message");
|
|
135
|
+
}
|
|
136
|
+
};
|
|
69
137
|
function injectStyles() {
|
|
70
138
|
if (document.getElementById("no-mess-live-edit-styles"))
|
|
71
139
|
return;
|
|
@@ -113,105 +181,151 @@ export function createLiveEditHandler(config) {
|
|
|
113
181
|
return;
|
|
114
182
|
rafId = requestAnimationFrame(() => {
|
|
115
183
|
rafId = null;
|
|
116
|
-
|
|
184
|
+
try {
|
|
185
|
+
updateAllPositions();
|
|
186
|
+
}
|
|
187
|
+
catch (error) {
|
|
188
|
+
reportRuntimeError(error, { phase: "updateAllPositions" });
|
|
189
|
+
}
|
|
117
190
|
});
|
|
118
191
|
}
|
|
119
192
|
function buildOverlays() {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
193
|
+
try {
|
|
194
|
+
for (const entry of overlays) {
|
|
195
|
+
entry.overlay.remove();
|
|
196
|
+
}
|
|
197
|
+
overlays = [];
|
|
198
|
+
if (!container)
|
|
199
|
+
return;
|
|
200
|
+
const fieldElements = getFieldElements();
|
|
201
|
+
const fieldRects = [];
|
|
202
|
+
for (const [fieldName, elements] of fieldElements) {
|
|
203
|
+
for (const element of elements) {
|
|
204
|
+
const overlay = document.createElement("div");
|
|
205
|
+
overlay.className = "no-mess-overlay";
|
|
206
|
+
overlay.setAttribute(OVERLAY_ATTR, fieldName);
|
|
207
|
+
const label = document.createElement("span");
|
|
208
|
+
label.className = "no-mess-overlay-label";
|
|
209
|
+
label.textContent = fieldName;
|
|
210
|
+
overlay.appendChild(label);
|
|
211
|
+
positionOverlay(overlay, element);
|
|
212
|
+
overlay.addEventListener("click", () => {
|
|
213
|
+
safePostMessage({ type: "no-mess:field-clicked", fieldName }, { phase: "field-clicked", fieldName });
|
|
214
|
+
try {
|
|
215
|
+
config.onFieldClicked?.(fieldName);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
reportRuntimeError(error, { phase: "field-clicked", fieldName });
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
container.appendChild(overlay);
|
|
222
|
+
overlays.push({ element, overlay, fieldName });
|
|
223
|
+
const rect = element.getBoundingClientRect();
|
|
224
|
+
fieldRects.push({ fieldName, rect: serializeRect(rect) });
|
|
225
|
+
resizeObserver?.observe(element);
|
|
226
|
+
}
|
|
149
227
|
}
|
|
228
|
+
const uniqueFields = [...new Set(fieldRects.map((field) => field.fieldName))];
|
|
229
|
+
safePostMessage({
|
|
230
|
+
type: "no-mess:field-map",
|
|
231
|
+
fields: uniqueFields.map((fieldName) => {
|
|
232
|
+
const match = fieldRects.find((field) => field.fieldName === fieldName);
|
|
233
|
+
return { fieldName, rect: match?.rect };
|
|
234
|
+
}),
|
|
235
|
+
}, { phase: "field-map", count: uniqueFields.length });
|
|
236
|
+
}
|
|
237
|
+
catch (error) {
|
|
238
|
+
reportRuntimeError(error, { phase: "buildOverlays" }, "Failed to build live edit overlays");
|
|
150
239
|
}
|
|
151
|
-
// Send field map to admin
|
|
152
|
-
const uniqueFields = [...new Set(fieldRects.map((f) => f.fieldName))];
|
|
153
|
-
window.parent.postMessage({
|
|
154
|
-
type: "no-mess:field-map",
|
|
155
|
-
fields: uniqueFields.map((fieldName) => {
|
|
156
|
-
const match = fieldRects.find((f) => f.fieldName === fieldName);
|
|
157
|
-
return { fieldName, rect: match?.rect };
|
|
158
|
-
}),
|
|
159
|
-
}, config.adminOrigin);
|
|
160
240
|
}
|
|
161
241
|
function enterLiveEdit() {
|
|
162
242
|
if (active)
|
|
163
243
|
return;
|
|
164
244
|
active = true;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
245
|
+
try {
|
|
246
|
+
injectStyles();
|
|
247
|
+
createContainer();
|
|
248
|
+
if (typeof ResizeObserver !== "undefined") {
|
|
249
|
+
resizeObserver = new ResizeObserver(() => {
|
|
250
|
+
try {
|
|
251
|
+
schedulePositionUpdate();
|
|
252
|
+
}
|
|
253
|
+
catch (error) {
|
|
254
|
+
reportRuntimeError(error, { phase: "resizeObserver" });
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
else {
|
|
259
|
+
emitLog("warn", "ResizeObserver is not available; live edit overlays will fall back to scroll/resize updates only", {
|
|
260
|
+
feature: "ResizeObserver",
|
|
261
|
+
});
|
|
262
|
+
}
|
|
263
|
+
buildOverlays();
|
|
264
|
+
scrollListener = () => {
|
|
265
|
+
try {
|
|
266
|
+
schedulePositionUpdate();
|
|
267
|
+
}
|
|
268
|
+
catch (error) {
|
|
269
|
+
reportRuntimeError(error, { phase: "scrollListener" });
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
window.addEventListener("scroll", scrollListener, { passive: true });
|
|
273
|
+
window.addEventListener("resize", scrollListener, { passive: true });
|
|
274
|
+
if (typeof MutationObserver !== "undefined") {
|
|
275
|
+
mutationObserver = new MutationObserver(() => {
|
|
276
|
+
setTimeout(() => {
|
|
277
|
+
if (!active)
|
|
278
|
+
return;
|
|
279
|
+
buildOverlays();
|
|
280
|
+
}, 100);
|
|
281
|
+
});
|
|
282
|
+
mutationObserver.observe(document.body, {
|
|
283
|
+
childList: true,
|
|
284
|
+
subtree: true,
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
else {
|
|
288
|
+
emitLog("warn", "MutationObserver is not available; live edit overlays will not auto-refresh for DOM changes", {
|
|
289
|
+
feature: "MutationObserver",
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
safeInvoke(config.onEnter, { phase: "enter" }, "Live edit onEnter callback threw unexpectedly");
|
|
293
|
+
}
|
|
294
|
+
catch (error) {
|
|
295
|
+
reportRuntimeError(error, { phase: "enterLiveEdit" });
|
|
296
|
+
}
|
|
188
297
|
}
|
|
189
298
|
function exitLiveEdit() {
|
|
190
299
|
if (!active)
|
|
191
300
|
return;
|
|
192
301
|
active = false;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
302
|
+
try {
|
|
303
|
+
if (rafId !== null) {
|
|
304
|
+
cancelAnimationFrame(rafId);
|
|
305
|
+
rafId = null;
|
|
306
|
+
}
|
|
307
|
+
resizeObserver?.disconnect();
|
|
308
|
+
resizeObserver = null;
|
|
309
|
+
mutationObserver?.disconnect();
|
|
310
|
+
mutationObserver = null;
|
|
311
|
+
if (scrollListener) {
|
|
312
|
+
window.removeEventListener("scroll", scrollListener);
|
|
313
|
+
window.removeEventListener("resize", scrollListener);
|
|
314
|
+
scrollListener = null;
|
|
315
|
+
}
|
|
316
|
+
for (const entry of overlays) {
|
|
317
|
+
entry.overlay.remove();
|
|
318
|
+
}
|
|
319
|
+
overlays = [];
|
|
320
|
+
container?.remove();
|
|
321
|
+
container = null;
|
|
322
|
+
styleEl?.remove();
|
|
323
|
+
styleEl = null;
|
|
324
|
+
safeInvoke(config.onExit, { phase: "exit" }, "Live edit onExit callback threw unexpectedly");
|
|
196
325
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
mutationObserver?.disconnect();
|
|
200
|
-
mutationObserver = null;
|
|
201
|
-
if (scrollListener) {
|
|
202
|
-
window.removeEventListener("scroll", scrollListener);
|
|
203
|
-
window.removeEventListener("resize", scrollListener);
|
|
204
|
-
scrollListener = null;
|
|
326
|
+
catch (error) {
|
|
327
|
+
reportRuntimeError(error, { phase: "exitLiveEdit" });
|
|
205
328
|
}
|
|
206
|
-
for (const entry of overlays) {
|
|
207
|
-
entry.overlay.remove();
|
|
208
|
-
}
|
|
209
|
-
overlays = [];
|
|
210
|
-
container?.remove();
|
|
211
|
-
container = null;
|
|
212
|
-
styleEl?.remove();
|
|
213
|
-
styleEl = null;
|
|
214
|
-
config.onExit?.();
|
|
215
329
|
}
|
|
216
330
|
function handleFieldUpdate(fieldName, value) {
|
|
217
331
|
const elements = document.querySelectorAll(`[${FIELD_ATTR}="${fieldName}"]`);
|
|
@@ -252,31 +366,56 @@ export function createLiveEditHandler(config) {
|
|
|
252
366
|
const data = event.data;
|
|
253
367
|
if (!data || typeof data.type !== "string")
|
|
254
368
|
return;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
369
|
+
try {
|
|
370
|
+
switch (data.type) {
|
|
371
|
+
case "no-mess:live-edit-enter":
|
|
372
|
+
enterLiveEdit();
|
|
373
|
+
break;
|
|
374
|
+
case "no-mess:live-edit-exit":
|
|
375
|
+
exitLiveEdit();
|
|
376
|
+
break;
|
|
377
|
+
case "no-mess:field-updated":
|
|
378
|
+
if (!active)
|
|
379
|
+
break;
|
|
380
|
+
if (typeof data.fieldName !== "string") {
|
|
381
|
+
emitLog("debug", "Ignored malformed live edit field update message", {
|
|
382
|
+
type: data.type,
|
|
383
|
+
});
|
|
384
|
+
break;
|
|
385
|
+
}
|
|
264
386
|
handleFieldUpdate(data.fieldName, data.value);
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
387
|
+
break;
|
|
388
|
+
case "no-mess:field-focus":
|
|
389
|
+
if (!active)
|
|
390
|
+
break;
|
|
391
|
+
if (typeof data.fieldName !== "string") {
|
|
392
|
+
emitLog("debug", "Ignored malformed live edit focus message", {
|
|
393
|
+
type: data.type,
|
|
394
|
+
});
|
|
395
|
+
break;
|
|
396
|
+
}
|
|
269
397
|
handleFieldFocus(data.fieldName);
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
398
|
+
break;
|
|
399
|
+
case "no-mess:field-blur":
|
|
400
|
+
if (!active)
|
|
401
|
+
break;
|
|
402
|
+
if (typeof data.fieldName !== "string") {
|
|
403
|
+
emitLog("debug", "Ignored malformed live edit blur message", {
|
|
404
|
+
type: data.type,
|
|
405
|
+
});
|
|
406
|
+
break;
|
|
407
|
+
}
|
|
274
408
|
handleFieldBlur(data.fieldName);
|
|
275
|
-
|
|
276
|
-
|
|
409
|
+
break;
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
catch (error) {
|
|
413
|
+
reportRuntimeError(error, {
|
|
414
|
+
phase: "handleMessage",
|
|
415
|
+
type: data.type,
|
|
416
|
+
});
|
|
277
417
|
}
|
|
278
418
|
}
|
|
279
|
-
// Start listening immediately
|
|
280
419
|
window.addEventListener("message", handleMessage);
|
|
281
420
|
return {
|
|
282
421
|
cleanup: () => {
|