@syntrologie/runtime-sdk 2.14.0 → 2.16.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.
Files changed (74) hide show
  1. package/README.md +1 -0
  2. package/dist/SmartCanvasApp.d.ts +4 -1
  3. package/dist/SmartCanvasElementLit.d.ts +166 -0
  4. package/dist/actions/schema.js +4 -3
  5. package/dist/actions/types.d.ts +8 -2
  6. package/dist/anchor/AnchorResolver.d.ts +1 -0
  7. package/dist/api-lit.d.ts +84 -0
  8. package/dist/api.d.ts +3 -0
  9. package/dist/apps/builtinRuntimeModules-lit.d.ts +20 -0
  10. package/dist/bootstrap-init.d.ts +2 -0
  11. package/dist/bootstrap-types.d.ts +10 -0
  12. package/dist/chunk-2IQ2PTLJ.js +871 -0
  13. package/dist/chunk-2IQ2PTLJ.js.map +7 -0
  14. package/dist/{chunk-YLLWLUQX.js → chunk-4HXPGXUC.js} +1 -16
  15. package/dist/{chunk-YLLWLUQX.js.map → chunk-4HXPGXUC.js.map} +1 -1
  16. package/dist/{chunk-IR6UOR63.js → chunk-GX7BBYX6.js} +2 -2
  17. package/dist/chunk-JMHRHAEL.js +18 -0
  18. package/dist/chunk-JMHRHAEL.js.map +7 -0
  19. package/dist/{chunk-JCDCANR7.js → chunk-NVV7IWJC.js} +1301 -1084
  20. package/dist/chunk-NVV7IWJC.js.map +7 -0
  21. package/dist/{chunk-77TNZ66J.js → chunk-XVRDKBYF.js} +3 -3
  22. package/dist/components/SyntroCanvasOverlay.d.ts +100 -0
  23. package/dist/components/SyntroDrawer.d.ts +110 -0
  24. package/dist/components/SyntroLauncher.d.ts +105 -0
  25. package/dist/components/SyntroTileCard.d.ts +74 -0
  26. package/dist/components/SyntroTileWheel.d.ts +51 -0
  27. package/dist/config/schema.js +3 -2
  28. package/dist/controllers/DecisionController.d.ts +48 -0
  29. package/dist/controllers/NotificationsController.d.ts +59 -0
  30. package/dist/controllers/RuntimeController.d.ts +52 -0
  31. package/dist/controllers/RuntimeEventsController.d.ts +42 -0
  32. package/dist/controllers/ThemeController.d.ts +110 -0
  33. package/dist/controllers/index.d.ts +13 -0
  34. package/dist/decisions/schema.js +2 -1
  35. package/dist/decisions/types.d.ts +4 -0
  36. package/dist/editorLoader.d.ts +5 -0
  37. package/dist/index-lit.d.ts +40 -0
  38. package/dist/index.d.ts +1 -0
  39. package/dist/index.js +1338 -19
  40. package/dist/index.js.map +4 -4
  41. package/dist/interop/LitInReact.d.ts +27 -0
  42. package/dist/interop/ReactInLit.d.ts +42 -0
  43. package/dist/interop/index.d.ts +7 -0
  44. package/dist/metrics/sessionMetrics.d.ts +4 -0
  45. package/dist/notifications/SyntroToastStack.d.ts +43 -0
  46. package/dist/platform/PlatformAdapter.d.ts +46 -0
  47. package/dist/platform/ShopifyAdapter.d.ts +36 -0
  48. package/dist/platform/ShopifyAnchorResolver.d.ts +31 -0
  49. package/dist/platform/ShopifyAntiFlicker.d.ts +21 -0
  50. package/dist/platform/ShopifyPixelBridge.d.ts +37 -0
  51. package/dist/platform/detect.d.ts +9 -0
  52. package/dist/platform/index.d.ts +10 -0
  53. package/dist/platform/shopify-cookie-contract.d.ts +39 -0
  54. package/dist/react-compat.d.ts +114 -0
  55. package/dist/react.js +6 -4
  56. package/dist/react.js.map +1 -1
  57. package/dist/shopify-pixel-entry.d.ts +68 -0
  58. package/dist/shopify-pixel.js +77 -0
  59. package/dist/shopify-pixel.js.map +7 -0
  60. package/dist/shopify-pixel.min.js +2 -0
  61. package/dist/shopify-pixel.min.js.map +7 -0
  62. package/dist/smart-canvas.esm.js +856 -240
  63. package/dist/smart-canvas.esm.js.map +4 -4
  64. package/dist/smart-canvas.js +28769 -37080
  65. package/dist/smart-canvas.js.map +4 -4
  66. package/dist/smart-canvas.min.js +855 -240
  67. package/dist/smart-canvas.min.js.map +4 -4
  68. package/dist/theme/index.js +30 -0
  69. package/dist/theme/index.js.map +7 -0
  70. package/dist/version.d.ts +1 -1
  71. package/package.json +10 -1
  72. package/dist/chunk-JCDCANR7.js.map +0 -7
  73. /package/dist/{chunk-IR6UOR63.js.map → chunk-GX7BBYX6.js.map} +0 -0
  74. /package/dist/{chunk-77TNZ66J.js.map → chunk-XVRDKBYF.js.map} +0 -0
@@ -1,9 +1,14 @@
1
+ import {
2
+ ThemeProvider,
3
+ blue,
4
+ useTheme
5
+ } from "./chunk-2IQ2PTLJ.js";
1
6
  import {
2
7
  __privateAdd,
3
8
  __privateGet,
4
9
  __privateSet,
5
10
  __publicField
6
- } from "./chunk-YLLWLUQX.js";
11
+ } from "./chunk-JMHRHAEL.js";
7
12
 
8
13
  // ../adaptives/adaptive-content/dist/reconciliation-guard.js
9
14
  function guardAgainstReconciliation(container, anchor, reinsertFn, opts) {
@@ -91,13 +96,13 @@ var ALLOWED_TAGS = /* @__PURE__ */ new Set([
91
96
  "rect",
92
97
  "g"
93
98
  ]);
94
- function sanitizeHtml(html) {
99
+ function sanitizeHtml(html2) {
95
100
  var _a2;
96
101
  const hasNative = typeof window.Sanitizer === "function";
97
102
  if (hasNative) {
98
103
  try {
99
104
  const s = new window.Sanitizer({});
100
- const frag = s.sanitizeToFragment(html);
105
+ const frag = s.sanitizeToFragment(html2);
101
106
  const div = document.createElement("div");
102
107
  div.append(frag);
103
108
  return div.innerHTML;
@@ -105,14 +110,14 @@ function sanitizeHtml(html) {
105
110
  }
106
111
  }
107
112
  const tpl = document.createElement("template");
108
- tpl.innerHTML = html;
113
+ tpl.innerHTML = html2;
109
114
  const root = tpl.content;
110
115
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null);
111
116
  const toRemove = [];
112
117
  while (walker.nextNode()) {
113
118
  const el = walker.currentNode;
114
- const tag2 = el.tagName.toLowerCase();
115
- if (!ALLOWED_TAGS.has(tag2)) {
119
+ const tag = el.tagName.toLowerCase();
120
+ if (!ALLOWED_TAGS.has(tag)) {
116
121
  toRemove.push(el);
117
122
  continue;
118
123
  }
@@ -256,6 +261,22 @@ var executeInsertHtml = async (action, context) => {
256
261
  }
257
262
  };
258
263
  };
264
+ function findTextTarget(el) {
265
+ var _a2, _b;
266
+ if (el.children.length === 0)
267
+ return el;
268
+ const textChildren = Array.from(el.children).filter((child) => {
269
+ var _a3;
270
+ return (_a3 = child.textContent) == null ? void 0 : _a3.trim();
271
+ });
272
+ if (textChildren.length === 1) {
273
+ const child = textChildren[0];
274
+ if (((_a2 = child.textContent) == null ? void 0 : _a2.trim()) === ((_b = el.textContent) == null ? void 0 : _b.trim())) {
275
+ return findTextTarget(child);
276
+ }
277
+ }
278
+ return el;
279
+ }
259
280
  var executeSetText = async (action, context) => {
260
281
  var _a2;
261
282
  let anchorEl = context.resolveAnchor(action.anchorId);
@@ -267,8 +288,9 @@ var executeSetText = async (action, context) => {
267
288
  return { cleanup: () => {
268
289
  } };
269
290
  }
270
- const originalText = (_a2 = anchorEl.textContent) != null ? _a2 : "";
271
- anchorEl.textContent = action.text;
291
+ const textTarget = findTextTarget(anchorEl);
292
+ const originalText = (_a2 = textTarget.textContent) != null ? _a2 : "";
293
+ textTarget.textContent = action.text;
272
294
  context.publishEvent("action.applied", {
273
295
  id: context.generateId(),
274
296
  kind: "content:setText",
@@ -278,11 +300,11 @@ var executeSetText = async (action, context) => {
278
300
  cleanup: () => {
279
301
  if (!anchorEl.isConnected)
280
302
  return;
281
- anchorEl.textContent = originalText;
303
+ textTarget.textContent = originalText;
282
304
  },
283
305
  updateFn: (changes) => {
284
306
  if ("text" in changes && typeof changes.text === "string") {
285
- anchorEl.textContent = changes.text;
307
+ textTarget.textContent = changes.text;
286
308
  }
287
309
  }
288
310
  };
@@ -1150,392 +1172,6 @@ var executeTour = async (action, context) => {
1150
1172
  return { cleanup };
1151
1173
  };
1152
1174
 
1153
- // ../design-system/src/tokens/colors.ts
1154
- var base = {
1155
- white: "#ffffff",
1156
- black: "#000000"
1157
- };
1158
- var brand = {
1159
- 0: "#2c0b0a",
1160
- 1: "#5b1715",
1161
- 2: "#89221f",
1162
- 3: "#b72e2a",
1163
- 4: "#d44844",
1164
- 5: "#dd6d69",
1165
- 6: "#e5918f",
1166
- 7: "#eeb6b4",
1167
- 8: "#f6dada",
1168
- 9: "#faebea"
1169
- };
1170
- var slateGrey = {
1171
- 0: "#07080a",
1172
- 1: "#0f1318",
1173
- 2: "#0e1114",
1174
- 3: "#1c222a",
1175
- 4: "#2b333f",
1176
- 5: "#394454",
1177
- 6: "#475569",
1178
- 7: "#677384",
1179
- 8: "#87919f",
1180
- 9: "#a8afba",
1181
- 10: "#cbd0d7",
1182
- 11: "#e8eaee",
1183
- 12: "#f6f7f9"
1184
- };
1185
- var green = {
1186
- 0: "#07230a",
1187
- 1: "#0e4514",
1188
- 2: "#16681e",
1189
- 3: "#1d8a28",
1190
- 4: "#24ad32",
1191
- 5: "#4fbd5a",
1192
- 6: "#7acd82",
1193
- 7: "#a5deab",
1194
- 8: "#d0eed3",
1195
- 9: "#e5f6e7"
1196
- };
1197
- var yellow = {
1198
- 0: "#301f09",
1199
- 1: "#5f3e12",
1200
- 2: "#8f5e1b",
1201
- 3: "#be7d24",
1202
- 4: "#ee9c2d",
1203
- 5: "#f1b057",
1204
- 6: "#f5c481",
1205
- 7: "#f8d7ab",
1206
- 8: "#fcebd5",
1207
- 9: "#fdf5ea"
1208
- };
1209
- var red = {
1210
- 0: "#330707",
1211
- 1: "#660f0e",
1212
- 2: "#991616",
1213
- 3: "#cc1e1d",
1214
- 4: "#ff2524",
1215
- 5: "#ff5150",
1216
- 6: "#ff7c7c",
1217
- 7: "#ffa8a7",
1218
- 8: "#ffd3d3",
1219
- 9: "#ffe9e9"
1220
- };
1221
- var blue = {
1222
- 0: "#051533",
1223
- 1: "#0a2a66",
1224
- 2: "#0f3f98",
1225
- 3: "#1454cb",
1226
- 4: "#1969fe",
1227
- 5: "#4787fe",
1228
- 6: "#75a5fe",
1229
- 7: "#a3c3ff",
1230
- 8: "#d1e1ff",
1231
- 9: "#e8f0ff"
1232
- };
1233
- var orange = {
1234
- 0: "#662500",
1235
- 1: "#993d00",
1236
- 2: "#cc5800",
1237
- 3: "#ff7700",
1238
- 4: "#fea85d",
1239
- 5: "#fec58f",
1240
- 6: "#ffd6ae",
1241
- 7: "#fee6cd",
1242
- 8: "#fff1e1",
1243
- 9: "#fff8f0"
1244
- };
1245
- var purple = {
1246
- 0: "#151229",
1247
- 1: "#2a2452",
1248
- 2: "#40357c",
1249
- 3: "#5547a5",
1250
- 4: "#6a59ce",
1251
- 5: "#887ad8",
1252
- 6: "#a69be2",
1253
- 7: "#c3bdeb",
1254
- 8: "#e1def5",
1255
- 9: "#f0eefa"
1256
- };
1257
- var pink = {
1258
- 0: "#37091f",
1259
- 1: "#69123c",
1260
- 2: "#9b1c58",
1261
- 3: "#cd2575",
1262
- 4: "#ff2e92",
1263
- 5: "#ff58a8",
1264
- 6: "#ff82be",
1265
- 7: "#ffabd3",
1266
- 8: "#ffd5e9",
1267
- 9: "#ffeaf4"
1268
- };
1269
- var text = {
1270
- primary: slateGrey[10],
1271
- secondary: slateGrey[9],
1272
- tertiary: slateGrey[8]
1273
- };
1274
- var background = {
1275
- primary: slateGrey[2],
1276
- secondary: slateGrey[0]
1277
- };
1278
- var border = {
1279
- primary: slateGrey[4],
1280
- secondary: slateGrey[3]
1281
- };
1282
- var button = {
1283
- primary: {
1284
- text: base.white,
1285
- icon: base.white,
1286
- border: brand[3],
1287
- backgroundDefault: brand[3],
1288
- backgroundHover: brand[2]
1289
- },
1290
- neutral: {
1291
- text: slateGrey[10],
1292
- textHover: base.white,
1293
- icon: slateGrey[10],
1294
- iconHover: base.white,
1295
- border: slateGrey[4],
1296
- background: slateGrey[2]
1297
- },
1298
- link: {
1299
- text: base.white,
1300
- icon: base.white,
1301
- hover: brand[5]
1302
- },
1303
- error: {
1304
- text: red[5],
1305
- hover: red[6]
1306
- },
1307
- success: {
1308
- text: green[5],
1309
- hover: green[6]
1310
- }
1311
- };
1312
- var badge = {
1313
- slateGrey: {
1314
- content: slateGrey[10],
1315
- pillOutline: slateGrey[10],
1316
- borderPrimary: slateGrey[5],
1317
- borderSecondary: slateGrey[5],
1318
- background: slateGrey[3]
1319
- },
1320
- brand: {
1321
- content: brand[9],
1322
- pillOutline: brand[9],
1323
- borderPrimary: brand[6],
1324
- borderSecondary: brand[6],
1325
- background: brand[0]
1326
- },
1327
- red: {
1328
- content: red[8],
1329
- pillOutline: red[4],
1330
- borderPrimary: red[2],
1331
- borderSecondary: red[2],
1332
- background: red[0]
1333
- },
1334
- yellow: {
1335
- content: yellow[8],
1336
- pillOutline: yellow[4],
1337
- borderPrimary: yellow[2],
1338
- borderSecondary: yellow[2],
1339
- background: yellow[0]
1340
- },
1341
- green: {
1342
- content: green[8],
1343
- pillOutline: green[4],
1344
- borderPrimary: green[2],
1345
- borderSecondary: green[2],
1346
- background: green[0]
1347
- },
1348
- purple: {
1349
- content: purple[8],
1350
- pillOutline: purple[4],
1351
- borderPrimary: purple[2],
1352
- borderSecondary: purple[2],
1353
- background: purple[0]
1354
- },
1355
- blue: {
1356
- content: blue[8],
1357
- pillOutline: blue[4],
1358
- borderPrimary: blue[2],
1359
- borderSecondary: blue[2],
1360
- background: blue[0]
1361
- },
1362
- orange: {
1363
- content: orange[8],
1364
- pillOutline: orange[4],
1365
- borderPrimary: orange[2],
1366
- borderSecondary: orange[2],
1367
- background: orange[0]
1368
- },
1369
- pink: {
1370
- content: pink[8],
1371
- pillOutline: pink[4],
1372
- borderPrimary: pink[2],
1373
- borderSecondary: pink[2],
1374
- background: pink[0]
1375
- }
1376
- };
1377
- var badgeBanner = {
1378
- green: {
1379
- content: green[8],
1380
- border: green[2],
1381
- background: green[0]
1382
- },
1383
- yellow: {
1384
- content: yellow[8],
1385
- border: yellow[2],
1386
- background: yellow[0]
1387
- },
1388
- red: {
1389
- content: red[8],
1390
- border: red[2],
1391
- background: red[0]
1392
- }
1393
- };
1394
- var alert = {
1395
- green: {
1396
- content: green[1],
1397
- background: green[9]
1398
- },
1399
- yellow: {
1400
- content: yellow[1],
1401
- background: yellow[9]
1402
- },
1403
- red: {
1404
- content: red[1],
1405
- background: red[9]
1406
- }
1407
- };
1408
- var tag = {
1409
- content: slateGrey[10],
1410
- border: slateGrey[4],
1411
- background: slateGrey[3]
1412
- };
1413
- var menu = {
1414
- backgroundDefault: slateGrey[2],
1415
- backgroundHover: slateGrey[1],
1416
- selected: slateGrey[3]
1417
- };
1418
- var inputDropdown = {
1419
- background: slateGrey[2],
1420
- icon: slateGrey[10],
1421
- borderDefault: slateGrey[4],
1422
- borderSelected: brand[3],
1423
- textLabel: slateGrey[9],
1424
- textPlaceholder: slateGrey[8],
1425
- textHint: slateGrey[8]
1426
- };
1427
- var inputField = {
1428
- backgroundDefault: slateGrey[2],
1429
- backgroundDisabled: slateGrey[0],
1430
- textLabel: slateGrey[9],
1431
- textPlaceholder: slateGrey[8],
1432
- textHint: slateGrey[8],
1433
- textError: red[5],
1434
- iconDefault: slateGrey[9],
1435
- iconPlaceholder: slateGrey[10],
1436
- iconError: red[5],
1437
- borderDefault: slateGrey[4],
1438
- borderSelected: brand[3],
1439
- borderError: red[5]
1440
- };
1441
- var toggle = {
1442
- handleDefault: base.white,
1443
- handleDisabled: slateGrey[10],
1444
- off: {
1445
- backgroundDefault: slateGrey[4],
1446
- backgroundHover: slateGrey[5],
1447
- backgroundDisabled: slateGrey[4]
1448
- },
1449
- on: {
1450
- backgroundDefault: green[3],
1451
- backgroundHover: green[2],
1452
- backgroundDisabled: slateGrey[4]
1453
- }
1454
- };
1455
- var checkbox = {
1456
- off: {
1457
- backgroundDefault: "#00000000",
1458
- backgroundHover: slateGrey[5],
1459
- backgroundDisabled: slateGrey[2],
1460
- border: slateGrey[6]
1461
- },
1462
- on: {
1463
- backgroundDefault: green[0],
1464
- backgroundHover: green[1],
1465
- backgroundDisabled: slateGrey[2],
1466
- border: green[3]
1467
- }
1468
- };
1469
- var avatar = {
1470
- content: slateGrey[10],
1471
- background: slateGrey[4]
1472
- };
1473
- var progressBarSlider = {
1474
- background: slateGrey[4],
1475
- active: green[3]
1476
- };
1477
- var card = {
1478
- background: slateGrey[1],
1479
- content: slateGrey[9],
1480
- border: slateGrey[4]
1481
- };
1482
- var sidebar = {
1483
- backgroundDefault: slateGrey[1],
1484
- backgroundHover: slateGrey[3],
1485
- backgroundActive: slateGrey[4],
1486
- border: slateGrey[4],
1487
- contentPrimary: slateGrey[10],
1488
- contentSecondary: slateGrey[9],
1489
- contentTertiary: slateGrey[8]
1490
- };
1491
- var modal = {
1492
- background: slateGrey[1],
1493
- content: slateGrey[9],
1494
- border: slateGrey[4]
1495
- };
1496
- var tab = {
1497
- activeBackground: slateGrey[3],
1498
- activeContent: brand[5],
1499
- inactiveContent: slateGrey[9],
1500
- border: slateGrey[4]
1501
- };
1502
- var table = {
1503
- header: {
1504
- textDefault: slateGrey[9],
1505
- textHover: slateGrey[8],
1506
- backgroundDefault: slateGrey[1]
1507
- },
1508
- border: slateGrey[4],
1509
- cell: {
1510
- textPrimary: slateGrey[10],
1511
- textSecondary: slateGrey[9],
1512
- backgroundDefault: slateGrey[2],
1513
- backgroundHover: slateGrey[1]
1514
- }
1515
- };
1516
- var breadcrumbs = {
1517
- textPrimaryDefault: slateGrey[10],
1518
- textPrimaryHover: slateGrey[10],
1519
- textSecondaryDefault: slateGrey[8],
1520
- textSecondaryHover: slateGrey[9],
1521
- iconPrimary: slateGrey[10],
1522
- iconSecondary: slateGrey[8]
1523
- };
1524
- var loadingIndicator = {
1525
- background: green[1],
1526
- active: green[5]
1527
- };
1528
- var datePicker = {
1529
- textDefault: slateGrey[10],
1530
- textSelected: base.white,
1531
- textDisabled: slateGrey[7],
1532
- backgroundDefault: slateGrey[2],
1533
- backgroundMiddle: slateGrey[3],
1534
- backgroundSelected: brand[3],
1535
- border: slateGrey[4]
1536
- };
1537
- var scroll = slateGrey[9];
1538
-
1539
1175
  // ../adaptives/adaptive-overlays/dist/highlight.js
1540
1176
  var _a;
1541
1177
  var supportsPathClip = typeof CSS !== "undefined" && ((_a = CSS.supports) == null ? void 0 : _a.call(CSS, "clip-path", "path('M0 0 H1 V1 Z')"));
@@ -1727,13 +1363,13 @@ var ALLOWED_TAGS2 = /* @__PURE__ */ new Set([
1727
1363
  "rect",
1728
1364
  "g"
1729
1365
  ]);
1730
- function sanitizeHtml2(html) {
1366
+ function sanitizeHtml2(html2) {
1731
1367
  var _a2;
1732
1368
  const hasNative = typeof window.Sanitizer === "function";
1733
1369
  if (hasNative) {
1734
1370
  try {
1735
1371
  const s = new window.Sanitizer({});
1736
- const frag = s.sanitizeToFragment(html);
1372
+ const frag = s.sanitizeToFragment(html2);
1737
1373
  const div = document.createElement("div");
1738
1374
  div.append(frag);
1739
1375
  return div.innerHTML;
@@ -1741,14 +1377,14 @@ function sanitizeHtml2(html) {
1741
1377
  }
1742
1378
  }
1743
1379
  const tpl = document.createElement("template");
1744
- tpl.innerHTML = html;
1380
+ tpl.innerHTML = html2;
1745
1381
  const root = tpl.content;
1746
1382
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null);
1747
1383
  const toRemove = [];
1748
1384
  while (walker.nextNode()) {
1749
1385
  const el = walker.currentNode;
1750
- const tag2 = el.tagName.toLowerCase();
1751
- if (!ALLOWED_TAGS2.has(tag2)) {
1386
+ const tag = el.tagName.toLowerCase();
1387
+ if (!ALLOWED_TAGS2.has(tag)) {
1752
1388
  toRemove.push(el);
1753
1389
  continue;
1754
1390
  }
@@ -1793,12 +1429,12 @@ var executeModal = async (action, context) => {
1793
1429
  transition: opacity 200ms ease-out;
1794
1430
  `;
1795
1431
  context.overlayRoot.appendChild(scrimEl);
1796
- const modal2 = document.createElement("div");
1797
- modal2.className = `syntro-modal syntro-modal-${size}`;
1798
- modal2.setAttribute("role", "dialog");
1799
- modal2.setAttribute("aria-modal", "true");
1432
+ const modal = document.createElement("div");
1433
+ modal.className = `syntro-modal syntro-modal-${size}`;
1434
+ modal.setAttribute("role", "dialog");
1435
+ modal.setAttribute("aria-modal", "true");
1800
1436
  const sizeMap = { sm: "360px", md: "480px", lg: "640px" };
1801
- modal2.style.cssText = `
1437
+ modal.style.cssText = `
1802
1438
  position: fixed;
1803
1439
  top: 50%;
1804
1440
  left: 50%;
@@ -1813,13 +1449,13 @@ var executeModal = async (action, context) => {
1813
1449
  transition: opacity 200ms ease-out, transform 200ms ease-out;
1814
1450
  padding: 24px;
1815
1451
  `;
1816
- let html = "";
1452
+ let html2 = "";
1817
1453
  if (content.title) {
1818
- html += `<h2 class="syntro-modal-title" style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: ${V.title};">${sanitizeHtml2(content.title)}</h2>`;
1454
+ html2 += `<h2 class="syntro-modal-title" style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: ${V.title};">${sanitizeHtml2(content.title)}</h2>`;
1819
1455
  }
1820
- html += `<div class="syntro-modal-body" style="color: ${V.text}; line-height: 1.5;">${sanitizeHtml2(content.body)}</div>`;
1456
+ html2 += `<div class="syntro-modal-body" style="color: ${V.text}; line-height: 1.5;">${sanitizeHtml2(content.body)}</div>`;
1821
1457
  if ((dismiss == null ? void 0 : dismiss.closeButton) !== false) {
1822
- html += `
1458
+ html2 += `
1823
1459
  <button class="syntro-modal-close" data-syntro-action="dismiss" style="
1824
1460
  position: absolute;
1825
1461
  top: 16px;
@@ -1838,10 +1474,10 @@ var executeModal = async (action, context) => {
1838
1474
  `;
1839
1475
  }
1840
1476
  if (ctaButtons && ctaButtons.length > 0) {
1841
- html += `<div class="syntro-modal-actions" style="display: flex; gap: 12px; margin-top: 24px; justify-content: flex-end;">`;
1477
+ html2 += `<div class="syntro-modal-actions" style="display: flex; gap: 12px; margin-top: 24px; justify-content: flex-end;">`;
1842
1478
  for (const btn of ctaButtons) {
1843
1479
  const isPrimary = (_b = btn.primary) != null ? _b : false;
1844
- html += `
1480
+ html2 += `
1845
1481
  <button
1846
1482
  class="syntro-modal-btn ${isPrimary ? "syntro-modal-btn-primary" : ""}"
1847
1483
  data-syntro-action="${sanitizeHtml2(btn.actionId)}"
@@ -1859,12 +1495,12 @@ var executeModal = async (action, context) => {
1859
1495
  </button>
1860
1496
  `;
1861
1497
  }
1862
- html += `</div>`;
1498
+ html2 += `</div>`;
1863
1499
  }
1864
- modal2.innerHTML = html;
1865
- context.overlayRoot.appendChild(modal2);
1500
+ modal.innerHTML = html2;
1501
+ context.overlayRoot.appendChild(modal);
1866
1502
  let actionClicked = null;
1867
- const actionBtns = modal2.querySelectorAll("[data-syntro-action]");
1503
+ const actionBtns = modal.querySelectorAll("[data-syntro-action]");
1868
1504
  const actionHandler = (e) => {
1869
1505
  const btn = e.currentTarget;
1870
1506
  const actionId = btn.getAttribute("data-syntro-action");
@@ -1904,14 +1540,14 @@ var executeModal = async (action, context) => {
1904
1540
  handle.destroy();
1905
1541
  }, dismiss.timeoutMs);
1906
1542
  }
1907
- const focusableEls = modal2.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
1543
+ const focusableEls = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
1908
1544
  if (focusableEls.length > 0) {
1909
1545
  requestAnimationFrame(() => focusableEls[0].focus());
1910
1546
  }
1911
1547
  requestAnimationFrame(() => {
1912
1548
  scrimEl.style.opacity = "1";
1913
- modal2.style.opacity = "1";
1914
- modal2.style.transform = "translate(-50%, -50%) scale(1)";
1549
+ modal.style.opacity = "1";
1550
+ modal.style.transform = "translate(-50%, -50%) scale(1)";
1915
1551
  });
1916
1552
  context.publishEvent("action.applied", {
1917
1553
  id: context.generateId(),
@@ -1928,14 +1564,14 @@ var executeModal = async (action, context) => {
1928
1564
  scrimEl.removeEventListener("click", onScrimClick);
1929
1565
  actionBtns.forEach((btn) => btn.removeEventListener("click", actionHandler));
1930
1566
  originalInert.forEach((el) => el.removeAttribute("inert"));
1931
- modal2.style.pointerEvents = "none";
1567
+ modal.style.pointerEvents = "none";
1932
1568
  scrimEl.style.pointerEvents = "none";
1933
- modal2.style.opacity = "0";
1934
- modal2.style.transform = "translate(-50%, -50%) scale(0.95)";
1569
+ modal.style.opacity = "0";
1570
+ modal.style.transform = "translate(-50%, -50%) scale(0.95)";
1935
1571
  scrimEl.style.opacity = "0";
1936
1572
  setTimeout(() => {
1937
1573
  try {
1938
- modal2.remove();
1574
+ modal.remove();
1939
1575
  } catch {
1940
1576
  }
1941
1577
  try {
@@ -2163,7 +1799,7 @@ function showTooltip(anchorEl, overlayRoot, opts) {
2163
1799
  };
2164
1800
  }
2165
1801
  if (opts.trigger === "click") {
2166
- const toggle2 = () => {
1802
+ const toggle = () => {
2167
1803
  const isVisible = div.style.visibility === "visible";
2168
1804
  if (isVisible) {
2169
1805
  handle.destroy();
@@ -2175,8 +1811,8 @@ function showTooltip(anchorEl, overlayRoot, opts) {
2175
1811
  div.style.visibility = "hidden";
2176
1812
  div.style.opacity = "0";
2177
1813
  div.style.transition = "opacity 200ms ease, visibility 200ms";
2178
- anchorEl.addEventListener("click", toggle2);
2179
- return () => anchorEl.removeEventListener("click", toggle2);
1814
+ anchorEl.addEventListener("click", toggle);
1815
+ return () => anchorEl.removeEventListener("click", toggle);
2180
1816
  }
2181
1817
  div.style.opacity = "0";
2182
1818
  div.style.transition = "opacity 200ms ease";
@@ -2503,6 +2139,543 @@ var WorkflowMountableWidget = {
2503
2139
  }
2504
2140
  };
2505
2141
 
2142
+ // ../adaptives/adaptive-overlays/dist/WorkflowWidgetLit.js
2143
+ import { html, LitElement, nothing } from "lit";
2144
+ import { styleMap } from "lit/directives/style-map.js";
2145
+ var __classPrivateFieldSet = function(receiver, state, value, kind, f) {
2146
+ if (kind === "m") throw new TypeError("Private method is not writable");
2147
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
2148
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
2149
+ return kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value), value;
2150
+ };
2151
+ var __classPrivateFieldGet = function(receiver, state, kind, f) {
2152
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
2153
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
2154
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
2155
+ };
2156
+ var _WorkflowTrackerLit_unsubTourStarted;
2157
+ var _WorkflowTrackerLit_unsubTourEvents;
2158
+ var _WorkflowTrackerLit_toastCleanups;
2159
+ var _WorkflowTrackerLit_notified;
2160
+ var _WorkflowTrackerLit_completedMap;
2161
+ var _WorkflowTrackerLit_persistInitialized;
2162
+ var _WorkflowTrackerLit_tourWorkflows;
2163
+ var TOKEN_BLUE_4 = "#1969fe";
2164
+ var TOKEN_GREEN_4 = "#24ad32";
2165
+ var TOKEN_SLATE_2 = "#0e1114";
2166
+ var TOKEN_SLATE_7 = "#677384";
2167
+ var TOKEN_SLATE_9 = "#a8afba";
2168
+ var TOKEN_SLATE_12 = "#f6f7f9";
2169
+ var TOKEN_WHITE = "#ffffff";
2170
+ function showWorkflowToast2(notification) {
2171
+ const toast = document.createElement("div");
2172
+ toast.setAttribute("data-testid", "workflow-toast");
2173
+ Object.assign(toast.style, {
2174
+ position: "fixed",
2175
+ bottom: "16px",
2176
+ right: "16px",
2177
+ zIndex: "2147483646",
2178
+ padding: "12px 16px",
2179
+ borderRadius: "8px",
2180
+ backgroundColor: `var(--se-color-bg-surface, ${TOKEN_WHITE})`,
2181
+ color: `var(--se-color-text-primary, ${TOKEN_SLATE_2})`,
2182
+ boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
2183
+ maxWidth: "320px",
2184
+ fontFamily: "var(--se-font-family, system-ui, sans-serif)",
2185
+ fontSize: "14px",
2186
+ lineHeight: "1.4",
2187
+ transition: "opacity 0.3s ease"
2188
+ });
2189
+ const titleEl = document.createElement("div");
2190
+ titleEl.style.fontWeight = "600";
2191
+ titleEl.textContent = notification.title;
2192
+ toast.appendChild(titleEl);
2193
+ if (notification.body) {
2194
+ const bodyEl = document.createElement("div");
2195
+ bodyEl.style.marginTop = "4px";
2196
+ bodyEl.style.fontSize = "13px";
2197
+ bodyEl.style.color = "var(--se-color-text-secondary, #666)";
2198
+ bodyEl.textContent = notification.body;
2199
+ toast.appendChild(bodyEl);
2200
+ }
2201
+ document.body.appendChild(toast);
2202
+ let removeTimer;
2203
+ const fadeTimer = setTimeout(() => {
2204
+ toast.style.opacity = "0";
2205
+ removeTimer = setTimeout(() => {
2206
+ toast.remove();
2207
+ }, 300);
2208
+ }, 4e3);
2209
+ return () => {
2210
+ clearTimeout(fadeTimer);
2211
+ clearTimeout(removeTimer);
2212
+ toast.remove();
2213
+ };
2214
+ }
2215
+ function extractWorkflowsFromActive2(activeActions) {
2216
+ const workflows = /* @__PURE__ */ new Map();
2217
+ for (const entry of activeActions) {
2218
+ const action = entry.action;
2219
+ if (action.kind === "overlays:tour" && action.workflow && action.tourId) {
2220
+ const meta = action.workflow;
2221
+ const rawSteps = action.steps || [];
2222
+ const steps = rawSteps.map((s) => {
2223
+ var _a2;
2224
+ return {
2225
+ id: s.id,
2226
+ title: ((_a2 = meta.stepTitles) == null ? void 0 : _a2[s.id]) || s.id
2227
+ };
2228
+ });
2229
+ workflows.set(action.tourId, { meta, steps });
2230
+ }
2231
+ }
2232
+ return workflows;
2233
+ }
2234
+ var TAG_NAME = "syntro-workflow-tracker";
2235
+ var WorkflowTrackerLit = class extends LitElement {
2236
+ constructor() {
2237
+ super(...arguments);
2238
+ this.runtimeRef = null;
2239
+ this._workflowEntries = [];
2240
+ this._actionVersion = 0;
2241
+ _WorkflowTrackerLit_unsubTourStarted.set(this, null);
2242
+ _WorkflowTrackerLit_unsubTourEvents.set(this, null);
2243
+ _WorkflowTrackerLit_toastCleanups.set(this, []);
2244
+ _WorkflowTrackerLit_notified.set(this, /* @__PURE__ */ new Set());
2245
+ _WorkflowTrackerLit_completedMap.set(this, {});
2246
+ _WorkflowTrackerLit_persistInitialized.set(this, false);
2247
+ _WorkflowTrackerLit_tourWorkflows.set(this, /* @__PURE__ */ new Map());
2248
+ }
2249
+ // ── Light DOM ─────────────────────────────────────────────────────────────
2250
+ /**
2251
+ * Render into the element itself (light DOM) so host-page CSS variables
2252
+ * flow through without a nested shadow boundary.
2253
+ */
2254
+ createRenderRoot() {
2255
+ return this;
2256
+ }
2257
+ // ── Helpers ───────────────────────────────────────────────────────────────
2258
+ get _stateNs() {
2259
+ var _a2, _b, _c, _d, _e;
2260
+ return (_e = (_d = (_c = (_b = (_a2 = this.runtimeRef) == null ? void 0 : _a2.state) == null ? void 0 : _b.user) == null ? void 0 : _c.ns) == null ? void 0 : _d.call(_c, "workflows")) != null ? _e : null;
2261
+ }
2262
+ /**
2263
+ * Re-scan active actions and update _tourWorkflows + entries.
2264
+ * Called initially and whenever _actionVersion bumps.
2265
+ */
2266
+ _rescanWorkflows() {
2267
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
2268
+ const active = (_d = (_c = (_b = (_a2 = this.runtimeRef) == null ? void 0 : _a2.actions) == null ? void 0 : _b.getActive) == null ? void 0 : _c.call(_b)) != null ? _d : [];
2269
+ const workflows = extractWorkflowsFromActive2(active);
2270
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_tourWorkflows, workflows, "f");
2271
+ if (workflows.size === 0)
2272
+ return;
2273
+ const stateNs = this._stateNs;
2274
+ const dismissed = (_e = stateNs == null ? void 0 : stateNs.get("dismissed")) != null ? _e : [];
2275
+ const completed = (_f = stateNs == null ? void 0 : stateNs.get("completed")) != null ? _f : {};
2276
+ this._workflowEntries = (() => {
2277
+ const existingIds = new Set(this._workflowEntries.map((e) => e.tourId));
2278
+ const newEntries = [];
2279
+ for (const [tourId, { meta, steps }] of workflows) {
2280
+ if (existingIds.has(tourId))
2281
+ continue;
2282
+ let status = "active";
2283
+ if (dismissed.includes(tourId)) {
2284
+ status = "dismissed";
2285
+ } else if (completed[tourId]) {
2286
+ status = "completed";
2287
+ }
2288
+ newEntries.push({
2289
+ tourId,
2290
+ meta,
2291
+ steps,
2292
+ currentStepId: null,
2293
+ completedSteps: [],
2294
+ status,
2295
+ completedAt: completed[tourId] || void 0
2296
+ });
2297
+ }
2298
+ return newEntries.length > 0 ? [...this._workflowEntries, ...newEntries] : this._workflowEntries;
2299
+ })();
2300
+ for (const [tourId, { meta }] of workflows) {
2301
+ const dismissed2 = (_g = stateNs == null ? void 0 : stateNs.get("dismissed")) != null ? _g : [];
2302
+ const completed2 = (_h = stateNs == null ? void 0 : stateNs.get("completed")) != null ? _h : {};
2303
+ if (!__classPrivateFieldGet(this, _WorkflowTrackerLit_notified, "f").has(tourId) && meta.notification && !dismissed2.includes(tourId) && !completed2[tourId]) {
2304
+ __classPrivateFieldGet(this, _WorkflowTrackerLit_notified, "f").add(tourId);
2305
+ stateNs == null ? void 0 : stateNs.set("notified", [...__classPrivateFieldGet(this, _WorkflowTrackerLit_notified, "f")]);
2306
+ const cleanup = showWorkflowToast2(meta.notification);
2307
+ __classPrivateFieldGet(this, _WorkflowTrackerLit_toastCleanups, "f").push(cleanup);
2308
+ }
2309
+ }
2310
+ }
2311
+ // ── Lifecycle ─────────────────────────────────────────────────────────────
2312
+ connectedCallback() {
2313
+ super.connectedCallback();
2314
+ this._initSubscriptions();
2315
+ }
2316
+ disconnectedCallback() {
2317
+ super.disconnectedCallback();
2318
+ this._teardownSubscriptions();
2319
+ for (const cleanup of __classPrivateFieldGet(this, _WorkflowTrackerLit_toastCleanups, "f")) {
2320
+ cleanup();
2321
+ }
2322
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_toastCleanups, [], "f");
2323
+ }
2324
+ updated(changed) {
2325
+ if (changed.has("runtimeRef")) {
2326
+ this._teardownSubscriptions();
2327
+ this._initSubscriptions();
2328
+ }
2329
+ if (changed.has("_actionVersion")) {
2330
+ this._rescanWorkflows();
2331
+ }
2332
+ }
2333
+ // ── Subscription management ───────────────────────────────────────────────
2334
+ _initSubscriptions() {
2335
+ var _a2, _b, _c, _d;
2336
+ if (!((_b = (_a2 = this.runtimeRef) == null ? void 0 : _a2.events) == null ? void 0 : _b.subscribe))
2337
+ return;
2338
+ if (!__classPrivateFieldGet(this, _WorkflowTrackerLit_persistInitialized, "f") && this._stateNs) {
2339
+ const notified = (_c = this._stateNs.get("notified")) != null ? _c : [];
2340
+ for (const id of notified) {
2341
+ __classPrivateFieldGet(this, _WorkflowTrackerLit_notified, "f").add(id);
2342
+ }
2343
+ const completed = (_d = this._stateNs.get("completed")) != null ? _d : {};
2344
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_completedMap, { ...completed }, "f");
2345
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_persistInitialized, true, "f");
2346
+ }
2347
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_unsubTourStarted, this.runtimeRef.events.subscribe({ names: ["tour.started", "tour.resumed"] }, () => {
2348
+ this._actionVersion += 1;
2349
+ }), "f");
2350
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_unsubTourEvents, this.runtimeRef.events.subscribe({ patterns: ["^tour\\."] }, (event) => {
2351
+ this._handleTourEvent(event);
2352
+ }), "f");
2353
+ this._rescanWorkflows();
2354
+ }
2355
+ _teardownSubscriptions() {
2356
+ var _a2, _b;
2357
+ (_a2 = __classPrivateFieldGet(this, _WorkflowTrackerLit_unsubTourStarted, "f")) == null ? void 0 : _a2.call(this);
2358
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_unsubTourStarted, null, "f");
2359
+ (_b = __classPrivateFieldGet(this, _WorkflowTrackerLit_unsubTourEvents, "f")) == null ? void 0 : _b.call(this);
2360
+ __classPrivateFieldSet(this, _WorkflowTrackerLit_unsubTourEvents, null, "f");
2361
+ }
2362
+ // ── Event handler ─────────────────────────────────────────────────────────
2363
+ _handleTourEvent(event) {
2364
+ var _a2;
2365
+ const tourId = (_a2 = event.props) == null ? void 0 : _a2.tourId;
2366
+ if (!tourId)
2367
+ return;
2368
+ if (!__classPrivateFieldGet(this, _WorkflowTrackerLit_tourWorkflows, "f").has(tourId) && event.name === "tour.started") {
2369
+ this._actionVersion += 1;
2370
+ return;
2371
+ }
2372
+ if (!__classPrivateFieldGet(this, _WorkflowTrackerLit_tourWorkflows, "f").has(tourId))
2373
+ return;
2374
+ const stateNs = this._stateNs;
2375
+ this._workflowEntries = this._workflowEntries.map((entry) => {
2376
+ var _a3, _b, _c, _d, _e;
2377
+ if (entry.tourId !== tourId)
2378
+ return entry;
2379
+ switch (event.name) {
2380
+ case "tour.started": {
2381
+ const startStepId = ((_a3 = event.props) == null ? void 0 : _a3.startStepId) || ((_b = entry.steps[0]) == null ? void 0 : _b.id) || null;
2382
+ if (!__classPrivateFieldGet(this, _WorkflowTrackerLit_notified, "f").has(tourId)) {
2383
+ __classPrivateFieldGet(this, _WorkflowTrackerLit_notified, "f").add(tourId);
2384
+ stateNs == null ? void 0 : stateNs.set("notified", [...__classPrivateFieldGet(this, _WorkflowTrackerLit_notified, "f")]);
2385
+ const workflow = __classPrivateFieldGet(this, _WorkflowTrackerLit_tourWorkflows, "f").get(tourId);
2386
+ if (workflow == null ? void 0 : workflow.meta.notification) {
2387
+ const cleanup = showWorkflowToast2(workflow.meta.notification);
2388
+ __classPrivateFieldGet(this, _WorkflowTrackerLit_toastCleanups, "f").push(cleanup);
2389
+ }
2390
+ }
2391
+ const activeIds = this._workflowEntries.filter((e) => e.status === "active" || e.tourId === tourId).map((e) => e.tourId);
2392
+ if (!activeIds.includes(tourId)) {
2393
+ activeIds.push(tourId);
2394
+ }
2395
+ stateNs == null ? void 0 : stateNs.set("active", [...new Set(activeIds)]);
2396
+ return {
2397
+ ...entry,
2398
+ status: "active",
2399
+ currentStepId: startStepId,
2400
+ completedSteps: entry.status === "active" ? entry.completedSteps : []
2401
+ };
2402
+ }
2403
+ case "tour.step_started": {
2404
+ const stepId = (_c = event.props) == null ? void 0 : _c.stepId;
2405
+ return {
2406
+ ...entry,
2407
+ currentStepId: stepId || entry.currentStepId
2408
+ };
2409
+ }
2410
+ case "tour.step_changed": {
2411
+ const previousStepId = (_d = event.props) == null ? void 0 : _d.previousStepId;
2412
+ const nextStepId = (_e = event.props) == null ? void 0 : _e.nextStepId;
2413
+ const completedSteps = previousStepId && !entry.completedSteps.includes(previousStepId) ? [...entry.completedSteps, previousStepId] : entry.completedSteps;
2414
+ return {
2415
+ ...entry,
2416
+ currentStepId: nextStepId || entry.currentStepId,
2417
+ completedSteps
2418
+ };
2419
+ }
2420
+ case "tour.completed": {
2421
+ const completedAt = Date.now();
2422
+ __classPrivateFieldGet(this, _WorkflowTrackerLit_completedMap, "f")[tourId] = completedAt;
2423
+ stateNs == null ? void 0 : stateNs.set("completed", { ...__classPrivateFieldGet(this, _WorkflowTrackerLit_completedMap, "f") });
2424
+ return {
2425
+ ...entry,
2426
+ status: "completed",
2427
+ currentStepId: null,
2428
+ completedSteps: entry.steps.map((s) => s.id),
2429
+ completedAt
2430
+ };
2431
+ }
2432
+ case "tour.paused":
2433
+ return entry;
2434
+ default:
2435
+ return entry;
2436
+ }
2437
+ });
2438
+ }
2439
+ // ── User action handlers ──────────────────────────────────────────────────
2440
+ _handleStepClick(tourId, stepId) {
2441
+ var _a2, _b;
2442
+ (_b = (_a2 = this.runtimeRef) == null ? void 0 : _a2.events) == null ? void 0 : _b.publish("workflow:jump_to_step", { tourId, stepId });
2443
+ this.dispatchEvent(new CustomEvent("workflow-step-click", {
2444
+ bubbles: true,
2445
+ detail: { tourId, stepId }
2446
+ }));
2447
+ }
2448
+ _handleDismiss(tourId) {
2449
+ var _a2;
2450
+ this._workflowEntries = this._workflowEntries.map((entry) => entry.tourId === tourId ? { ...entry, status: "dismissed" } : entry);
2451
+ const dismissedIds = this._workflowEntries.filter((e) => e.status === "dismissed").map((e) => e.tourId);
2452
+ (_a2 = this._stateNs) == null ? void 0 : _a2.set("dismissed", dismissedIds);
2453
+ this.dispatchEvent(new CustomEvent("workflow-dismissed", {
2454
+ bubbles: true,
2455
+ detail: { tourId }
2456
+ }));
2457
+ }
2458
+ // ── Render helpers ────────────────────────────────────────────────────────
2459
+ _renderProgressBar(completed, total) {
2460
+ const percent = total > 0 ? Math.round(completed / total * 100) : 0;
2461
+ const trackStyles = {
2462
+ width: "100%",
2463
+ height: "6px",
2464
+ borderRadius: "9999px",
2465
+ background: "rgba(255,255,255,0.08)",
2466
+ overflow: "hidden"
2467
+ };
2468
+ const fillStyles = {
2469
+ height: "100%",
2470
+ borderRadius: "9999px",
2471
+ background: `var(--se-color-primary, ${TOKEN_BLUE_4})`,
2472
+ transition: "width 0.3s ease",
2473
+ width: `${percent}%`
2474
+ };
2475
+ return html`
2476
+ <div style=${styleMap(trackStyles)}>
2477
+ <div
2478
+ role="progressbar"
2479
+ aria-valuenow=${percent}
2480
+ aria-valuemin="0"
2481
+ aria-valuemax="100"
2482
+ style=${styleMap(fillStyles)}
2483
+ ></div>
2484
+ </div>
2485
+ `;
2486
+ }
2487
+ _renderStepItem(step, isCompleted, isCurrent, tourId) {
2488
+ const btnStyles = {
2489
+ display: "flex",
2490
+ alignItems: "center",
2491
+ gap: "8px",
2492
+ width: "100%",
2493
+ padding: "6px 8px",
2494
+ borderRadius: "4px",
2495
+ border: "none",
2496
+ background: "transparent",
2497
+ cursor: "pointer",
2498
+ textAlign: "left",
2499
+ fontSize: "12px",
2500
+ lineHeight: "1.4",
2501
+ color: isCurrent ? `var(--se-color-text-primary, ${TOKEN_SLATE_12})` : `var(--se-color-text-secondary, ${TOKEN_SLATE_9})`,
2502
+ fontWeight: isCurrent ? "600" : "400"
2503
+ };
2504
+ const indicatorWrapStyles = {
2505
+ flexShrink: "0",
2506
+ width: "16px",
2507
+ textAlign: "center"
2508
+ };
2509
+ const dotStyles = {
2510
+ display: "inline-block",
2511
+ width: "6px",
2512
+ height: "6px",
2513
+ borderRadius: "50%",
2514
+ background: isCurrent ? `var(--se-color-primary, ${TOKEN_BLUE_4})` : "rgba(255,255,255,0.12)"
2515
+ };
2516
+ const checkStyles = {
2517
+ color: `var(--se-color-success, ${TOKEN_GREEN_4})`
2518
+ };
2519
+ const labelStyles = {
2520
+ flex: "1",
2521
+ overflow: "hidden",
2522
+ textOverflow: "ellipsis",
2523
+ whiteSpace: "nowrap"
2524
+ };
2525
+ const indicator = isCompleted ? html`<span role="img" aria-label="completed" style=${styleMap(checkStyles)}>&#10003;</span>` : isCurrent ? html`<span style=${styleMap(dotStyles)}></span>` : html`<span style=${styleMap(dotStyles)}></span>`;
2526
+ return html`
2527
+ <button
2528
+ type="button"
2529
+ data-testid=${`step-${step.id}`}
2530
+ data-current=${isCurrent ? "true" : nothing}
2531
+ data-completed=${isCompleted ? "true" : nothing}
2532
+ aria-current=${isCurrent ? "step" : nothing}
2533
+ style=${styleMap(btnStyles)}
2534
+ @click=${() => this._handleStepClick(tourId, step.id)}
2535
+ >
2536
+ <span style=${styleMap(indicatorWrapStyles)}>${indicator}</span>
2537
+ <span style=${styleMap(labelStyles)}>${step.title}</span>
2538
+ </button>
2539
+ `;
2540
+ }
2541
+ _renderWorkflowCard(workflow) {
2542
+ const completedCount = workflow.completedSteps.length;
2543
+ const totalSteps = workflow.steps.length;
2544
+ const cardStyles = {
2545
+ padding: "12px",
2546
+ borderRadius: "8px",
2547
+ border: "1px solid rgba(255,255,255,0.08)",
2548
+ background: "rgba(255,255,255,0.02)"
2549
+ };
2550
+ const headerStyles = {
2551
+ display: "flex",
2552
+ alignItems: "center",
2553
+ gap: "8px",
2554
+ marginBottom: "8px"
2555
+ };
2556
+ const titleStyles = {
2557
+ flex: "1",
2558
+ fontSize: "13px",
2559
+ fontWeight: "600",
2560
+ color: `var(--se-color-text-primary, ${TOKEN_SLATE_12})`,
2561
+ overflow: "hidden",
2562
+ textOverflow: "ellipsis",
2563
+ whiteSpace: "nowrap"
2564
+ };
2565
+ const dismissBtnStyles = {
2566
+ flexShrink: "0",
2567
+ padding: "2px 6px",
2568
+ border: "none",
2569
+ borderRadius: "4px",
2570
+ background: "transparent",
2571
+ color: `var(--se-color-text-tertiary, ${TOKEN_SLATE_7})`,
2572
+ fontSize: "12px",
2573
+ cursor: "pointer",
2574
+ lineHeight: "1"
2575
+ };
2576
+ const progressWrapStyles = {
2577
+ marginBottom: "8px"
2578
+ };
2579
+ const progressLabelStyles = {
2580
+ fontSize: "10px",
2581
+ color: `var(--se-color-text-tertiary, ${TOKEN_SLATE_7})`,
2582
+ marginTop: "4px"
2583
+ };
2584
+ const stepsColStyles = {
2585
+ display: "flex",
2586
+ flexDirection: "column"
2587
+ };
2588
+ return html`
2589
+ <div style=${styleMap(cardStyles)}>
2590
+ <!-- Header: icon + title + dismiss -->
2591
+ <div style=${styleMap(headerStyles)}>
2592
+ ${workflow.meta.icon ? html`<span data-testid="workflow-icon" style="flex-shrink:0;font-size:14px">${workflow.meta.icon}</span>` : nothing}
2593
+ <span style=${styleMap(titleStyles)}>${workflow.meta.title}</span>
2594
+ <button
2595
+ type="button"
2596
+ data-testid=${`dismiss-${workflow.tourId}`}
2597
+ style=${styleMap(dismissBtnStyles)}
2598
+ aria-label=${`Dismiss ${workflow.meta.title}`}
2599
+ @click=${() => this._handleDismiss(workflow.tourId)}
2600
+ >&#10005;</button>
2601
+ </div>
2602
+
2603
+ <!-- Progress bar + label -->
2604
+ <div style=${styleMap(progressWrapStyles)}>
2605
+ ${this._renderProgressBar(completedCount, totalSteps)}
2606
+ <div style=${styleMap(progressLabelStyles)}>
2607
+ ${completedCount} of ${totalSteps} steps
2608
+ </div>
2609
+ </div>
2610
+
2611
+ <!-- Step list -->
2612
+ <div style=${styleMap(stepsColStyles)}>
2613
+ ${workflow.steps.map((step) => this._renderStepItem(step, workflow.completedSteps.includes(step.id), workflow.currentStepId === step.id, workflow.tourId))}
2614
+ </div>
2615
+ </div>
2616
+ `;
2617
+ }
2618
+ // ── Render ────────────────────────────────────────────────────────────────
2619
+ render() {
2620
+ const activeWorkflows = this._workflowEntries.filter((w) => w.status === "active");
2621
+ if (activeWorkflows.length === 0) {
2622
+ const emptyStyles = {
2623
+ display: "flex",
2624
+ alignItems: "center",
2625
+ justifyContent: "center",
2626
+ padding: "24px 0",
2627
+ fontSize: "12px",
2628
+ color: `var(--se-color-text-tertiary, ${TOKEN_SLATE_7})`
2629
+ };
2630
+ return html`<div style=${styleMap(emptyStyles)}>No active workflows</div>`;
2631
+ }
2632
+ const containerStyles = {
2633
+ display: "flex",
2634
+ flexDirection: "column",
2635
+ gap: "8px"
2636
+ };
2637
+ return html`
2638
+ <div style=${styleMap(containerStyles)}>
2639
+ ${activeWorkflows.map((workflow) => this._renderWorkflowCard(workflow))}
2640
+ </div>
2641
+ `;
2642
+ }
2643
+ };
2644
+ _WorkflowTrackerLit_unsubTourStarted = /* @__PURE__ */ new WeakMap(), _WorkflowTrackerLit_unsubTourEvents = /* @__PURE__ */ new WeakMap(), _WorkflowTrackerLit_toastCleanups = /* @__PURE__ */ new WeakMap(), _WorkflowTrackerLit_notified = /* @__PURE__ */ new WeakMap(), _WorkflowTrackerLit_completedMap = /* @__PURE__ */ new WeakMap(), _WorkflowTrackerLit_persistInitialized = /* @__PURE__ */ new WeakMap(), _WorkflowTrackerLit_tourWorkflows = /* @__PURE__ */ new WeakMap();
2645
+ WorkflowTrackerLit.properties = {
2646
+ // Public input: runtime ref injected by MountableWidget
2647
+ runtimeRef: { attribute: false },
2648
+ // Internal reactive state
2649
+ _workflowEntries: { state: true },
2650
+ _actionVersion: { state: true }
2651
+ };
2652
+ if (typeof window !== "undefined" && !customElements.get(TAG_NAME)) {
2653
+ customElements.define(TAG_NAME, WorkflowTrackerLit);
2654
+ }
2655
+ var WorkflowWidgetLitMountable = {
2656
+ mount(container, config) {
2657
+ var _a2;
2658
+ const runtime3 = (_a2 = config == null ? void 0 : config.runtime) != null ? _a2 : null;
2659
+ if (typeof window !== "undefined" && !customElements.get(TAG_NAME)) {
2660
+ customElements.define(TAG_NAME, WorkflowTrackerLit);
2661
+ }
2662
+ const el = document.createElement(TAG_NAME);
2663
+ el.runtimeRef = runtime3;
2664
+ container.appendChild(el);
2665
+ return () => {
2666
+ el.remove();
2667
+ };
2668
+ },
2669
+ update(container, config) {
2670
+ var _a2;
2671
+ const el = container.querySelector(TAG_NAME);
2672
+ if (!el)
2673
+ return;
2674
+ const runtime3 = (_a2 = config == null ? void 0 : config.runtime) != null ? _a2 : null;
2675
+ el.runtimeRef = runtime3;
2676
+ }
2677
+ };
2678
+
2506
2679
  // ../adaptives/adaptive-overlays/dist/runtime.js
2507
2680
  var executeHighlight = async (action, context) => {
2508
2681
  var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
@@ -2671,10 +2844,10 @@ var executeBadge = async (action, context) => {
2671
2844
  }
2672
2845
  } catch {
2673
2846
  }
2674
- const badge2 = document.createElement("div");
2675
- badge2.textContent = action.content;
2676
- badge2.setAttribute("data-syntro-badge", action.anchorId.selector);
2677
- Object.assign(badge2.style, {
2847
+ const badge = document.createElement("div");
2848
+ badge.textContent = action.content;
2849
+ badge.setAttribute("data-syntro-badge", action.anchorId.selector);
2850
+ Object.assign(badge.style, {
2678
2851
  position: "absolute",
2679
2852
  padding: "2px 6px",
2680
2853
  fontSize: "12px",
@@ -2692,19 +2865,19 @@ var executeBadge = async (action, context) => {
2692
2865
  if (getComputedStyle(anchorEl).position === "static") {
2693
2866
  anchorEl.style.position = "relative";
2694
2867
  }
2695
- anchorEl.appendChild(badge2);
2868
+ anchorEl.appendChild(badge);
2696
2869
  switch (position) {
2697
2870
  case "top-left":
2698
- Object.assign(badge2.style, { top: "-8px", left: "-8px" });
2871
+ Object.assign(badge.style, { top: "-8px", left: "-8px" });
2699
2872
  break;
2700
2873
  case "top-right":
2701
- Object.assign(badge2.style, { top: "-8px", right: "-8px" });
2874
+ Object.assign(badge.style, { top: "-8px", right: "-8px" });
2702
2875
  break;
2703
2876
  case "bottom-left":
2704
- Object.assign(badge2.style, { bottom: "-8px", left: "-8px" });
2877
+ Object.assign(badge.style, { bottom: "-8px", left: "-8px" });
2705
2878
  break;
2706
2879
  case "bottom-right":
2707
- Object.assign(badge2.style, { bottom: "-8px", right: "-8px" });
2880
+ Object.assign(badge.style, { bottom: "-8px", right: "-8px" });
2708
2881
  break;
2709
2882
  }
2710
2883
  context.publishEvent("action.applied", {
@@ -2717,7 +2890,7 @@ var executeBadge = async (action, context) => {
2717
2890
  return {
2718
2891
  cleanup: () => {
2719
2892
  try {
2720
- badge2.remove();
2893
+ badge.remove();
2721
2894
  } catch {
2722
2895
  }
2723
2896
  if (!anchorEl.isConnected)
@@ -2728,7 +2901,7 @@ var executeBadge = async (action, context) => {
2728
2901
  },
2729
2902
  updateFn: (changes) => {
2730
2903
  if ("content" in changes && typeof changes.content === "string") {
2731
- badge2.textContent = changes.content;
2904
+ badge.textContent = changes.content;
2732
2905
  }
2733
2906
  }
2734
2907
  };
@@ -2745,16 +2918,16 @@ var executeTooltip = async (action, context) => {
2745
2918
  } };
2746
2919
  }
2747
2920
  const { content } = action;
2748
- let html = "";
2921
+ let html2 = "";
2749
2922
  if (content.title) {
2750
- html += `<div class="syntro-tt-title">${sanitizeHtml2(content.title)}</div>`;
2923
+ html2 += `<div class="syntro-tt-title">${sanitizeHtml2(content.title)}</div>`;
2751
2924
  }
2752
- html += `<div class="syntro-tt-body">${sanitizeHtml2(content.body)}</div>`;
2925
+ html2 += `<div class="syntro-tt-body">${sanitizeHtml2(content.body)}</div>`;
2753
2926
  if (content.ctaButtons && content.ctaButtons.length > 0) {
2754
- html += `<div class="syntro-tt-actions">`;
2927
+ html2 += `<div class="syntro-tt-actions">`;
2755
2928
  for (const btn of content.ctaButtons) {
2756
2929
  const isPrimary = (_a2 = btn.primary) != null ? _a2 : false;
2757
- html += `
2930
+ html2 += `
2758
2931
  <button
2759
2932
  class="syntro-tt-btn ${isPrimary ? "syntro-tt-btn-primary" : ""}"
2760
2933
  data-syntro-action="${sanitizeHtml2(btn.actionId)}"
@@ -2763,16 +2936,16 @@ var executeTooltip = async (action, context) => {
2763
2936
  </button>
2764
2937
  `;
2765
2938
  }
2766
- html += `</div>`;
2939
+ html2 += `</div>`;
2767
2940
  } else if (content.cta) {
2768
- html += `<div class="syntro-tt-actions">
2941
+ html2 += `<div class="syntro-tt-actions">
2769
2942
  <button class="syntro-tt-btn syntro-tt-btn-primary" data-syntro-action="cta">
2770
2943
  ${sanitizeHtml2(content.cta.label)}
2771
2944
  </button>
2772
2945
  </div>`;
2773
2946
  }
2774
2947
  const handle = showTooltip(anchorEl, context.overlayRoot, {
2775
- html,
2948
+ html: html2,
2776
2949
  placement: (_b = action.placement) != null ? _b : "top",
2777
2950
  trigger: (_c = action.trigger) != null ? _c : "immediate",
2778
2951
  onAction: (actionId) => {
@@ -2834,6 +3007,15 @@ var runtime2 = {
2834
3007
  icon: "\u{1F4CB}",
2835
3008
  description: "Tracks multi-step workflow progress across tours"
2836
3009
  }
3010
+ },
3011
+ {
3012
+ id: "adaptive-overlays:workflow-tracker-lit",
3013
+ component: WorkflowWidgetLitMountable,
3014
+ metadata: {
3015
+ name: "Workflow Tracker (Lit)",
3016
+ icon: "\u{1F4CB}",
3017
+ description: "Lit web component equivalent of the Workflow Tracker \u2014 decorator-free, light DOM"
3018
+ }
2837
3019
  }
2838
3020
  ]
2839
3021
  };
@@ -2950,7 +3132,9 @@ var NAMESPACE_TO_APP_ID = {
2950
3132
  faq: "adaptive-faq",
2951
3133
  nav: "adaptive-nav",
2952
3134
  gamification: "adaptive-gamification",
2953
- chatbot: "adaptive-chatbot"
3135
+ chatbot: "adaptive-chatbot",
3136
+ overlays: "adaptive-overlays",
3137
+ content: "adaptive-content"
2954
3138
  };
2955
3139
  function resolveAppId(namespace) {
2956
3140
  var _a2;
@@ -3456,7 +3640,7 @@ function getAntiFlickerSnippet(config = {}) {
3456
3640
  }
3457
3641
 
3458
3642
  // src/version.ts
3459
- var SDK_VERSION = "2.14.0";
3643
+ var SDK_VERSION = "2.16.0";
3460
3644
 
3461
3645
  // src/types.ts
3462
3646
  var SDK_SCHEMA_VERSION = "2.0";
@@ -3981,6 +4165,7 @@ function parseElementsChain(chain) {
3981
4165
  if (!chain)
3982
4166
  return void 0;
3983
4167
  return chain.split(";").map((segment) => {
4168
+ var _a2;
3984
4169
  const el = {};
3985
4170
  const colonIdx = segment.indexOf(":");
3986
4171
  const tagPart = colonIdx >= 0 ? segment.slice(0, colonIdx) : segment;
@@ -3992,6 +4177,8 @@ function parseElementsChain(chain) {
3992
4177
  } else {
3993
4178
  el.tag_name = tagPart;
3994
4179
  }
4180
+ if (!/^[a-zA-Z][a-zA-Z0-9-]*$/.test(String((_a2 = el.tag_name) != null ? _a2 : "")))
4181
+ return null;
3995
4182
  const attrRegex = /([\w$]+)="([^"]*)"/g;
3996
4183
  let match;
3997
4184
  while ((match = attrRegex.exec(attrPart)) !== null) {
@@ -4005,7 +4192,7 @@ function parseElementsChain(chain) {
4005
4192
  delete el.text;
4006
4193
  }
4007
4194
  return el;
4008
- });
4195
+ }).filter((el) => el !== null);
4009
4196
  }
4010
4197
  function resolveInteractiveTag(elements, directTag) {
4011
4198
  if (directTag && INTERACTIVE_TAGS.has(directTag))
@@ -4013,9 +4200,9 @@ function resolveInteractiveTag(elements, directTag) {
4013
4200
  if (!elements)
4014
4201
  return directTag;
4015
4202
  for (const el of elements) {
4016
- const tag2 = el.tag_name;
4017
- if (tag2 && INTERACTIVE_TAGS.has(tag2))
4018
- return tag2;
4203
+ const tag = el.tag_name;
4204
+ if (tag && INTERACTIVE_TAGS.has(tag))
4205
+ return tag;
4019
4206
  }
4020
4207
  return directTag;
4021
4208
  }
@@ -4957,6 +5144,7 @@ function collectEntries(tiles, appRegistry2) {
4957
5144
  function useNotifyWatcher(runtime3, tiles, appRegistry2) {
4958
5145
  const prevStateRef = useRef3(/* @__PURE__ */ new Map());
4959
5146
  useEffect3(() => {
5147
+ var _a2;
4960
5148
  if (!(runtime3 == null ? void 0 : runtime3.events) || !appRegistry2) return;
4961
5149
  const entries = collectEntries(tiles, appRegistry2);
4962
5150
  if (entries.length === 0) return;
@@ -4971,11 +5159,11 @@ function useNotifyWatcher(runtime3, tiles, appRegistry2) {
4971
5159
  }
4972
5160
  }
4973
5161
  }
4974
- const unsub = runtime3.events.subscribe(() => {
4975
- var _a2;
5162
+ const reeval = () => {
5163
+ var _a3;
4976
5164
  for (const entry of entries) {
4977
5165
  const result = runtime3.evaluateSync(entry.strategy);
4978
- const wasVisible = (_a2 = prevStateRef.current.get(entry.id)) != null ? _a2 : false;
5166
+ const wasVisible = (_a3 = prevStateRef.current.get(entry.id)) != null ? _a3 : false;
4979
5167
  prevStateRef.current.set(entry.id, result.value);
4980
5168
  if (!wasVisible && result.value) {
4981
5169
  notifiedStore.set(entry.id, true);
@@ -4984,8 +5172,13 @@ function useNotifyWatcher(runtime3, tiles, appRegistry2) {
4984
5172
  notifiedStore.remove(entry.id);
4985
5173
  }
4986
5174
  }
4987
- });
4988
- return unsub;
5175
+ };
5176
+ const unsubEvents = runtime3.events.subscribe(reeval);
5177
+ const unsubMetrics = (_a2 = runtime3.sessionMetrics) == null ? void 0 : _a2.subscribe(reeval);
5178
+ return () => {
5179
+ unsubEvents();
5180
+ unsubMetrics == null ? void 0 : unsubMetrics();
5181
+ };
4989
5182
  }, [runtime3, tiles, appRegistry2]);
4990
5183
  }
4991
5184
 
@@ -5287,480 +5480,41 @@ function TileCard({
5287
5480
  }
5288
5481
  ),
5289
5482
  resolvedSubtitle && /* @__PURE__ */ jsx6(
5290
- "p",
5291
- {
5292
- style: {
5293
- fontSize: "0.8rem",
5294
- fontWeight: 400,
5295
- color: "var(--sc-tile-text-color)",
5296
- margin: "0.125rem 0 0",
5297
- whiteSpace: "nowrap",
5298
- overflow: "hidden",
5299
- textOverflow: "ellipsis"
5300
- },
5301
- children: resolvedSubtitle
5302
- }
5303
- )
5304
- ] })
5305
- ] }),
5306
- /* @__PURE__ */ jsx6(
5307
- "div",
5308
- {
5309
- style: {
5310
- padding: "var(--sc-tile-body-padding, 0 0.75rem 0.5rem)",
5311
- borderTop: "1px solid rgba(255, 255, 255, 0.06)"
5312
- },
5313
- children: /* @__PURE__ */ jsx6("div", { style: { paddingTop: "var(--sc-tile-gap, 0.25rem)" }, children: /* @__PURE__ */ jsx6(WidgetMount, { widgetId: widget, props: { ...props, instanceId: config.id } }) })
5314
- }
5315
- )
5316
- ]
5317
- }
5318
- );
5319
- }
5320
-
5321
- // src/components/ShadowCanvasOverlay.tsx
5322
- import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef5, useState as useState5 } from "react";
5323
- import { createPortal } from "react-dom";
5324
-
5325
- // src/theme/defaultTheme.ts
5326
- function withAlpha(hex, alpha) {
5327
- return `${hex}${Math.round(alpha * 255).toString(16).padStart(2, "0")}`;
5328
- }
5329
- var darkTheme = {
5330
- // Brand colors
5331
- colorPrimary: brand[3],
5332
- colorPrimaryHover: brand[4],
5333
- colorPrimaryMuted: brand[0],
5334
- // Surface colors (with alpha for glass/vibrancy effects)
5335
- colorBackground: withAlpha(slateGrey[1], 0.95),
5336
- colorBackgroundElevated: withAlpha(slateGrey[3], 0.95),
5337
- colorBackgroundSubtle: withAlpha(slateGrey[0], 0.2),
5338
- colorSurface: withAlpha(slateGrey[4], 0.8),
5339
- colorSurfaceHover: withAlpha(slateGrey[5], 0.8),
5340
- // Text colors
5341
- colorText: text.primary,
5342
- colorTextSecondary: text.secondary,
5343
- colorTextMuted: text.tertiary,
5344
- colorTextInverse: slateGrey[1],
5345
- // Border colors
5346
- colorBorder: border.primary,
5347
- colorBorderSubtle: border.secondary,
5348
- // Semantic colors
5349
- colorSuccess: green[4],
5350
- colorSuccessMuted: green[0],
5351
- colorWarning: yellow[4],
5352
- colorWarningMuted: yellow[0],
5353
- colorError: red[4],
5354
- colorErrorMuted: red[0],
5355
- colorInfo: blue[4],
5356
- colorInfoMuted: blue[0],
5357
- // Notification badge
5358
- colorNotification: brand[4],
5359
- colorNotificationMuted: withAlpha(brand[4], 0.4),
5360
- // Glass morphism
5361
- glassBackground: withAlpha(slateGrey[1], 0.6),
5362
- glassBackgroundHover: withAlpha(slateGrey[1], 0.7),
5363
- glassBorder: "rgba(255, 255, 255, 0.08)",
5364
- glassBlur: "blur(24px)",
5365
- glassSaturate: "saturate(1.2)",
5366
- // Typography (SF Pro stack)
5367
- fontFamily: "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif",
5368
- fontFamilyMono: "'SF Mono', 'Fira Code', Consolas, monospace",
5369
- fontSizeXs: "0.7rem",
5370
- fontSizeSm: "0.8rem",
5371
- fontSizeMd: "0.9rem",
5372
- fontSizeLg: "1rem",
5373
- fontSizeXl: "1.25rem",
5374
- fontSizeXxl: "1.5rem",
5375
- fontWeightNormal: "400",
5376
- fontWeightMedium: "500",
5377
- fontWeightSemibold: "600",
5378
- fontWeightBold: "700",
5379
- lineHeightTight: "1.25",
5380
- lineHeightNormal: "1.5",
5381
- lineHeightRelaxed: "1.75",
5382
- // Spacing
5383
- spacingXs: "0.25rem",
5384
- spacingSm: "0.5rem",
5385
- spacingMd: "0.75rem",
5386
- spacingLg: "1rem",
5387
- spacingXl: "1.5rem",
5388
- // Border radius
5389
- borderRadiusSm: "6px",
5390
- borderRadiusMd: "10px",
5391
- borderRadiusLg: "14px",
5392
- borderRadiusXl: "20px",
5393
- borderRadiusFull: "9999px",
5394
- // Shadows
5395
- shadowSm: "0 1px 2px rgba(0, 0, 0, 0.2)",
5396
- shadowMd: "0 2px 12px rgba(0, 0, 0, 0.3)",
5397
- shadowLg: "0 8px 24px rgba(0, 0, 0, 0.4)",
5398
- shadowXl: "0 16px 48px rgba(0, 0, 0, 0.5)",
5399
- // Backdrop effects
5400
- backdropBlur: "blur(20px)",
5401
- backdropSaturate: "saturate(180%)",
5402
- // Animation
5403
- transitionFast: "0.1s ease",
5404
- transitionNormal: "0.25s ease",
5405
- transitionSlow: "0.4s ease"
5406
- };
5407
- var lightTheme = {
5408
- // Brand colors
5409
- colorPrimary: brand[3],
5410
- colorPrimaryHover: brand[2],
5411
- colorPrimaryMuted: withAlpha(brand[5], 0.1),
5412
- // Surface colors
5413
- colorBackground: withAlpha(slateGrey[12], 0.95),
5414
- colorBackgroundElevated: withAlpha(slateGrey[11], 0.95),
5415
- colorBackgroundSubtle: withAlpha(slateGrey[0], 0.02),
5416
- colorSurface: withAlpha(slateGrey[11], 0.6),
5417
- colorSurfaceHover: withAlpha(slateGrey[10], 0.6),
5418
- // Text colors
5419
- colorText: slateGrey[1],
5420
- colorTextSecondary: slateGrey[6],
5421
- colorTextMuted: slateGrey[8],
5422
- colorTextInverse: slateGrey[12],
5423
- // Border colors
5424
- colorBorder: withAlpha(slateGrey[0], 0.12),
5425
- colorBorderSubtle: withAlpha(slateGrey[0], 0.06),
5426
- // Semantic colors
5427
- colorSuccess: green[4],
5428
- colorSuccessMuted: withAlpha(green[4], 0.12),
5429
- colorWarning: yellow[4],
5430
- colorWarningMuted: withAlpha(yellow[4], 0.12),
5431
- colorError: red[4],
5432
- colorErrorMuted: withAlpha(red[4], 0.12),
5433
- colorInfo: blue[4],
5434
- colorInfoMuted: withAlpha(blue[4], 0.12),
5435
- // Notification badge
5436
- colorNotification: brand[3],
5437
- colorNotificationMuted: withAlpha(brand[3], 0.4),
5438
- // Glass morphism
5439
- glassBackground: withAlpha(slateGrey[12], 0.7),
5440
- glassBackgroundHover: withAlpha(slateGrey[12], 0.8),
5441
- glassBorder: "rgba(0, 0, 0, 0.06)",
5442
- glassBlur: "blur(24px)",
5443
- glassSaturate: "saturate(1.2)",
5444
- // Typography (same as dark)
5445
- fontFamily: "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif",
5446
- fontFamilyMono: "'SF Mono', 'Fira Code', Consolas, monospace",
5447
- fontSizeXs: "0.7rem",
5448
- fontSizeSm: "0.8rem",
5449
- fontSizeMd: "0.9rem",
5450
- fontSizeLg: "1rem",
5451
- fontSizeXl: "1.25rem",
5452
- fontSizeXxl: "1.5rem",
5453
- fontWeightNormal: "400",
5454
- fontWeightMedium: "500",
5455
- fontWeightSemibold: "600",
5456
- fontWeightBold: "700",
5457
- lineHeightTight: "1.25",
5458
- lineHeightNormal: "1.5",
5459
- lineHeightRelaxed: "1.75",
5460
- // Spacing (same as dark)
5461
- spacingXs: "0.25rem",
5462
- spacingSm: "0.5rem",
5463
- spacingMd: "0.75rem",
5464
- spacingLg: "1rem",
5465
- spacingXl: "1.5rem",
5466
- // Border radius (same as dark)
5467
- borderRadiusSm: "6px",
5468
- borderRadiusMd: "10px",
5469
- borderRadiusLg: "14px",
5470
- borderRadiusXl: "20px",
5471
- borderRadiusFull: "9999px",
5472
- // Shadows (lighter for light mode)
5473
- shadowSm: "0 1px 2px rgba(0, 0, 0, 0.08)",
5474
- shadowMd: "0 2px 12px rgba(0, 0, 0, 0.12)",
5475
- shadowLg: "0 8px 24px rgba(0, 0, 0, 0.16)",
5476
- shadowXl: "0 16px 48px rgba(0, 0, 0, 0.2)",
5477
- // Backdrop effects
5478
- backdropBlur: "blur(20px)",
5479
- backdropSaturate: "saturate(180%)",
5480
- // Animation
5481
- transitionFast: "0.1s ease",
5482
- transitionNormal: "0.25s ease",
5483
- transitionSlow: "0.4s ease"
5484
- };
5485
- function kebabCase(str) {
5486
- return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
5487
- }
5488
- var darkDefaults = {
5489
- mode: "dark",
5490
- fontFamily: "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif",
5491
- colorPrimary: brand[3],
5492
- colorPrimaryHover: brand[4],
5493
- borderRadius: "12px",
5494
- canvas: {
5495
- position: "right",
5496
- layout: "overlay",
5497
- background: withAlpha(slateGrey[1], 0.6),
5498
- blur: "blur(24px)",
5499
- border: "none",
5500
- width: "clamp(380px, 25vw, 520px)",
5501
- transitionDuration: "300ms",
5502
- transitionEasing: "cubic-bezier(0.16, 1, 0.3, 1)",
5503
- transitionFade: "6%"
5504
- },
5505
- launcher: {
5506
- background: button.primary.backgroundDefault,
5507
- backgroundHover: button.primary.backgroundHover,
5508
- color: button.primary.icon,
5509
- size: "56px",
5510
- shadow: `0 8px 32px ${withAlpha(slateGrey[0], 0.6)}`,
5511
- borderRadius: "9999px"
5512
- },
5513
- tile: {
5514
- background: withAlpha(slateGrey[1], 0.6),
5515
- backgroundHover: withAlpha(slateGrey[1], 0.7),
5516
- border: "1px solid rgba(255, 255, 255, 0.08)",
5517
- borderRadius: "14px",
5518
- shadow: "0 2px 12px rgba(0, 0, 0, 0.3)",
5519
- titleColor: text.primary,
5520
- textColor: text.secondary,
5521
- iconBackground: `linear-gradient(135deg, ${brand[3]} 0%, ${brand[3]}cc 100%)`,
5522
- iconShadow: `0 2px 8px ${brand[3]}40`,
5523
- headerPadding: "0.375rem 0.75rem",
5524
- bodyPadding: "0 0.75rem 0.5rem",
5525
- gap: "0.25rem"
5526
- },
5527
- overlay: {
5528
- background: withAlpha(slateGrey[1], 0.6),
5529
- textColor: text.primary,
5530
- titleColor: text.primary,
5531
- arrowColor: withAlpha(slateGrey[1], 0.6),
5532
- arrowSize: "8px",
5533
- border: "none",
5534
- borderRadius: "0",
5535
- scrimOpacity: "0",
5536
- highlightRing: `2px solid ${brand[3]}`
5537
- },
5538
- notification: {
5539
- background: withAlpha(slateGrey[0], 0.95),
5540
- textColor: text.primary,
5541
- textSecondaryColor: text.secondary,
5542
- border: `1px solid ${slateGrey[5]}`,
5543
- borderRadius: "12px",
5544
- successColor: green[4],
5545
- warningColor: yellow[4],
5546
- errorColor: red[4],
5547
- iconBackground: withAlpha(brand[3], 0.15),
5548
- progressGradient: `linear-gradient(90deg, ${brand[3]}, ${brand[4]})`
5549
- },
5550
- content: {
5551
- background: withAlpha(slateGrey[3], 0.8),
5552
- backgroundHover: withAlpha(slateGrey[5], 0.6),
5553
- border: `1px solid ${withAlpha(slateGrey[5], 0.5)}`,
5554
- borderRadius: "8px",
5555
- textColor: text.primary,
5556
- textSecondaryColor: text.secondary,
5557
- itemDivider: "none",
5558
- itemGap: "6px",
5559
- itemPadding: "12px 16px",
5560
- itemFontSize: "15px",
5561
- bodyPadding: "0 16px 12px 16px",
5562
- bodyFontSize: "14px",
5563
- categoryPadding: "8px 4px 4px 4px",
5564
- categoryGap: "4px",
5565
- categoryFontSize: "12px",
5566
- searchBackground: withAlpha(slateGrey[3], 0.8),
5567
- searchColor: text.primary,
5568
- chevronColor: "currentColor"
5569
- }
5570
- };
5571
- var lightDefaults = {
5572
- mode: "light",
5573
- fontFamily: "-apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif",
5574
- colorPrimary: brand[3],
5575
- colorPrimaryHover: brand[2],
5576
- borderRadius: "12px",
5577
- canvas: {
5578
- position: "right",
5579
- layout: "overlay",
5580
- background: withAlpha(slateGrey[12], 0.7),
5581
- blur: "blur(24px)",
5582
- border: "none",
5583
- width: "clamp(380px, 25vw, 520px)",
5584
- transitionDuration: "300ms",
5585
- transitionEasing: "cubic-bezier(0.16, 1, 0.3, 1)",
5586
- transitionFade: "6%"
5587
- },
5588
- launcher: {
5589
- background: brand[3],
5590
- backgroundHover: brand[2],
5591
- color: "#ffffff",
5592
- size: "56px",
5593
- shadow: "0 8px 32px rgba(0, 0, 0, 0.15)",
5594
- borderRadius: "9999px"
5595
- },
5596
- tile: {
5597
- background: withAlpha(slateGrey[12], 0.7),
5598
- backgroundHover: withAlpha(slateGrey[12], 0.8),
5599
- border: "1px solid rgba(0, 0, 0, 0.06)",
5600
- borderRadius: "14px",
5601
- shadow: "0 2px 12px rgba(0, 0, 0, 0.12)",
5602
- titleColor: slateGrey[1],
5603
- textColor: slateGrey[6],
5604
- iconBackground: `linear-gradient(135deg, ${brand[3]} 0%, ${brand[3]}cc 100%)`,
5605
- iconShadow: `0 2px 8px ${brand[3]}40`,
5606
- headerPadding: "0.375rem 0.75rem",
5607
- bodyPadding: "0 0.75rem 0.5rem",
5608
- gap: "0.25rem"
5609
- },
5610
- overlay: {
5611
- background: withAlpha(slateGrey[12], 0.7),
5612
- textColor: slateGrey[1],
5613
- titleColor: slateGrey[1],
5614
- arrowColor: withAlpha(slateGrey[12], 0.7),
5615
- arrowSize: "8px",
5616
- border: "none",
5617
- borderRadius: "0",
5618
- scrimOpacity: "0",
5619
- highlightRing: `2px solid ${brand[3]}`
5620
- },
5621
- notification: {
5622
- background: withAlpha(slateGrey[12], 0.95),
5623
- textColor: slateGrey[1],
5624
- textSecondaryColor: slateGrey[6],
5625
- border: `1px solid ${withAlpha(slateGrey[0], 0.12)}`,
5626
- borderRadius: "12px",
5627
- successColor: green[4],
5628
- warningColor: yellow[4],
5629
- errorColor: red[4],
5630
- iconBackground: withAlpha(brand[3], 0.1),
5631
- progressGradient: `linear-gradient(90deg, ${brand[3]}, ${brand[2]})`
5632
- },
5633
- content: {
5634
- background: withAlpha(slateGrey[12], 0.8),
5635
- backgroundHover: withAlpha(slateGrey[11], 0.6),
5636
- border: `1px solid ${slateGrey[11]}`,
5637
- borderRadius: "8px",
5638
- textColor: slateGrey[1],
5639
- textSecondaryColor: slateGrey[6],
5640
- itemDivider: "none",
5641
- itemGap: "6px",
5642
- itemPadding: "12px 16px",
5643
- itemFontSize: "15px",
5644
- bodyPadding: "0 16px 12px 16px",
5645
- bodyFontSize: "14px",
5646
- categoryPadding: "8px 4px 4px 4px",
5647
- categoryGap: "4px",
5648
- categoryFontSize: "12px",
5649
- searchBackground: slateGrey[12],
5650
- searchColor: slateGrey[1],
5651
- chevronColor: "currentColor"
5652
- }
5653
- };
5654
- function mergeThemeConfig(customer) {
5655
- var _a2, _b, _c, _d, _e;
5656
- const base2 = customer.mode === "light" ? lightDefaults : darkDefaults;
5657
- return {
5658
- mode: (_a2 = customer.mode) != null ? _a2 : base2.mode,
5659
- fontFamily: (_b = customer.fontFamily) != null ? _b : base2.fontFamily,
5660
- colorPrimary: (_c = customer.colorPrimary) != null ? _c : base2.colorPrimary,
5661
- colorPrimaryHover: (_d = customer.colorPrimaryHover) != null ? _d : base2.colorPrimaryHover,
5662
- borderRadius: (_e = customer.borderRadius) != null ? _e : base2.borderRadius,
5663
- canvas: { ...base2.canvas, ...customer.canvas },
5664
- launcher: { ...base2.launcher, ...customer.launcher },
5665
- tile: { ...base2.tile, ...customer.tile },
5666
- overlay: { ...base2.overlay, ...customer.overlay },
5667
- notification: { ...base2.notification, ...customer.notification },
5668
- content: { ...base2.content, ...customer.content }
5669
- };
5670
- }
5671
- function mergeThemeWithWorkspace(workspaceTheme, configTheme) {
5672
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j;
5673
- const mode = (_b = (_a2 = configTheme.mode) != null ? _a2 : workspaceTheme.mode) != null ? _b : "dark";
5674
- const base2 = mode === "light" ? lightDefaults : darkDefaults;
5675
- return {
5676
- mode,
5677
- fontFamily: (_d = (_c = configTheme.fontFamily) != null ? _c : workspaceTheme.fontFamily) != null ? _d : base2.fontFamily,
5678
- colorPrimary: (_f = (_e = configTheme.colorPrimary) != null ? _e : workspaceTheme.colorPrimary) != null ? _f : base2.colorPrimary,
5679
- colorPrimaryHover: (_h = (_g = configTheme.colorPrimaryHover) != null ? _g : workspaceTheme.colorPrimaryHover) != null ? _h : base2.colorPrimaryHover,
5680
- borderRadius: (_j = (_i = configTheme.borderRadius) != null ? _i : workspaceTheme.borderRadius) != null ? _j : base2.borderRadius,
5681
- canvas: { ...base2.canvas, ...workspaceTheme.canvas, ...configTheme.canvas },
5682
- launcher: { ...base2.launcher, ...workspaceTheme.launcher, ...configTheme.launcher },
5683
- tile: { ...base2.tile, ...workspaceTheme.tile, ...configTheme.tile },
5684
- overlay: { ...base2.overlay, ...workspaceTheme.overlay, ...configTheme.overlay },
5685
- notification: {
5686
- ...base2.notification,
5687
- ...workspaceTheme.notification,
5688
- ...configTheme.notification
5689
- },
5690
- content: { ...base2.content, ...workspaceTheme.content, ...configTheme.content }
5691
- };
5692
- }
5693
- var ELEMENT_SECTIONS = [
5694
- "canvas",
5695
- "launcher",
5696
- "tile",
5697
- "overlay",
5698
- "notification",
5699
- "content"
5700
- ];
5701
- function flattenThemeConfig(config) {
5702
- const vars = {};
5703
- if (config.fontFamily) vars["--sc-font-family"] = config.fontFamily;
5704
- if (config.colorPrimary) vars["--sc-color-primary"] = config.colorPrimary;
5705
- if (config.colorPrimaryHover) vars["--sc-color-primary-hover"] = config.colorPrimaryHover;
5706
- if (config.borderRadius) vars["--sc-border-radius"] = config.borderRadius;
5707
- for (const section of ELEMENT_SECTIONS) {
5708
- const sectionConfig = config[section];
5709
- if (!sectionConfig) continue;
5710
- for (const [key, value] of Object.entries(sectionConfig)) {
5711
- if (value !== void 0) {
5712
- vars[`--sc-${section}-${kebabCase(key)}`] = value;
5713
- }
5714
- }
5715
- }
5716
- return vars;
5717
- }
5718
-
5719
- // src/theme/ThemeProvider.tsx
5720
- import { createContext as createContext3, useContext as useContext3, useEffect as useEffect6, useMemo as useMemo4 } from "react";
5721
- import { jsx as jsx7 } from "react/jsx-runtime";
5722
- var ThemeContext = createContext3(null);
5723
- function ThemeProvider({
5724
- children,
5725
- themeConfig,
5726
- workspaceTheme,
5727
- shadowRoot
5728
- }) {
5729
- const merged = useMemo4(
5730
- () => workspaceTheme ? mergeThemeWithWorkspace(workspaceTheme, themeConfig != null ? themeConfig : {}) : mergeThemeConfig(themeConfig != null ? themeConfig : {}),
5731
- [themeConfig, workspaceTheme]
5483
+ "p",
5484
+ {
5485
+ style: {
5486
+ fontSize: "0.8rem",
5487
+ fontWeight: 400,
5488
+ color: "var(--sc-tile-text-color)",
5489
+ margin: "0.125rem 0 0",
5490
+ whiteSpace: "nowrap",
5491
+ overflow: "hidden",
5492
+ textOverflow: "ellipsis"
5493
+ },
5494
+ children: resolvedSubtitle
5495
+ }
5496
+ )
5497
+ ] })
5498
+ ] }),
5499
+ /* @__PURE__ */ jsx6(
5500
+ "div",
5501
+ {
5502
+ style: {
5503
+ padding: "var(--sc-tile-body-padding, 0 0.75rem 0.5rem)",
5504
+ borderTop: "1px solid rgba(255, 255, 255, 0.06)"
5505
+ },
5506
+ children: /* @__PURE__ */ jsx6("div", { style: { paddingTop: "var(--sc-tile-gap, 0.25rem)" }, children: /* @__PURE__ */ jsx6(WidgetMount, { widgetId: widget, props: { ...props, instanceId: config.id } }) })
5507
+ }
5508
+ )
5509
+ ]
5510
+ }
5732
5511
  );
5733
- const cssVariables = useMemo4(() => flattenThemeConfig(merged), [merged]);
5734
- useEffect6(() => {
5735
- if (!shadowRoot) return;
5736
- let styleEl = shadowRoot.querySelector("#sc-theme-vars");
5737
- if (!styleEl) {
5738
- styleEl = document.createElement("style");
5739
- styleEl.id = "sc-theme-vars";
5740
- shadowRoot.insertBefore(styleEl, shadowRoot.firstChild);
5741
- }
5742
- const cssRules = Object.entries(cssVariables).map(([key, value2]) => ` ${key}: ${value2};`).join("\n");
5743
- styleEl.textContent = `:host {
5744
- ${cssRules}
5745
- }`;
5746
- }, [shadowRoot, cssVariables]);
5747
- const value = {
5748
- config: merged,
5749
- mode: merged.mode,
5750
- cssVariables
5751
- };
5752
- return /* @__PURE__ */ jsx7(ThemeContext.Provider, { value, children });
5753
- }
5754
- function useTheme() {
5755
- const context = useContext3(ThemeContext);
5756
- if (!context) {
5757
- throw new Error("useTheme must be used within a ThemeProvider");
5758
- }
5759
- return context;
5760
5512
  }
5761
5513
 
5762
5514
  // src/components/ShadowCanvasOverlay.tsx
5763
- import { Fragment, jsx as jsx8, jsxs as jsxs3 } from "react/jsx-runtime";
5515
+ import { useCallback as useCallback4, useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState5 } from "react";
5516
+ import { createPortal } from "react-dom";
5517
+ import { Fragment, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
5764
5518
  var LAUNCHER_STYLES_ID = "syntro-launcher-styles";
5765
5519
  function ensureLauncherStyles(target, css) {
5766
5520
  if (target.querySelector(`#${LAUNCHER_STYLES_ID}`)) return;
@@ -5818,7 +5572,7 @@ function ShadowCanvasOverlay({
5818
5572
  },
5819
5573
  [runtime3, isOpen, onToggle, dismissNotification]
5820
5574
  );
5821
- const launcherCss = useMemo5(
5575
+ const launcherCss = useMemo4(
5822
5576
  () => `
5823
5577
  @keyframes syntro-launcher-pulse {
5824
5578
  0%, 100% {
@@ -5855,7 +5609,7 @@ function ShadowCanvasOverlay({
5855
5609
  `,
5856
5610
  [config.colorPrimary, config.colorPrimaryHover]
5857
5611
  );
5858
- useEffect7(() => {
5612
+ useEffect6(() => {
5859
5613
  if (!isOpen) return;
5860
5614
  tiles.forEach((tile) => {
5861
5615
  telemetry == null ? void 0 : telemetry.trackRectangleViewed(tile.id, "overlay");
@@ -5865,11 +5619,11 @@ function ShadowCanvasOverlay({
5865
5619
  }
5866
5620
  });
5867
5621
  }, [telemetry, runtime3, isOpen, tiles]);
5868
- useEffect7(() => {
5622
+ useEffect6(() => {
5869
5623
  setMounted(true);
5870
5624
  ensureLauncherStyles(shadowRoot, launcherCss);
5871
5625
  }, [shadowRoot, launcherCss]);
5872
- const toggle2 = useCallback4(() => {
5626
+ const toggle = useCallback4(() => {
5873
5627
  const next = !isOpen;
5874
5628
  if (next) {
5875
5629
  telemetry == null ? void 0 : telemetry.trackCanvasOpened("overlay");
@@ -5882,17 +5636,17 @@ function ShadowCanvasOverlay({
5882
5636
  }
5883
5637
  onToggle();
5884
5638
  }, [isOpen, telemetry, runtime3, onToggle]);
5885
- useEffect7(() => {
5639
+ useEffect6(() => {
5886
5640
  if (!isOpen) return;
5887
5641
  const handleOutsideClick = (e) => {
5888
5642
  const path = e.composedPath();
5889
5643
  if (containerRef.current && !path.includes(containerRef.current) && launcherRef.current && !path.includes(launcherRef.current)) {
5890
- toggle2();
5644
+ toggle();
5891
5645
  }
5892
5646
  };
5893
5647
  document.addEventListener("mousedown", handleOutsideClick);
5894
5648
  return () => document.removeEventListener("mousedown", handleOutsideClick);
5895
- }, [isOpen, toggle2]);
5649
+ }, [isOpen, toggle]);
5896
5650
  const onLauncherPointerDown = useCallback4((e) => {
5897
5651
  const rect = e.currentTarget.getBoundingClientRect();
5898
5652
  dragRef.current = {
@@ -5921,10 +5675,10 @@ function ShadowCanvasOverlay({
5921
5675
  const drag = dragRef.current;
5922
5676
  dragRef.current = null;
5923
5677
  if (drag && !drag.dragged) {
5924
- toggle2();
5678
+ toggle();
5925
5679
  }
5926
5680
  },
5927
- [toggle2]
5681
+ [toggle]
5928
5682
  );
5929
5683
  const isFocused = displayMode === "focused";
5930
5684
  const isRight = config.canvas.position === "right";
@@ -5933,7 +5687,7 @@ function ShadowCanvasOverlay({
5933
5687
  const containerRef = useRef5(null);
5934
5688
  const launcherRef = useRef5(null);
5935
5689
  const zIndex = 2147483600;
5936
- useEffect7(() => {
5690
+ useEffect6(() => {
5937
5691
  var _a3, _b2, _c2, _d2;
5938
5692
  if (!isPush) return;
5939
5693
  const root = document.documentElement;
@@ -5953,7 +5707,7 @@ function ShadowCanvasOverlay({
5953
5707
  root.style.transition = prevTransition;
5954
5708
  };
5955
5709
  }, [isPush, isOpen, isRight, config.canvas.transitionDuration, config.canvas.transitionEasing]);
5956
- useEffect7(() => {
5710
+ useEffect6(() => {
5957
5711
  if (!isPush || !isOpen) return;
5958
5712
  const container = containerRef.current;
5959
5713
  if (!container) return;
@@ -6012,7 +5766,7 @@ function ShadowCanvasOverlay({
6012
5766
  pointerEvents: "none",
6013
5767
  padding: "0"
6014
5768
  };
6015
- const content = /* @__PURE__ */ jsx8(
5769
+ const content = /* @__PURE__ */ jsx7(
6016
5770
  "div",
6017
5771
  {
6018
5772
  "data-shadow-canvas-id": "overlay-root",
@@ -6024,7 +5778,7 @@ function ShadowCanvasOverlay({
6024
5778
  },
6025
5779
  children: /* @__PURE__ */ jsxs3("div", { style: wrapperStyle, children: [
6026
5780
  /* @__PURE__ */ jsxs3("div", { ref: containerRef, "data-shadow-canvas-id": "overlay-container", style: containerStyle, children: [
6027
- isFocused && canvasTitle && /* @__PURE__ */ jsx8("header", { style: { color: "white", padding: "1.5rem 1.5rem 0" }, children: /* @__PURE__ */ jsx8(
5781
+ isFocused && canvasTitle && /* @__PURE__ */ jsx7("header", { style: { color: "white", padding: "1.5rem 1.5rem 0" }, children: /* @__PURE__ */ jsx7(
6028
5782
  "p",
6029
5783
  {
6030
5784
  style: {
@@ -6037,7 +5791,7 @@ function ShadowCanvasOverlay({
6037
5791
  children: canvasTitle
6038
5792
  }
6039
5793
  ) }),
6040
- /* @__PURE__ */ jsx8("div", { style: { flex: 1, overflowY: "auto", padding: isFocused ? "0" : "1rem" }, children: isLoading ? /* @__PURE__ */ jsx8(
5794
+ /* @__PURE__ */ jsx7("div", { style: { flex: 1, overflowY: "auto", padding: isFocused ? "0" : "1rem" }, children: isLoading ? /* @__PURE__ */ jsx7(
6041
5795
  "div",
6042
5796
  {
6043
5797
  style: { color: "var(--sc-overlay-text-color)", padding: isFocused ? "1rem" : "0" },
@@ -6057,7 +5811,7 @@ function ShadowCanvasOverlay({
6057
5811
  }
6058
5812
  ) : isFocused ? (
6059
5813
  /* Focused Mode: Render first tile full size */
6060
- tiles.length > 0 ? /* @__PURE__ */ jsx8(
5814
+ tiles.length > 0 ? /* @__PURE__ */ jsx7(
6061
5815
  TileCard,
6062
5816
  {
6063
5817
  config: tiles[0],
@@ -6068,7 +5822,7 @@ function ShadowCanvasOverlay({
6068
5822
  ) : null
6069
5823
  ) : (
6070
5824
  /* Standard Mode: Stacked cards — widgets always visible */
6071
- /* @__PURE__ */ jsx8(
5825
+ /* @__PURE__ */ jsx7(
6072
5826
  "div",
6073
5827
  {
6074
5828
  style: {
@@ -6077,7 +5831,7 @@ function ShadowCanvasOverlay({
6077
5831
  gap: "0.75rem",
6078
5832
  width: "100%"
6079
5833
  },
6080
- children: tiles.map((tile) => /* @__PURE__ */ jsx8(
5834
+ children: tiles.map((tile) => /* @__PURE__ */ jsx7(
6081
5835
  TileCard,
6082
5836
  {
6083
5837
  config: tile,
@@ -6092,7 +5846,7 @@ function ShadowCanvasOverlay({
6092
5846
  ) }),
6093
5847
  footerSlot
6094
5848
  ] }),
6095
- /* @__PURE__ */ jsx8("div", { style: { flex: "1 1 auto" } })
5849
+ /* @__PURE__ */ jsx7("div", { style: { flex: "1 1 auto" } })
6096
5850
  ] })
6097
5851
  }
6098
5852
  );
@@ -6110,7 +5864,7 @@ function ShadowCanvasOverlay({
6110
5864
  zIndex: zIndex + 47
6111
5865
  },
6112
5866
  children: [
6113
- /* @__PURE__ */ jsx8(
5867
+ /* @__PURE__ */ jsx7(
6114
5868
  NotificationToastStack,
6115
5869
  {
6116
5870
  notifications,
@@ -6181,11 +5935,11 @@ function ShadowCanvasOverlay({
6181
5935
  focusable: "false",
6182
5936
  style: { transition: "transform 200ms ease" },
6183
5937
  children: [
6184
- /* @__PURE__ */ jsx8("path", { d: "M18 6L6 18" }),
6185
- /* @__PURE__ */ jsx8("path", { d: "M6 6l12 12" })
5938
+ /* @__PURE__ */ jsx7("path", { d: "M18 6L6 18" }),
5939
+ /* @__PURE__ */ jsx7("path", { d: "M6 6l12 12" })
6186
5940
  ]
6187
5941
  }
6188
- ) : ((_e = config.launcher) == null ? void 0 : _e.icon) ? /* @__PURE__ */ jsx8(
5942
+ ) : ((_e = config.launcher) == null ? void 0 : _e.icon) ? /* @__PURE__ */ jsx7(
6189
5943
  "img",
6190
5944
  {
6191
5945
  src: config.launcher.icon,
@@ -6213,16 +5967,16 @@ function ShadowCanvasOverlay({
6213
5967
  focusable: "false",
6214
5968
  style: { transition: "transform 200ms ease" },
6215
5969
  children: [
6216
- /* @__PURE__ */ jsx8("path", { d: "M12 3l1.912 5.813a2 2 0 0 0 1.275 1.275L21 12l-5.813 1.912a2 2 0 0 0-1.275 1.275L12 21l-1.912-5.813a2 2 0 0 0-1.275-1.275L3 12l5.813-1.912a2 2 0 0 0 1.275-1.275L12 3Z" }),
6217
- /* @__PURE__ */ jsx8("path", { d: "M5 3v4" }),
6218
- /* @__PURE__ */ jsx8("path", { d: "M3 5h4" }),
6219
- /* @__PURE__ */ jsx8("path", { d: "M19 17v4" }),
6220
- /* @__PURE__ */ jsx8("path", { d: "M17 19h4" })
5970
+ /* @__PURE__ */ jsx7("path", { d: "M12 3l1.912 5.813a2 2 0 0 0 1.275 1.275L21 12l-5.813 1.912a2 2 0 0 0-1.275 1.275L12 21l-1.912-5.813a2 2 0 0 0-1.275-1.275L3 12l5.813-1.912a2 2 0 0 0 1.275-1.275L12 3Z" }),
5971
+ /* @__PURE__ */ jsx7("path", { d: "M5 3v4" }),
5972
+ /* @__PURE__ */ jsx7("path", { d: "M3 5h4" }),
5973
+ /* @__PURE__ */ jsx7("path", { d: "M19 17v4" }),
5974
+ /* @__PURE__ */ jsx7("path", { d: "M17 19h4" })
6221
5975
  ]
6222
5976
  }
6223
5977
  ),
6224
5978
  !isOpen && notifications.length > 0 && /* @__PURE__ */ jsxs3("div", { style: { position: "absolute", top: -2, right: -2, pointerEvents: "none" }, children: [
6225
- /* @__PURE__ */ jsx8(
5979
+ /* @__PURE__ */ jsx7(
6226
5980
  "span",
6227
5981
  {
6228
5982
  className: "syntro-badge-ping",
@@ -6234,7 +5988,7 @@ function ShadowCanvasOverlay({
6234
5988
  }
6235
5989
  }
6236
5990
  ),
6237
- /* @__PURE__ */ jsx8(
5991
+ /* @__PURE__ */ jsx7(
6238
5992
  "span",
6239
5993
  {
6240
5994
  className: "syntro-badge-glow",
@@ -6245,7 +5999,7 @@ function ShadowCanvasOverlay({
6245
5999
  }
6246
6000
  }
6247
6001
  ),
6248
- /* @__PURE__ */ jsx8(
6002
+ /* @__PURE__ */ jsx7(
6249
6003
  "span",
6250
6004
  {
6251
6005
  className: "syntro-badge-bounce",
@@ -6279,7 +6033,7 @@ function ShadowCanvasOverlay({
6279
6033
  }
6280
6034
 
6281
6035
  // src/hooks/useShadowCanvasConfig.ts
6282
- import { useCallback as useCallback5, useEffect as useEffect8, useMemo as useMemo6, useRef as useRef6, useState as useState6 } from "react";
6036
+ import { useCallback as useCallback5, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef6, useState as useState6 } from "react";
6283
6037
  var sortTiles = (tiles) => [...tiles].sort((a, b) => {
6284
6038
  var _a2, _b;
6285
6039
  return ((_a2 = b.priority) != null ? _a2 : 0) - ((_b = a.priority) != null ? _b : 0);
@@ -6360,37 +6114,37 @@ function useShadowCanvasConfig({
6360
6114
  }));
6361
6115
  }
6362
6116
  }, [experiments, fetcher, runtime3]);
6363
- useEffect8(() => {
6117
+ useEffect7(() => {
6364
6118
  load();
6365
6119
  if (experiments == null ? void 0 : experiments.onFeaturesChanged) {
6366
6120
  return experiments.onFeaturesChanged(() => load());
6367
6121
  }
6368
6122
  }, [load, experiments, pageUrl]);
6369
- useEffect8(() => {
6123
+ useEffect7(() => {
6370
6124
  if (!(runtime3 == null ? void 0 : runtime3.accumulator)) return;
6371
6125
  return runtime3.accumulator.subscribe(() => {
6372
6126
  refilter();
6373
6127
  });
6374
6128
  }, [runtime3, refilter]);
6375
- useEffect8(() => {
6129
+ useEffect7(() => {
6376
6130
  if (!(runtime3 == null ? void 0 : runtime3.context)) return;
6377
6131
  return runtime3.context.subscribe(() => {
6378
6132
  refilter();
6379
6133
  });
6380
6134
  }, [runtime3, refilter]);
6381
- useEffect8(() => {
6135
+ useEffect7(() => {
6382
6136
  if (!pollIntervalMs) return;
6383
6137
  const id = setInterval(() => {
6384
6138
  load();
6385
6139
  }, pollIntervalMs);
6386
6140
  return () => clearInterval(id);
6387
6141
  }, [load, pollIntervalMs]);
6388
- return useMemo6(() => state, [state]);
6142
+ return useMemo5(() => state, [state]);
6389
6143
  }
6390
6144
 
6391
6145
  // src/SmartCanvasApp.tsx
6392
- import { useEffect as useEffect9, useMemo as useMemo7, useRef as useRef7, useState as useState7 } from "react";
6393
- import { jsx as jsx9 } from "react/jsx-runtime";
6146
+ import { useEffect as useEffect8, useMemo as useMemo6, useRef as useRef7, useState as useState7 } from "react";
6147
+ import { jsx as jsx8 } from "react/jsx-runtime";
6394
6148
  function SmartCanvasApp({
6395
6149
  controller,
6396
6150
  fetcher,
@@ -6410,10 +6164,11 @@ function SmartCanvasApp({
6410
6164
  launcherLabel,
6411
6165
  canvasHost,
6412
6166
  initialBatchHandle,
6413
- workspaceTheme
6167
+ workspaceTheme,
6168
+ platformAdapter
6414
6169
  }) {
6415
6170
  if (runtime3) {
6416
- return /* @__PURE__ */ jsx9(RuntimeProvider, { runtime: runtime3, children: /* @__PURE__ */ jsx9(
6171
+ return /* @__PURE__ */ jsx8(RuntimeProvider, { runtime: runtime3, children: /* @__PURE__ */ jsx8(
6417
6172
  SmartCanvasAppInner,
6418
6173
  {
6419
6174
  controller,
@@ -6434,11 +6189,12 @@ function SmartCanvasApp({
6434
6189
  launcherLabel,
6435
6190
  canvasHost,
6436
6191
  initialBatchHandle,
6437
- workspaceTheme
6192
+ workspaceTheme,
6193
+ platformAdapter
6438
6194
  }
6439
6195
  ) });
6440
6196
  }
6441
- return /* @__PURE__ */ jsx9(
6197
+ return /* @__PURE__ */ jsx8(
6442
6198
  SmartCanvasAppInner,
6443
6199
  {
6444
6200
  controller,
@@ -6458,7 +6214,8 @@ function SmartCanvasApp({
6458
6214
  launcherLabel,
6459
6215
  canvasHost,
6460
6216
  initialBatchHandle,
6461
- workspaceTheme
6217
+ workspaceTheme,
6218
+ platformAdapter
6462
6219
  }
6463
6220
  );
6464
6221
  }
@@ -6481,7 +6238,8 @@ function SmartCanvasAppInner({
6481
6238
  launcherLabel,
6482
6239
  canvasHost: _canvasHost,
6483
6240
  initialBatchHandle,
6484
- workspaceTheme
6241
+ workspaceTheme,
6242
+ platformAdapter
6485
6243
  }) {
6486
6244
  var _a2, _b, _c, _d, _e, _f;
6487
6245
  const [open, setOpen] = useState7(controller.getState().open);
@@ -6489,31 +6247,20 @@ function SmartCanvasAppInner({
6489
6247
  const [localUrl, setLocalUrl] = useState7(
6490
6248
  () => typeof window !== "undefined" ? window.location.href : "/"
6491
6249
  );
6250
+ const [reapplyTick, setReapplyTick] = useState7(0);
6492
6251
  const pageUrl = (_a2 = pageContext == null ? void 0 : pageContext.url) != null ? _a2 : localUrl;
6493
- useEffect9(() => {
6252
+ useEffect8(() => {
6494
6253
  if (runtime3) return;
6495
6254
  if (typeof window === "undefined") return;
6496
6255
  const updateUrl = () => setLocalUrl(window.location.href);
6497
6256
  window.addEventListener("popstate", updateUrl);
6498
6257
  window.addEventListener("hashchange", updateUrl);
6499
- const originalPushState = history.pushState;
6500
- const originalReplaceState = history.replaceState;
6501
- history.pushState = function(...args) {
6502
- originalPushState.apply(this, args);
6503
- queueMicrotask(updateUrl);
6504
- };
6505
- history.replaceState = function(...args) {
6506
- originalReplaceState.apply(this, args);
6507
- queueMicrotask(updateUrl);
6508
- };
6509
6258
  return () => {
6510
6259
  window.removeEventListener("popstate", updateUrl);
6511
6260
  window.removeEventListener("hashchange", updateUrl);
6512
- history.pushState = originalPushState;
6513
- history.replaceState = originalReplaceState;
6514
6261
  };
6515
6262
  }, [runtime3]);
6516
- const derivedFetcher = useMemo7(() => {
6263
+ const derivedFetcher = useMemo6(() => {
6517
6264
  if (fetcher) return fetcher;
6518
6265
  return createCanvasConfigFetcher({
6519
6266
  configUri,
@@ -6530,8 +6277,8 @@ function SmartCanvasAppInner({
6530
6277
  pageUrl
6531
6278
  });
6532
6279
  const hasContent = configState.tiles.length > 0 && !configState.error;
6533
- useEffect9(() => controller.subscribe((state) => setOpen(state.open)), [controller]);
6534
- useEffect9(() => {
6280
+ useEffect8(() => controller.subscribe((state) => setOpen(state.open)), [controller]);
6281
+ useEffect8(() => {
6535
6282
  if (!configState.isLoading && !hasContent && controller.getState().open) {
6536
6283
  controller.setOpen(false);
6537
6284
  }
@@ -6540,7 +6287,7 @@ function SmartCanvasAppInner({
6540
6287
  const adoptedInitialRef = useRef7(!!initialBatchHandle);
6541
6288
  const runVersionRef = useRef7(0);
6542
6289
  const pendingRevertRef = useRef7(null);
6543
- useEffect9(() => {
6290
+ useEffect8(() => {
6544
6291
  if (!(runtime3 == null ? void 0 : runtime3.actions)) return;
6545
6292
  if (adoptedInitialRef.current) {
6546
6293
  if (configState.actions.length > 0) {
@@ -6552,7 +6299,11 @@ function SmartCanvasAppInner({
6552
6299
  const stale = () => version !== runVersionRef.current;
6553
6300
  const run = async () => {
6554
6301
  if (pendingRevertRef.current) {
6555
- await pendingRevertRef.current;
6302
+ try {
6303
+ await pendingRevertRef.current;
6304
+ } catch (err) {
6305
+ console.error("[SmartCanvasApp] Pending revert failed:", err);
6306
+ }
6556
6307
  pendingRevertRef.current = null;
6557
6308
  }
6558
6309
  if (batchHandleRef.current) {
@@ -6588,23 +6339,31 @@ function SmartCanvasAppInner({
6588
6339
  batchHandleRef.current = null;
6589
6340
  }
6590
6341
  };
6591
- }, [runtime3, configState.actions, pageUrl]);
6592
- useEffect9(() => {
6342
+ }, [runtime3, configState.actions, pageUrl, reapplyTick]);
6343
+ useEffect8(() => {
6593
6344
  if (!runtime3) return;
6594
6345
  return runtime3.events.subscribe(
6595
6346
  { names: ["canvas.requestOpen"] },
6596
6347
  () => controller.setOpen(true)
6597
6348
  );
6598
6349
  }, [runtime3, controller]);
6350
+ useEffect8(() => {
6351
+ if (!platformAdapter || !(runtime3 == null ? void 0 : runtime3.actions)) return;
6352
+ const unsub = platformAdapter.onRegionDidLoad((regionId) => {
6353
+ console.log(`[SmartCanvasApp] Platform region reloaded: ${regionId}, re-applying actions`);
6354
+ setReapplyTick((t) => t + 1);
6355
+ });
6356
+ return unsub;
6357
+ }, [platformAdapter, runtime3]);
6599
6358
  const { shadowRoot } = useShadowRoot();
6600
6359
  const themeConfig = configState.theme;
6601
- return /* @__PURE__ */ jsx9(
6360
+ return /* @__PURE__ */ jsx8(
6602
6361
  ThemeProvider,
6603
6362
  {
6604
6363
  themeConfig,
6605
6364
  workspaceTheme,
6606
6365
  shadowRoot,
6607
- children: !configState.isLoading && !hasContent ? null : /* @__PURE__ */ jsx9(
6366
+ children: !configState.isLoading && !hasContent ? null : /* @__PURE__ */ jsx8(
6608
6367
  ShadowCanvasOverlay,
6609
6368
  {
6610
6369
  tiles: configState.tiles,
@@ -6628,8 +6387,8 @@ function SmartCanvasAppInner({
6628
6387
 
6629
6388
  // src/SmartCanvasElement.tsx
6630
6389
  import { createRoot as createRoot2 } from "react-dom/client";
6631
- import { jsx as jsx10 } from "react/jsx-runtime";
6632
- var TAG_NAME = "smart-canvas";
6390
+ import { jsx as jsx9 } from "react/jsx-runtime";
6391
+ var TAG_NAME2 = "smart-canvas";
6633
6392
  var BASE_CSS = `
6634
6393
  :host {
6635
6394
  font: inherit;
@@ -6729,13 +6488,13 @@ var SmartCanvasElement = class extends HTMLElement {
6729
6488
  __privateSet(this, _root, createRoot2(__privateGet(this, _mount)));
6730
6489
  }
6731
6490
  __privateGet(this, _root).render(
6732
- /* @__PURE__ */ jsx10(
6491
+ /* @__PURE__ */ jsx9(
6733
6492
  ShadowRootProvider,
6734
6493
  {
6735
6494
  shadowRoot: __privateGet(this, _shadow),
6736
6495
  portalRoot: __privateGet(this, _portalRoot),
6737
6496
  overlayContainer: __privateGet(this, _overlayContainer),
6738
- children: /* @__PURE__ */ jsx10(SmartCanvasApp, { ...__privateGet(this, _lastAppProps), controller: __privateGet(this, _controller), canvasHost: this })
6497
+ children: /* @__PURE__ */ jsx9(SmartCanvasApp, { ...__privateGet(this, _lastAppProps), controller: __privateGet(this, _controller), canvasHost: this })
6739
6498
  }
6740
6499
  )
6741
6500
  );
@@ -6761,8 +6520,8 @@ _root = new WeakMap();
6761
6520
  _lastAppProps = new WeakMap();
6762
6521
  var registerSmartCanvasElement = () => {
6763
6522
  if (typeof window === "undefined") return;
6764
- if (!customElements.get(TAG_NAME)) {
6765
- customElements.define(TAG_NAME, SmartCanvasElement);
6523
+ if (!customElements.get(TAG_NAME2)) {
6524
+ customElements.define(TAG_NAME2, SmartCanvasElement);
6766
6525
  }
6767
6526
  };
6768
6527
 
@@ -6789,6 +6548,23 @@ function decodeParam(paramName) {
6789
6548
  return null;
6790
6549
  }
6791
6550
  }
6551
+ var STORAGE_KEY_SOURCE = "__syntro_rt_editor_source";
6552
+ var STORAGE_KEY_CONF = "__syntro_rt_editor_conf";
6553
+ function persistToStorage(key, value) {
6554
+ try {
6555
+ sessionStorage.setItem(key, JSON.stringify(value));
6556
+ } catch {
6557
+ }
6558
+ }
6559
+ function readFromStorage(key) {
6560
+ try {
6561
+ const raw = sessionStorage.getItem(key);
6562
+ if (!raw) return null;
6563
+ return JSON.parse(raw);
6564
+ } catch {
6565
+ return null;
6566
+ }
6567
+ }
6792
6568
  var _cachedSource;
6793
6569
  var _cachedConf;
6794
6570
  function getEditorSource() {
@@ -6797,6 +6573,7 @@ function getEditorSource() {
6797
6573
  const globalParams = typeof window !== "undefined" ? window.__SYNTRO_EDITOR_PARAMS__ : null;
6798
6574
  if (globalParams == null ? void 0 : globalParams.token) {
6799
6575
  _cachedSource = { token: globalParams.token, api_base: globalParams.apiBase || "" };
6576
+ persistToStorage(STORAGE_KEY_SOURCE, _cachedSource);
6800
6577
  console.log(
6801
6578
  `[DIAG] getEditorSource: from __SYNTRO_EDITOR_PARAMS__ (token=${_cachedSource.token.slice(0, 15)}...)`
6802
6579
  );
@@ -6804,6 +6581,15 @@ function getEditorSource() {
6804
6581
  const decoded = decodeParam("editor_source");
6805
6582
  if (decoded) {
6806
6583
  _cachedSource = decoded;
6584
+ persistToStorage(STORAGE_KEY_SOURCE, decoded);
6585
+ } else {
6586
+ const fromStorage = readFromStorage(STORAGE_KEY_SOURCE);
6587
+ if (fromStorage == null ? void 0 : fromStorage.token) {
6588
+ _cachedSource = fromStorage;
6589
+ console.log(
6590
+ `[DIAG] getEditorSource: restored from sessionStorage (token=${fromStorage.token.slice(0, 15)}...)`
6591
+ );
6592
+ }
6807
6593
  }
6808
6594
  console.log(
6809
6595
  `[DIAG] getEditorSource: from URL param \u2192 ${decoded ? `token=${(_a2 = decoded.token) == null ? void 0 : _a2.slice(0, 15)}...` : "NULL"}`
@@ -6825,11 +6611,21 @@ function getEditorConf() {
6825
6611
  syntro_token: globalParams.syntroToken,
6826
6612
  workspace_id: globalParams.workspaceId
6827
6613
  };
6614
+ persistToStorage(STORAGE_KEY_CONF, _cachedConf);
6828
6615
  console.log(`[DIAG] getEditorConf: from __SYNTRO_EDITOR_PARAMS__ (mode=${_cachedConf.mode})`);
6829
6616
  } else {
6830
6617
  const decoded = decodeParam("editor_conf");
6831
6618
  if (decoded) {
6832
6619
  _cachedConf = decoded;
6620
+ persistToStorage(STORAGE_KEY_CONF, decoded);
6621
+ } else {
6622
+ const fromStorage = readFromStorage(STORAGE_KEY_CONF);
6623
+ if (fromStorage == null ? void 0 : fromStorage.mode) {
6624
+ _cachedConf = fromStorage;
6625
+ console.log(
6626
+ `[DIAG] getEditorConf: restored from sessionStorage (mode=${fromStorage.mode})`
6627
+ );
6628
+ }
6833
6629
  }
6834
6630
  console.log(
6835
6631
  `[DIAG] getEditorConf: from URL param \u2192 ${decoded ? `mode=${decoded.mode}` : "NULL"}`
@@ -6912,18 +6708,13 @@ var loadEditorSdk = async (editorUrlOrOptions) => {
6912
6708
  return;
6913
6709
  }
6914
6710
  const token = getToken();
6915
- if (!token) {
6916
- warn("Syntro Runtime", "\u274C No token found in editor_source.");
6917
- debug("Syntro Runtime", "================================");
6918
- return;
6919
- }
6920
- const editorUrl = `${baseEditorUrl}?token=${encodeURIComponent(token)}`;
6711
+ const editorUrl = token ? `${baseEditorUrl}?token=${encodeURIComponent(token)}` : baseEditorUrl;
6921
6712
  debug("Syntro Runtime", "Editor URL:", editorUrl);
6922
6713
  debug("Syntro Runtime", "Options:", {
6923
6714
  hasIntegrity: !!options.integrity,
6924
6715
  hasEditorUrl: !!baseEditorUrl,
6925
6716
  hasApiBase: !!apiBase,
6926
- tokenPrefix: `${token.slice(0, 10)}...`
6717
+ tokenPrefix: token ? `${token.slice(0, 10)}...` : "none"
6927
6718
  });
6928
6719
  if (!validateEditorUrl(baseEditorUrl)) {
6929
6720
  console.error("[Syntro Runtime] \u274C BLOCKED: Editor from untrusted URL:", baseEditorUrl);
@@ -7372,7 +7163,8 @@ var createSmartCanvas = async (config = {}) => {
7372
7163
  configUriFeatureKey: config.configUriFeatureKey,
7373
7164
  fetchCredentials: config.fetchCredentials,
7374
7165
  initialBatchHandle: currentBatchHandle,
7375
- workspaceTheme: config.workspaceTheme
7166
+ workspaceTheme: config.workspaceTheme,
7167
+ platformAdapter: config.platformAdapter
7376
7168
  };
7377
7169
  host.mountReactApp(appProps);
7378
7170
  if (config.defaultOpen) {
@@ -7545,6 +7337,7 @@ var STORAGE_KEY = "syntro_session_metrics";
7545
7337
  var SessionMetricTracker = class {
7546
7338
  constructor(options = {}) {
7547
7339
  __publicField(this, "metrics", /* @__PURE__ */ new Map());
7340
+ __publicField(this, "subscribers", /* @__PURE__ */ new Set());
7548
7341
  __publicField(this, "experiments");
7549
7342
  __publicField(this, "attributePrefix");
7550
7343
  __publicField(this, "onMetricChange");
@@ -7569,6 +7362,7 @@ var SessionMetricTracker = class {
7569
7362
  this.saveToStorage();
7570
7363
  this.updateExperimentAttributes(metricKey, newValue);
7571
7364
  (_b = this.onMetricChange) == null ? void 0 : _b.call(this, metricKey, newValue);
7365
+ this.notifySubscribers();
7572
7366
  return newValue;
7573
7367
  }
7574
7368
  /**
@@ -7583,6 +7377,7 @@ var SessionMetricTracker = class {
7583
7377
  this.saveToStorage();
7584
7378
  this.updateExperimentAttributes(metricKey, value);
7585
7379
  (_a2 = this.onMetricChange) == null ? void 0 : _a2.call(this, metricKey, value);
7380
+ this.notifySubscribers();
7586
7381
  }
7587
7382
  /**
7588
7383
  * Get the current value of a metric.
@@ -7623,6 +7418,7 @@ var SessionMetricTracker = class {
7623
7418
  this.saveToStorage();
7624
7419
  this.updateExperimentAttributes(metricKey, 0);
7625
7420
  (_a2 = this.onMetricChange) == null ? void 0 : _a2.call(this, metricKey, 0);
7421
+ this.notifySubscribers();
7626
7422
  }
7627
7423
  /**
7628
7424
  * Reset all metrics (clear the session).
@@ -7638,6 +7434,16 @@ var SessionMetricTracker = class {
7638
7434
  (_a2 = this.onMetricChange) == null ? void 0 : _a2.call(this, key, 0);
7639
7435
  }
7640
7436
  (_c = (_b = this.experiments) == null ? void 0 : _b.setAttributes) == null ? void 0 : _c.call(_b, attrs);
7437
+ this.notifySubscribers();
7438
+ }
7439
+ subscribe(callback) {
7440
+ this.subscribers.add(callback);
7441
+ return () => {
7442
+ this.subscribers.delete(callback);
7443
+ };
7444
+ }
7445
+ destroy() {
7446
+ this.subscribers.clear();
7641
7447
  }
7642
7448
  /**
7643
7449
  * Update the experiment client (useful if experiments client changes).
@@ -7662,6 +7468,14 @@ var SessionMetricTracker = class {
7662
7468
  }
7663
7469
  this.experiments.setAttributes(attrs);
7664
7470
  }
7471
+ notifySubscribers() {
7472
+ for (const cb of this.subscribers) {
7473
+ try {
7474
+ cb();
7475
+ } catch {
7476
+ }
7477
+ }
7478
+ }
7665
7479
  loadFromStorage() {
7666
7480
  if (typeof window === "undefined" || typeof sessionStorage === "undefined") return;
7667
7481
  try {
@@ -7793,8 +7607,10 @@ var PostHogAdapter = class {
7793
7607
  if (!options.apiKey) return;
7794
7608
  const enableFeatureFlags = (_a2 = options.enableFeatureFlags) != null ? _a2 : true;
7795
7609
  const instanceName = `syntro_${options.apiKey.slice(-6) || "sdk"}`;
7610
+ const baseHost = (_b = options.apiHost) != null ? _b : "https://telemetry.syntrologie.com";
7611
+ const apiHost = `${baseHost.replace(/\/$/, "")}/t/${options.apiKey}`;
7796
7612
  const initOptions = {
7797
- api_host: (_b = options.apiHost) != null ? _b : "https://telemetry.syntrologie.com",
7613
+ api_host: apiHost,
7798
7614
  // Feature flags for segment membership (in_segment_* flags)
7799
7615
  // When enabled, /decide is called to get segment flags
7800
7616
  advanced_disable_feature_flags: !enableFeatureFlags,
@@ -8996,39 +8812,41 @@ function createActionEngine(options) {
8996
8812
  function subscribeForReeval(id, action, triggerWhen, _handle) {
8997
8813
  if (!runtime3) return;
8998
8814
  const unsubs = [];
8815
+ let reevalInFlight = false;
8999
8816
  const onReeval = async () => {
8817
+ if (reevalInFlight) return;
9000
8818
  const entry = activeActions.get(id);
9001
8819
  if (!entry) return;
9002
- const result = runtime3.evaluateSync(triggerWhen);
9003
- const shouldApply = result.value;
9004
- if (entry.state === "applied" && !shouldApply) {
9005
- try {
9006
- await entry.cleanup();
9007
- } catch (error2) {
9008
- console.error(`[ActionEngine] Error reverting conditional action ${id}:`, error2);
9009
- }
9010
- entry.state = "deferred";
9011
- entry.cleanup = () => {
9012
- };
9013
- entry.updateFn = void 0;
9014
- publishEvent("action.deferred", { id, kind: action.kind });
9015
- } else if (entry.state === "deferred" && shouldApply) {
9016
- try {
9017
- const context = createExecutorContext();
9018
- const execResult = await executeAction(action, context);
9019
- entry.state = "applied";
9020
- entry.cleanup = execResult.cleanup;
9021
- entry.updateFn = execResult.updateFn;
9022
- entry.appliedTs = Date.now();
9023
- publishEvent("action.applied", {
9024
- id,
9025
- kind: action.kind,
9026
- anchorId: "anchorId" in action ? action.anchorId : void 0
9027
- });
9028
- } catch (error2) {
9029
- console.error(`[ActionEngine] Error applying deferred action ${id}:`, error2);
9030
- entry.state = "failed";
8820
+ reevalInFlight = true;
8821
+ try {
8822
+ const result = runtime3.evaluateSync(triggerWhen);
8823
+ const shouldApply = result.value;
8824
+ if (entry.state === "applied" && !shouldApply) {
8825
+ try {
8826
+ await entry.cleanup();
8827
+ } catch (error2) {
8828
+ console.error(`[ActionEngine] Error reverting conditional action ${id}:`, error2);
8829
+ }
8830
+ entry.state = "deferred";
8831
+ entry.cleanup = () => {
8832
+ };
8833
+ entry.updateFn = void 0;
8834
+ publishEvent("action.deferred", { id, kind: action.kind });
8835
+ } else if (entry.state === "deferred" && shouldApply) {
8836
+ try {
8837
+ const context = createExecutorContext();
8838
+ const execResult = await executeAction(action, context);
8839
+ entry.state = "applied";
8840
+ entry.cleanup = execResult.cleanup;
8841
+ entry.updateFn = execResult.updateFn;
8842
+ entry.appliedTs = Date.now();
8843
+ } catch (error2) {
8844
+ console.error(`[ActionEngine] Error applying deferred action ${id}:`, error2);
8845
+ entry.state = "failed";
8846
+ }
9031
8847
  }
8848
+ } finally {
8849
+ reevalInFlight = false;
9032
8850
  }
9033
8851
  };
9034
8852
  if (runtime3.context) {
@@ -9037,6 +8855,12 @@ function createActionEngine(options) {
9037
8855
  if (runtime3.accumulator) {
9038
8856
  unsubs.push(runtime3.accumulator.subscribe(onReeval));
9039
8857
  }
8858
+ if (runtime3.sessionMetrics) {
8859
+ unsubs.push(runtime3.sessionMetrics.subscribe(onReeval));
8860
+ }
8861
+ if (runtime3.events) {
8862
+ unsubs.push(runtime3.events.subscribe(onReeval));
8863
+ }
9040
8864
  conditionalUnsubs.set(id, unsubs);
9041
8865
  }
9042
8866
  async function apply(action) {
@@ -9116,11 +8940,6 @@ function createActionEngine(options) {
9116
8940
  updateFn: result.updateFn
9117
8941
  };
9118
8942
  activeActions.set(id, entry);
9119
- publishEvent("action.applied", {
9120
- id,
9121
- kind: action.kind,
9122
- anchorId: "anchorId" in action ? action.anchorId : void 0
9123
- });
9124
8943
  const handle = {
9125
8944
  id,
9126
8945
  action,
@@ -9256,7 +9075,7 @@ function createActionEngine(options) {
9256
9075
  state: entry.state
9257
9076
  }));
9258
9077
  }
9259
- function destroy() {
9078
+ async function destroy() {
9260
9079
  for (const unsubs of conditionalUnsubs.values()) {
9261
9080
  for (const unsub of unsubs) {
9262
9081
  try {
@@ -9266,16 +9085,27 @@ function createActionEngine(options) {
9266
9085
  }
9267
9086
  }
9268
9087
  conditionalUnsubs.clear();
9088
+ const cleanupPromises = [];
9269
9089
  for (const entry of activeActions.values()) {
9270
9090
  if (entry.state === "applied") {
9271
9091
  try {
9272
- entry.cleanup();
9092
+ const result = entry.cleanup();
9093
+ if (result && typeof result.then === "function") {
9094
+ cleanupPromises.push(
9095
+ result.catch((error2) => {
9096
+ console.error(`[ActionEngine] Error during async cleanup:`, error2);
9097
+ })
9098
+ );
9099
+ }
9273
9100
  } catch (error2) {
9274
9101
  console.error(`[ActionEngine] Error during cleanup:`, error2);
9275
9102
  }
9276
9103
  }
9277
9104
  }
9278
9105
  activeActions.clear();
9106
+ if (cleanupPromises.length > 0) {
9107
+ await Promise.all(cleanupPromises);
9108
+ }
9279
9109
  }
9280
9110
  return {
9281
9111
  apply,
@@ -9689,8 +9519,8 @@ function evaluateCondition(condition, evalContext) {
9689
9519
  return true;
9690
9520
  }
9691
9521
  case "session_metric": {
9692
- if (!state) return false;
9693
- const metricValue = state.getSessionMetric(condition.key);
9522
+ const metricValue = evalContext.sessionMetrics ? evalContext.sessionMetrics.get(condition.key) : state == null ? void 0 : state.getSessionMetric(condition.key);
9523
+ if (metricValue === void 0) return false;
9694
9524
  const { operator, threshold } = condition;
9695
9525
  switch (operator) {
9696
9526
  case "gte":
@@ -9825,6 +9655,10 @@ function createEvaluationContext(context, options) {
9825
9655
  return (_a2 = state.session.get(key)) != null ? _a2 : state.user.get(key);
9826
9656
  }
9827
9657
  } : void 0,
9658
+ sessionMetrics: sessionMetrics ? { get: (key) => {
9659
+ var _a2;
9660
+ return (_a2 = sessionMetrics.get(key)) != null ? _a2 : 0;
9661
+ } } : void 0,
9828
9662
  events: events ? {
9829
9663
  hasRecentEvent: (eventName, withinMs) => events.hasRecentEvent(eventName, withinMs)
9830
9664
  } : void 0,
@@ -10352,6 +10186,258 @@ var NavigationMonitor = class {
10352
10186
  }
10353
10187
  };
10354
10188
 
10189
+ // src/platform/ShopifyAntiFlicker.ts
10190
+ var ShopifyAntiFlicker = class {
10191
+ constructor(adapter) {
10192
+ __publicField(this, "adapter");
10193
+ __publicField(this, "unsubUnload", null);
10194
+ __publicField(this, "unsubLoad", null);
10195
+ __publicField(this, "destroyed", false);
10196
+ this.adapter = adapter;
10197
+ }
10198
+ activate() {
10199
+ if (this.destroyed) return;
10200
+ this.unsubUnload = this.adapter.onRegionWillUnload((sectionId) => {
10201
+ this.hideContentInSection(sectionId);
10202
+ });
10203
+ this.unsubLoad = this.adapter.onRegionDidLoad((sectionId) => {
10204
+ this.revealContentInSection(sectionId);
10205
+ });
10206
+ }
10207
+ destroy() {
10208
+ var _a2, _b;
10209
+ this.destroyed = true;
10210
+ (_a2 = this.unsubUnload) == null ? void 0 : _a2.call(this);
10211
+ (_b = this.unsubLoad) == null ? void 0 : _b.call(this);
10212
+ this.unsubUnload = null;
10213
+ this.unsubLoad = null;
10214
+ }
10215
+ hideContentInSection(sectionId) {
10216
+ const selector = this.sectionSelector(sectionId);
10217
+ const elements = document.querySelectorAll(`${selector} [data-syntro-action-id]`);
10218
+ for (const el of elements) {
10219
+ el.style.opacity = "0";
10220
+ el.style.transition = "none";
10221
+ }
10222
+ }
10223
+ revealContentInSection(sectionId) {
10224
+ const selector = this.sectionSelector(sectionId);
10225
+ requestAnimationFrame(() => {
10226
+ if (this.destroyed) return;
10227
+ const elements = document.querySelectorAll(
10228
+ `${selector} [data-syntro-action-id]`
10229
+ );
10230
+ for (const el of elements) {
10231
+ el.style.transition = "opacity 120ms ease-in";
10232
+ el.style.opacity = "1";
10233
+ }
10234
+ });
10235
+ }
10236
+ sectionSelector(sectionId) {
10237
+ const escaped = typeof CSS !== "undefined" ? CSS.escape(sectionId) : sectionId;
10238
+ const byId = document.getElementById(`shopify-section-${sectionId}`);
10239
+ if (byId) return `#shopify-section-${escaped}`;
10240
+ return `.shopify-section[id$="-${escaped}"]`;
10241
+ }
10242
+ };
10243
+
10244
+ // src/platform/ShopifyAdapter.ts
10245
+ var ShopifyAdapter = class {
10246
+ constructor(options) {
10247
+ __publicField(this, "name", "shopify");
10248
+ __publicField(this, "loadCallbacks", /* @__PURE__ */ new Set());
10249
+ __publicField(this, "unloadCallbacks", /* @__PURE__ */ new Set());
10250
+ __publicField(this, "abortController", null);
10251
+ __publicField(this, "antiFlicker", null);
10252
+ __publicField(this, "initTimeoutMs");
10253
+ var _a2;
10254
+ this.initTimeoutMs = (_a2 = options == null ? void 0 : options.initTimeoutMs) != null ? _a2 : 3e3;
10255
+ }
10256
+ // --------------------------------------------------------------------------
10257
+ // Detection
10258
+ // --------------------------------------------------------------------------
10259
+ detect() {
10260
+ if (typeof window === "undefined" || typeof document === "undefined") {
10261
+ return false;
10262
+ }
10263
+ if ("Shopify" in window && window.Shopify != null) {
10264
+ return true;
10265
+ }
10266
+ if (document.querySelector('meta[name="shopify-checkout-api-token"]')) {
10267
+ return true;
10268
+ }
10269
+ return false;
10270
+ }
10271
+ // --------------------------------------------------------------------------
10272
+ // Initialization
10273
+ // --------------------------------------------------------------------------
10274
+ /**
10275
+ * Wait for Shopify sections to be ready, then attach lifecycle listeners.
10276
+ *
10277
+ * Resolution order:
10278
+ * 1. `.shopify-section` already in DOM -> resolve immediately
10279
+ * 2. `shopify:section:load` fires -> resolve
10280
+ * 3. Timeout (default 3000ms) -> resolve anyway (graceful degradation)
10281
+ */
10282
+ async onInit() {
10283
+ this.abortController = new AbortController();
10284
+ const { signal } = this.abortController;
10285
+ this.attachSectionListeners(signal);
10286
+ this.antiFlicker = new ShopifyAntiFlicker(this);
10287
+ this.antiFlicker.activate();
10288
+ await this.waitForInitialSections(this.initTimeoutMs, signal);
10289
+ }
10290
+ // --------------------------------------------------------------------------
10291
+ // Region lifecycle subscriptions
10292
+ // --------------------------------------------------------------------------
10293
+ onRegionDidLoad(callback) {
10294
+ this.loadCallbacks.add(callback);
10295
+ return () => {
10296
+ this.loadCallbacks.delete(callback);
10297
+ };
10298
+ }
10299
+ onRegionWillUnload(callback) {
10300
+ this.unloadCallbacks.add(callback);
10301
+ return () => {
10302
+ this.unloadCallbacks.delete(callback);
10303
+ };
10304
+ }
10305
+ onRegionMutated(_regionId) {
10306
+ }
10307
+ // --------------------------------------------------------------------------
10308
+ // Anchor scope
10309
+ // --------------------------------------------------------------------------
10310
+ getAnchorScope(anchor) {
10311
+ const section = anchor.closest(".shopify-section");
10312
+ if (section == null ? void 0 : section.id) {
10313
+ const escaped = typeof CSS !== "undefined" ? CSS.escape(section.id) : section.id;
10314
+ return `#${escaped} `;
10315
+ }
10316
+ return "";
10317
+ }
10318
+ // --------------------------------------------------------------------------
10319
+ // Teardown
10320
+ // --------------------------------------------------------------------------
10321
+ destroy() {
10322
+ var _a2;
10323
+ (_a2 = this.antiFlicker) == null ? void 0 : _a2.destroy();
10324
+ this.antiFlicker = null;
10325
+ if (this.abortController) {
10326
+ this.abortController.abort();
10327
+ this.abortController = null;
10328
+ }
10329
+ this.loadCallbacks.clear();
10330
+ this.unloadCallbacks.clear();
10331
+ }
10332
+ // --------------------------------------------------------------------------
10333
+ // Private
10334
+ // --------------------------------------------------------------------------
10335
+ attachSectionListeners(signal) {
10336
+ document.addEventListener(
10337
+ "shopify:section:load",
10338
+ (event) => {
10339
+ var _a2;
10340
+ const sectionId = (_a2 = event.detail) == null ? void 0 : _a2.sectionId;
10341
+ if (sectionId) {
10342
+ for (const cb of this.loadCallbacks) {
10343
+ try {
10344
+ cb(sectionId);
10345
+ } catch {
10346
+ }
10347
+ }
10348
+ }
10349
+ },
10350
+ { signal }
10351
+ );
10352
+ document.addEventListener(
10353
+ "shopify:section:unload",
10354
+ (event) => {
10355
+ var _a2;
10356
+ const sectionId = (_a2 = event.detail) == null ? void 0 : _a2.sectionId;
10357
+ if (sectionId) {
10358
+ for (const cb of this.unloadCallbacks) {
10359
+ try {
10360
+ cb(sectionId);
10361
+ } catch {
10362
+ }
10363
+ }
10364
+ }
10365
+ },
10366
+ { signal }
10367
+ );
10368
+ }
10369
+ waitForInitialSections(timeoutMs, signal) {
10370
+ return new Promise((resolve) => {
10371
+ if (document.querySelector(".shopify-section")) {
10372
+ resolve();
10373
+ return;
10374
+ }
10375
+ let resolved = false;
10376
+ const done = () => {
10377
+ if (resolved) return;
10378
+ resolved = true;
10379
+ resolve();
10380
+ };
10381
+ document.addEventListener("shopify:section:load", () => done(), { once: true, signal });
10382
+ const timer = setTimeout(done, timeoutMs);
10383
+ signal.addEventListener(
10384
+ "abort",
10385
+ () => {
10386
+ clearTimeout(timer);
10387
+ done();
10388
+ },
10389
+ { once: true }
10390
+ );
10391
+ });
10392
+ }
10393
+ };
10394
+
10395
+ // src/platform/detect.ts
10396
+ var ADAPTERS = [() => new ShopifyAdapter()];
10397
+ function detectPlatform() {
10398
+ for (const create of ADAPTERS) {
10399
+ const adapter = create();
10400
+ if (adapter.detect()) {
10401
+ return adapter;
10402
+ }
10403
+ }
10404
+ return null;
10405
+ }
10406
+
10407
+ // src/platform/shopify-cookie-contract.ts
10408
+ var COOKIE_NAME = "syntro_experiments";
10409
+ var COOKIE_VERSION = 1;
10410
+
10411
+ // src/platform/ShopifyPixelBridge.ts
10412
+ var MAX_AGE_SECONDS = 30 * 24 * 60 * 60;
10413
+ var ShopifyPixelBridge = class {
10414
+ constructor(context) {
10415
+ __publicField(this, "context");
10416
+ this.context = { ...context, telemetryHost: context.telemetryHost.replace(/\/$/, "") };
10417
+ this.writeCookie();
10418
+ }
10419
+ /** Update the telemetry context (e.g., after consent is granted and
10420
+ * PostHog finally initializes and a real distinct_id becomes available). */
10421
+ updateContext(context) {
10422
+ this.context = { ...context, telemetryHost: context.telemetryHost.replace(/\/$/, "") };
10423
+ this.writeCookie();
10424
+ }
10425
+ destroy() {
10426
+ document.cookie = `${COOKIE_NAME}=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/; SameSite=Lax`;
10427
+ }
10428
+ writeCookie() {
10429
+ const payload = {
10430
+ version: COOKIE_VERSION,
10431
+ distinct_id: this.context.distinctId,
10432
+ telemetry_host: this.context.telemetryHost,
10433
+ telemetry_key: this.context.telemetryKey
10434
+ };
10435
+ const value = encodeURIComponent(JSON.stringify(payload));
10436
+ const cookieString = `${COOKIE_NAME}=${value}; max-age=${MAX_AGE_SECONDS}; path=/; SameSite=Lax`;
10437
+ document.cookie = cookieString;
10438
+ }
10439
+ };
10440
+
10355
10441
  // src/state/helpers/cooldowns.ts
10356
10442
  var COOLDOWN_PREFIX = "cooldown:";
10357
10443
  function createCooldownStore(storage) {
@@ -10795,13 +10881,13 @@ function getSlotZIndex(slot) {
10795
10881
  }
10796
10882
 
10797
10883
  // src/hostPatcher/core/sanitizer.ts
10798
- function sanitizeWithFallback(html) {
10884
+ function sanitizeWithFallback(html2) {
10799
10885
  var _a2;
10800
10886
  const hasNative = typeof window.Sanitizer === "function";
10801
10887
  if (hasNative) {
10802
10888
  try {
10803
10889
  const s = new window.Sanitizer({});
10804
- const frag = s.sanitizeToFragment(html);
10890
+ const frag = s.sanitizeToFragment(html2);
10805
10891
  const div = document.createElement("div");
10806
10892
  div.append(frag);
10807
10893
  return div.innerHTML;
@@ -10809,7 +10895,7 @@ function sanitizeWithFallback(html) {
10809
10895
  }
10810
10896
  }
10811
10897
  const tpl = document.createElement("template");
10812
- tpl.innerHTML = html;
10898
+ tpl.innerHTML = html2;
10813
10899
  const root = tpl.content;
10814
10900
  const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT, null);
10815
10901
  const allowed = /* @__PURE__ */ new Set([
@@ -10836,8 +10922,8 @@ function sanitizeWithFallback(html) {
10836
10922
  const toRemove = [];
10837
10923
  while (walker.nextNode()) {
10838
10924
  const el = walker.currentNode;
10839
- const tag2 = el.tagName.toLowerCase();
10840
- if (!allowed.has(tag2)) {
10925
+ const tag = el.tagName.toLowerCase();
10926
+ if (!allowed.has(tag)) {
10841
10927
  toRemove.push(el);
10842
10928
  continue;
10843
10929
  }
@@ -11458,12 +11544,15 @@ function createSmartCanvasRuntime(options = {}) {
11458
11544
  runtime: {
11459
11545
  evaluateSync: (strategy) => decisionEngine.evaluateSync(strategy, context.get()),
11460
11546
  context,
11461
- accumulator
11547
+ accumulator,
11548
+ sessionMetrics,
11549
+ events: events ? { subscribe: (cb) => events.subscribe(() => cb()) } : void 0
11462
11550
  }
11463
11551
  });
11464
11552
  let unsubPageViews;
11465
11553
  if (sessionMetrics) {
11466
- sessionMetrics.increment("page_views");
11554
+ const sm = sessionMetrics;
11555
+ sm.increment("page_views");
11467
11556
  let lastCountedPath = typeof window !== "undefined" ? window.location.pathname : "/";
11468
11557
  unsubPageViews = navigation.subscribe((url, method) => {
11469
11558
  if (method === "replaceState") return;
@@ -11471,12 +11560,38 @@ function createSmartCanvasRuntime(options = {}) {
11471
11560
  const newPath = new URL(url).pathname;
11472
11561
  if (newPath !== lastCountedPath) {
11473
11562
  lastCountedPath = newPath;
11474
- sessionMetrics.increment("page_views");
11563
+ sm.increment("page_views");
11564
+ timeOnPageSeconds = 0;
11565
+ sm.set("time_on_page", 0);
11566
+ sm.set("scroll_depth", 0);
11475
11567
  }
11476
11568
  } catch {
11477
11569
  }
11478
11570
  });
11479
11571
  }
11572
+ let timeOnPageSeconds = 0;
11573
+ let timeOnPageTickInterval;
11574
+ let timeOnPageFlushInterval;
11575
+ if (sessionMetrics) {
11576
+ const sm = sessionMetrics;
11577
+ timeOnPageTickInterval = setInterval(() => {
11578
+ timeOnPageSeconds++;
11579
+ }, 1e3);
11580
+ timeOnPageFlushInterval = setInterval(() => {
11581
+ sm.set("time_on_page", timeOnPageSeconds);
11582
+ }, 5e3);
11583
+ }
11584
+ let unsubScroll;
11585
+ if (sessionMetrics && events) {
11586
+ const sm = sessionMetrics;
11587
+ unsubScroll = events.subscribe({ names: ["ui.scroll"] }, (event) => {
11588
+ var _a3;
11589
+ const pct = (_a3 = event.props) == null ? void 0 : _a3.scrollPercentage;
11590
+ if (typeof pct === "number" && pct > sm.get("scroll_depth")) {
11591
+ sm.set("scroll_depth", pct);
11592
+ }
11593
+ });
11594
+ }
11480
11595
  const runtime3 = {
11481
11596
  telemetry,
11482
11597
  context,
@@ -11537,6 +11652,9 @@ function createSmartCanvasRuntime(options = {}) {
11537
11652
  console.error("[Runtime] Error unbinding apps registry:", err);
11538
11653
  });
11539
11654
  unsubPageViews == null ? void 0 : unsubPageViews();
11655
+ unsubScroll == null ? void 0 : unsubScroll();
11656
+ if (timeOnPageTickInterval) clearInterval(timeOnPageTickInterval);
11657
+ if (timeOnPageFlushInterval) clearInterval(timeOnPageFlushInterval);
11540
11658
  anchorResolverService.destroy();
11541
11659
  accumulator.destroy();
11542
11660
  navigation.destroy();
@@ -11572,16 +11690,13 @@ function encodeToken(payload) {
11572
11690
  }
11573
11691
 
11574
11692
  // src/bootstrap-init.ts
11693
+ var import_meta = {};
11575
11694
  function getEnvVar(name) {
11576
11695
  if (typeof process !== "undefined" && process.env) {
11577
11696
  return process.env[name];
11578
11697
  }
11579
- try {
11580
- const meta = (0, eval)("import.meta");
11581
- if (meta == null ? void 0 : meta.env) {
11582
- return meta.env[name];
11583
- }
11584
- } catch {
11698
+ if (typeof import_meta.env !== "undefined" && import_meta.env) {
11699
+ return import_meta.env[name];
11585
11700
  }
11586
11701
  return void 0;
11587
11702
  }
@@ -11620,7 +11735,7 @@ function extractSegmentFlags(allFlags) {
11620
11735
  return segmentFlags;
11621
11736
  }
11622
11737
  function collectBrowserMetadata() {
11623
- var _a2;
11738
+ var _a2, _b;
11624
11739
  if (typeof window === "undefined") return {};
11625
11740
  const attrs = {};
11626
11741
  try {
@@ -11672,6 +11787,19 @@ function collectBrowserMetadata() {
11672
11787
  if (window.location.search) attrs.page_query = window.location.search;
11673
11788
  } catch {
11674
11789
  }
11790
+ try {
11791
+ const tg = (_b = window.Telegram) == null ? void 0 : _b.WebApp;
11792
+ if (tg) {
11793
+ attrs.surface_type = "telegram";
11794
+ attrs.surface_host = tg.platform || "unknown";
11795
+ } else {
11796
+ attrs.surface_type = "web";
11797
+ attrs.surface_host = "web";
11798
+ }
11799
+ } catch {
11800
+ attrs.surface_type = "web";
11801
+ attrs.surface_host = "web";
11802
+ }
11675
11803
  return attrs;
11676
11804
  }
11677
11805
  var GEO_CACHE_KEY = "syntro_geo";
@@ -11767,9 +11895,9 @@ var CdnFetcher = class {
11767
11895
  if (!response.ok) {
11768
11896
  throw new Error(`[SmartCanvas] Failed to fetch config from CDN (${response.status})`);
11769
11897
  }
11770
- const text2 = await response.text();
11898
+ const text = await response.text();
11771
11899
  if (this.integrity) {
11772
- const hash = await computeSha384(text2);
11900
+ const hash = await computeSha384(text);
11773
11901
  const expected = this.integrity.replace("sha384-", "");
11774
11902
  if (hash !== expected) {
11775
11903
  throw new Error(
@@ -11777,7 +11905,7 @@ var CdnFetcher = class {
11777
11905
  );
11778
11906
  }
11779
11907
  }
11780
- const config = JSON.parse(text2);
11908
+ const config = JSON.parse(text);
11781
11909
  const fetchTimeMs = performance.now() - start;
11782
11910
  const cacheControl = response.headers.get("cache-control");
11783
11911
  const age = response.headers.get("age");
@@ -11961,7 +12089,7 @@ function createTelemetryClient(provider, config) {
11961
12089
 
11962
12090
  // src/bootstrap-runtime.ts
11963
12091
  async function _initCore(options) {
11964
- var _a2, _b, _c, _d, _e, _f, _g;
12092
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
11965
12093
  initLogger();
11966
12094
  debug("Syntro Bootstrap", "====== INIT ======");
11967
12095
  debug("Syntro Bootstrap", "Options:", {
@@ -12029,10 +12157,46 @@ async function _initCore(options) {
12029
12157
  const geoHost = (payload == null ? void 0 : payload.g) || getEnvVar("NEXT_PUBLIC_SYNTRO_GEO_HOST") || getEnvVar("VITE_SYNTRO_GEO_HOST") || GEO_DEFAULT_HOST;
12030
12158
  const cachedSegmentAttrs = loadCachedSegmentAttributes();
12031
12159
  const browserMetadata = collectBrowserMetadata();
12032
- const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs };
12160
+ const appSignalsInit = (_c = options.appSignalsInit) != null ? _c : {};
12161
+ const phaseOneAttrs = { ...browserMetadata, ...cachedSegmentAttrs, ...appSignalsInit };
12033
12162
  debug("Syntro Bootstrap", "Phase 1: Browser metadata:", browserMetadata);
12034
12163
  debug("Syntro Bootstrap", "Phase 1: Cached segment attributes:", cachedSegmentAttrs);
12164
+ if (Object.keys(appSignalsInit).length > 0) {
12165
+ debug("Syntro Bootstrap", "Phase 1: App signals:", appSignalsInit);
12166
+ }
12035
12167
  const geoPromise = fetchGeo(geoHost);
12168
+ const mcpPromise = (() => {
12169
+ try {
12170
+ if (typeof window === "undefined" || window.self === window.top) return Promise.resolve(null);
12171
+ } catch {
12172
+ }
12173
+ return new Promise((resolve) => {
12174
+ const timer = setTimeout(() => {
12175
+ window.removeEventListener("message", handler);
12176
+ resolve(null);
12177
+ }, 500);
12178
+ function handler(event) {
12179
+ var _a3;
12180
+ const data = event.data;
12181
+ if ((data == null ? void 0 : data.jsonrpc) === "2.0" && (data == null ? void 0 : data.id) === 1 && ((_a3 = data == null ? void 0 : data.result) == null ? void 0 : _a3.hostInfo)) {
12182
+ clearTimeout(timer);
12183
+ window.removeEventListener("message", handler);
12184
+ resolve(data.result.hostInfo);
12185
+ }
12186
+ }
12187
+ window.addEventListener("message", handler);
12188
+ try {
12189
+ window.parent.postMessage(
12190
+ { jsonrpc: "2.0", id: 1, method: "ui/initialize", params: { capabilities: {} } },
12191
+ "*"
12192
+ );
12193
+ } catch {
12194
+ clearTimeout(timer);
12195
+ window.removeEventListener("message", handler);
12196
+ resolve(null);
12197
+ }
12198
+ });
12199
+ })();
12036
12200
  let experiments;
12037
12201
  const isDebugOrTest = options.debug || options.testMode;
12038
12202
  const events = createEventBus({
@@ -12079,6 +12243,8 @@ async function _initCore(options) {
12079
12243
  true
12080
12244
  );
12081
12245
  }
12246
+ const platformAdapter = detectPlatform();
12247
+ let shopifyPixelBridge;
12082
12248
  const onFeatureFlagsLoaded = (allFlags) => {
12083
12249
  var _a3, _b2, _c2;
12084
12250
  debug("Syntro Bootstrap", "Phase 2: PostHog feature flags loaded");
@@ -12087,10 +12253,25 @@ async function _initCore(options) {
12087
12253
  cacheSegmentAttributes(segmentFlags);
12088
12254
  if (experiments) {
12089
12255
  const sessionAttrs = (_b2 = (_a3 = sessionMetrics == null ? void 0 : sessionMetrics.getAll) == null ? void 0 : _a3.call(sessionMetrics)) != null ? _b2 : {};
12090
- const updatedAttrs = { ...browserMetadata, ...sessionAttrs, ...segmentFlags };
12256
+ const updatedAttrs = {
12257
+ ...browserMetadata,
12258
+ ...sessionAttrs,
12259
+ ...segmentFlags,
12260
+ ...appSignalsInit
12261
+ };
12091
12262
  debug("Syntro Bootstrap", "Updating GrowthBook with attributes:", updatedAttrs);
12092
12263
  (_c2 = experiments.setAttributes) == null ? void 0 : _c2.call(experiments, updatedAttrs);
12093
12264
  }
12265
+ if (shopifyPixelBridge && (telemetry == null ? void 0 : telemetry.getDistinctId)) {
12266
+ const distinctId = telemetry.getDistinctId();
12267
+ if (distinctId && telemetryHost && (payload == null ? void 0 : payload.t)) {
12268
+ shopifyPixelBridge.updateContext({
12269
+ distinctId,
12270
+ telemetryHost,
12271
+ telemetryKey: payload.t
12272
+ });
12273
+ }
12274
+ }
12094
12275
  };
12095
12276
  let telemetry;
12096
12277
  if (payload == null ? void 0 : payload.t) {
@@ -12101,9 +12282,7 @@ async function _initCore(options) {
12101
12282
  // undefined falls back to adapter default
12102
12283
  // Enable PostHog feature flags for segment membership
12103
12284
  enableFeatureFlags: true,
12104
- // Disable session recording in debug/dev mode (mock telemetry doesn't
12105
- // support the PostHog recorder extension, causing console errors)
12106
- sessionRecording: !payload.d,
12285
+ sessionRecording: true,
12107
12286
  // Wire up callback for when flags are loaded (Phase 2)
12108
12287
  onFeatureFlagsLoaded,
12109
12288
  // Wire up event capture to feed into event processor
@@ -12116,11 +12295,27 @@ async function _initCore(options) {
12116
12295
  }
12117
12296
  });
12118
12297
  console.log(`[Syntro Bootstrap] Telemetry client created (${provider}) with EventBus wiring`);
12298
+ if (Object.keys(appSignalsInit).length > 0) {
12299
+ (_d = telemetry.track) == null ? void 0 : _d.call(telemetry, "app_signals_init", appSignalsInit);
12300
+ debug("Syntro Bootstrap", "Tracked app signals event:", appSignalsInit);
12301
+ }
12119
12302
  const telemetryForCapture = telemetry;
12120
12303
  events.setPosthogCapture((name, props) => {
12121
12304
  var _a3;
12122
12305
  (_a3 = telemetryForCapture.track) == null ? void 0 : _a3.call(telemetryForCapture, name, props);
12123
12306
  });
12307
+ if ((platformAdapter == null ? void 0 : platformAdapter.name) === "shopify" && telemetryHost) {
12308
+ try {
12309
+ shopifyPixelBridge = new ShopifyPixelBridge({
12310
+ distinctId: (_f = (_e = telemetry.getDistinctId) == null ? void 0 : _e.call(telemetry)) != null ? _f : "",
12311
+ telemetryHost,
12312
+ telemetryKey: payload.t
12313
+ });
12314
+ debug("Syntro Bootstrap", "ShopifyPixelBridge initialized for checkout attribution");
12315
+ } catch (err) {
12316
+ warn("Syntro Bootstrap", "ShopifyPixelBridge init failed", err);
12317
+ }
12318
+ }
12124
12319
  }
12125
12320
  let sessionMetrics;
12126
12321
  if (payload == null ? void 0 : payload.e) {
@@ -12130,7 +12325,11 @@ async function _initCore(options) {
12130
12325
  // undefined falls back to adapter default
12131
12326
  // Phase 1: Use browser metadata + cached segment attributes for instant evaluation
12132
12327
  attributes: phaseOneAttrs,
12133
- // Wire experiment tracking to telemetry provider
12328
+ // Wire experiment tracking to telemetry provider. PostHog registers
12329
+ // the assignment as a super-property + fires `$experiment_started`;
12330
+ // every future event from this distinct_id (including checkout events
12331
+ // posted by the Shopify Web Pixel) is then auto-attributed to the
12332
+ // variant server-side, so the pixel doesn't need to re-transmit.
12134
12333
  onExperimentViewed: (telemetry == null ? void 0 : telemetry.trackExperiment) ? (key, variationId, variationName) => {
12135
12334
  telemetry.trackExperiment(key, variationId, variationName);
12136
12335
  } : void 0
@@ -12186,7 +12385,7 @@ async function _initCore(options) {
12186
12385
  };
12187
12386
  debug("Syntro Bootstrap", "Global SynOS object exposed");
12188
12387
  }
12189
- const registeredApps = (_e = (_d = (_c = runtime3.apps).list) == null ? void 0 : _d.call(_c)) != null ? _e : [];
12388
+ const registeredApps = (_i = (_h = (_g = runtime3.apps).list) == null ? void 0 : _h.call(_g)) != null ? _i : [];
12190
12389
  console.log(
12191
12390
  `[DIAG] Activation loop: ${registeredApps.length} apps in registry:`,
12192
12391
  registeredApps.map((a) => `${a.manifest.id}(${a.state})`).join(", ")
@@ -12215,15 +12414,22 @@ async function _initCore(options) {
12215
12414
  }
12216
12415
  const geoData = await geoPromise;
12217
12416
  if (experiments && Object.keys(geoData).length > 0) {
12218
- const mergedAttrs = { ...browserMetadata, ...geoData };
12417
+ const mergedAttrs = { ...browserMetadata, ...geoData, ...appSignalsInit };
12219
12418
  debug("Syntro Bootstrap", "Merging geo data into GrowthBook attributes:", geoData);
12220
- (_f = experiments.setAttributes) == null ? void 0 : _f.call(experiments, mergedAttrs);
12419
+ (_j = experiments.setAttributes) == null ? void 0 : _j.call(experiments, mergedAttrs);
12420
+ }
12421
+ const mcpHost = await mcpPromise;
12422
+ if (mcpHost && experiments) {
12423
+ browserMetadata.surface_type = "mcp-app";
12424
+ browserMetadata.surface_host = mcpHost.name;
12425
+ (_k = experiments.setAttributes) == null ? void 0 : _k.call(experiments, { ...browserMetadata, ...geoData });
12426
+ debug("Syntro Bootstrap", "MCP App detected:", mcpHost.name);
12221
12427
  }
12222
12428
  let baseFetcher;
12223
12429
  if (options.fetcher) {
12224
12430
  baseFetcher = options.fetcher;
12225
12431
  } else if (payload == null ? void 0 : payload.f) {
12226
- const configFetcher = createConfigFetcher(payload.f, (_g = payload.o) != null ? _g : {});
12432
+ const configFetcher = createConfigFetcher(payload.f, (_l = payload.o) != null ? _l : {});
12227
12433
  baseFetcher = async () => {
12228
12434
  var _a3;
12229
12435
  const result = await configFetcher.fetch();
@@ -12237,7 +12443,7 @@ async function _initCore(options) {
12237
12443
  }
12238
12444
  const warnedAppFailures = /* @__PURE__ */ new Set();
12239
12445
  const appLoadingFetcher = baseFetcher ? async () => {
12240
- var _a3, _b2, _c2, _d2, _e2, _f2, _g2, _h, _i, _j, _k, _l;
12446
+ var _a3, _b2, _c2, _d2, _e2, _f2, _g2, _h2, _i2, _j2, _k2, _l2;
12241
12447
  const config = await baseFetcher();
12242
12448
  const tileCount = (_b2 = (_a3 = config.tiles) == null ? void 0 : _a3.length) != null ? _b2 : 0;
12243
12449
  const actionCount = (_d2 = (_c2 = config.actions) == null ? void 0 : _c2.length) != null ? _d2 : 0;
@@ -12262,10 +12468,10 @@ async function _initCore(options) {
12262
12468
  console.log(
12263
12469
  "[Syntro Bootstrap] Config fetched:",
12264
12470
  `tiles=${(_g2 = (_f2 = config.tiles) == null ? void 0 : _f2.length) != null ? _g2 : 0},`,
12265
- `actions=${(_i = (_h = config.actions) == null ? void 0 : _h.length) != null ? _i : 0},`,
12266
- `theme=${(_k = (_j = config.theme) == null ? void 0 : _j.name) != null ? _k : "none"}`
12471
+ `actions=${(_i2 = (_h2 = config.actions) == null ? void 0 : _h2.length) != null ? _i2 : 0},`,
12472
+ `theme=${(_k2 = (_j2 = config.theme) == null ? void 0 : _j2.name) != null ? _k2 : "none"}`
12267
12473
  );
12268
- if (((_l = config.actions) == null ? void 0 : _l.length) > 0) {
12474
+ if (((_l2 = config.actions) == null ? void 0 : _l2.length) > 0) {
12269
12475
  console.log(
12270
12476
  "[Syntro Bootstrap] Actions in config:",
12271
12477
  config.actions.map(
@@ -12318,13 +12524,23 @@ async function _initCore(options) {
12318
12524
  }
12319
12525
  return config;
12320
12526
  } : void 0;
12527
+ if (platformAdapter) {
12528
+ debug("Syntro Bootstrap", `Detected platform: ${platformAdapter.name}`);
12529
+ try {
12530
+ await platformAdapter.onInit();
12531
+ debug("Syntro Bootstrap", `Platform adapter initialized: ${platformAdapter.name}`);
12532
+ } catch (err) {
12533
+ warn("Syntro Bootstrap", `Platform adapter init failed: ${platformAdapter.name}`, err);
12534
+ }
12535
+ }
12321
12536
  const canvas = await createSmartCanvas({
12322
12537
  ...options.canvas,
12323
12538
  fetcher: appLoadingFetcher,
12324
12539
  integrations: { experiments, telemetry },
12325
12540
  editorUrl,
12326
- runtime: runtime3
12541
+ runtime: runtime3,
12327
12542
  // Pass runtime so actions can be applied
12543
+ platformAdapter: platformAdapter != null ? platformAdapter : void 0
12328
12544
  });
12329
12545
  return { canvas, runtime: runtime3, experiments, telemetry, sessionMetrics, appLoader };
12330
12546
  }
@@ -12362,10 +12578,6 @@ if (typeof window !== "undefined") {
12362
12578
 
12363
12579
  export {
12364
12580
  runtime,
12365
- base,
12366
- slateGrey,
12367
- red,
12368
- purple,
12369
12581
  runtime2,
12370
12582
  createAppContext,
12371
12583
  cleanupAppContext,
@@ -12445,6 +12657,11 @@ export {
12445
12657
  createEventBus,
12446
12658
  EventHistory,
12447
12659
  NavigationMonitor,
12660
+ ShopifyAntiFlicker,
12661
+ ShopifyAdapter,
12662
+ detectPlatform,
12663
+ COOKIE_NAME,
12664
+ ShopifyPixelBridge,
12448
12665
  StateStore,
12449
12666
  createStateStore,
12450
12667
  getSlotType,
@@ -12467,4 +12684,4 @@ export {
12467
12684
  encodeToken,
12468
12685
  Syntro
12469
12686
  };
12470
- //# sourceMappingURL=chunk-JCDCANR7.js.map
12687
+ //# sourceMappingURL=chunk-NVV7IWJC.js.map