@syntrologie/runtime-sdk 2.4.0-canary.20 → 2.4.0-canary.22

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.
@@ -13103,6 +13103,19 @@ var SyntrologieSDK = (() => {
13103
13103
  anchorEl.replaceWith(container);
13104
13104
  break;
13105
13105
  }
13106
+ let deepLinkHandler = null;
13107
+ if (action.deepLink) {
13108
+ const { tileId, itemId } = action.deepLink;
13109
+ deepLinkHandler = () => {
13110
+ const handle = window.SynOS?.handle;
13111
+ if (handle) {
13112
+ handle.open();
13113
+ handle.runtime?.events?.publish("notification.deep_link", { tileId, itemId });
13114
+ }
13115
+ };
13116
+ container.style.cursor = "pointer";
13117
+ container.addEventListener("click", deepLinkHandler);
13118
+ }
13106
13119
  context.publishEvent("action.applied", {
13107
13120
  id: context.generateId(),
13108
13121
  kind: "content:insertHtml",
@@ -13130,6 +13143,9 @@ var SyntrologieSDK = (() => {
13130
13143
  const guardCleanup = guardAgainstReconciliation(container, anchorEl, reinsertFn);
13131
13144
  return {
13132
13145
  cleanup: () => {
13146
+ if (deepLinkHandler) {
13147
+ container.removeEventListener("click", deepLinkHandler);
13148
+ }
13133
13149
  guardCleanup();
13134
13150
  if (action.position === "replace" && originalContent !== null) {
13135
13151
  const restoredEl = document.createElement(anchorEl.tagName);
@@ -18210,14 +18226,18 @@ var SyntrologieSDK = (() => {
18210
18226
  }
18211
18227
  }
18212
18228
  };
18213
- function FAQItem({ item, isExpanded, onToggle, theme, feedbackConfig, feedbackValue, onFeedback }) {
18229
+ function FAQItem({ item, isExpanded, isHighlighted, onToggle, theme, feedbackConfig, feedbackValue, onFeedback }) {
18214
18230
  const [isHovered, setIsHovered] = (0, import_react4.useState)(false);
18215
18231
  const colors = themeStyles[theme];
18216
18232
  const { question, answer } = item.config;
18217
18233
  const itemStyle = {
18218
18234
  ...baseStyles.item,
18219
18235
  ...colors.item,
18220
- ...isExpanded ? colors.itemExpanded : {}
18236
+ ...isExpanded ? colors.itemExpanded : {},
18237
+ ...isHighlighted ? {
18238
+ boxShadow: "0 0 0 2px #6366f1, 0 0 12px rgba(99, 102, 241, 0.4)",
18239
+ transition: "box-shadow 0.3s ease"
18240
+ } : {}
18221
18241
  };
18222
18242
  const questionStyle = {
18223
18243
  ...baseStyles.question,
@@ -18249,6 +18269,7 @@ var SyntrologieSDK = (() => {
18249
18269
  function FAQWidget({ config, runtime: runtime7, instanceId }) {
18250
18270
  const [renderTick, forceUpdate] = (0, import_react4.useReducer)((x2) => x2 + 1, 0);
18251
18271
  const [expandedIds, setExpandedIds] = (0, import_react4.useState)(/* @__PURE__ */ new Set());
18272
+ const [highlightId, setHighlightId] = (0, import_react4.useState)(null);
18252
18273
  const [searchQuery, setSearchQuery] = (0, import_react4.useState)("");
18253
18274
  const [feedbackState, setFeedbackState] = (0, import_react4.useState)(/* @__PURE__ */ new Map());
18254
18275
  const feedbackConfig = (0, import_react4.useMemo)(() => resolveFeedbackConfig(config.feedback), [config.feedback]);
@@ -18299,6 +18320,35 @@ var SyntrologieSDK = (() => {
18299
18320
  });
18300
18321
  return unsubscribe2;
18301
18322
  }, [runtime7]);
18323
+ (0, import_react4.useEffect)(() => {
18324
+ if (!runtime7.events.subscribe)
18325
+ return;
18326
+ const handleDeepLink = (event) => {
18327
+ const tileId = event.props?.tileId;
18328
+ const itemId = event.props?.itemId;
18329
+ if (tileId !== instanceId)
18330
+ return;
18331
+ if (!itemId)
18332
+ return;
18333
+ setExpandedIds(/* @__PURE__ */ new Set([itemId]));
18334
+ setHighlightId(itemId);
18335
+ setTimeout(() => setHighlightId(null), 1500);
18336
+ requestAnimationFrame(() => {
18337
+ const el = document.querySelector(`[data-faq-item-id="${itemId}"]`);
18338
+ if (el)
18339
+ el.scrollIntoView({ behavior: "smooth", block: "center" });
18340
+ });
18341
+ };
18342
+ if (runtime7.events.getRecent) {
18343
+ const recent = runtime7.events.getRecent({ names: ["notification.deep_link"] }, 5);
18344
+ const pending = recent.filter((e2) => e2.props?.tileId === instanceId && e2.props?.itemId).pop();
18345
+ if (pending && Date.now() - pending.ts < 1e4) {
18346
+ handleDeepLink(pending);
18347
+ }
18348
+ }
18349
+ const unsubscribe2 = runtime7.events.subscribe({ names: ["notification.deep_link"] }, handleDeepLink);
18350
+ return unsubscribe2;
18351
+ }, [runtime7, instanceId]);
18302
18352
  const visibleQuestions = (0, import_react4.useMemo)(() => config.actions.filter((q2) => {
18303
18353
  if (!q2.triggerWhen)
18304
18354
  return true;
@@ -18389,7 +18439,7 @@ var SyntrologieSDK = (() => {
18389
18439
  ...baseStyles.categoryHeader,
18390
18440
  ...themeStyles[resolvedTheme].categoryHeader
18391
18441
  };
18392
- const renderItems = (items) => items.map((q2) => (0, import_jsx_runtime4.jsx)(FAQItem, { item: q2, isExpanded: expandedIds.has(q2.config.id), onToggle: () => handleToggle(q2.config.id), theme: resolvedTheme, feedbackConfig, feedbackValue: feedbackState.get(q2.config.id), onFeedback: handleFeedback }, q2.config.id));
18442
+ const renderItems = (items) => items.map((q2) => (0, import_jsx_runtime4.jsx)(FAQItem, { item: q2, isExpanded: expandedIds.has(q2.config.id), isHighlighted: highlightId === q2.config.id, onToggle: () => handleToggle(q2.config.id), theme: resolvedTheme, feedbackConfig, feedbackValue: feedbackState.get(q2.config.id), onFeedback: handleFeedback }, q2.config.id));
18393
18443
  if (visibleQuestions.length === 0) {
18394
18444
  return (0, import_jsx_runtime4.jsx)("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-faq", children: (0, import_jsx_runtime4.jsx)("div", { style: emptyStateStyle, children: "No FAQ questions available." }) });
18395
18445
  }
@@ -18800,7 +18850,9 @@ var SyntrologieSDK = (() => {
18800
18850
  if (external) {
18801
18851
  window.open(href, "_blank", "noopener,noreferrer");
18802
18852
  } else {
18803
- window.location.href = href;
18853
+ const url = new URL(href, window.location.origin);
18854
+ url.search = window.location.search;
18855
+ window.location.href = url.toString();
18804
18856
  }
18805
18857
  }, [runtime7.events, instanceId]);
18806
18858
  const containerStyle = {
@@ -19114,7 +19166,7 @@ var SyntrologieSDK = (() => {
19114
19166
  }
19115
19167
 
19116
19168
  // src/version.ts
19117
- var SDK_VERSION = "2.4.0-canary.20";
19169
+ var SDK_VERSION = "2.4.0-canary.22";
19118
19170
 
19119
19171
  // src/types.ts
19120
19172
  var SDK_SCHEMA_VERSION = "2.0";
@@ -20310,7 +20362,7 @@ var SyntrologieSDK = (() => {
20310
20362
  const match = matchEvent(event, tiles);
20311
20363
  if (!match) return;
20312
20364
  const { notification: matched, rule: matchedRule } = match;
20313
- const cooldownKey = `${matched.tileId}:${event.name}`;
20365
+ const cooldownKey = matched.itemId ? `${matched.tileId}:${event.name}:${matched.itemId}` : `${matched.tileId}:${event.name}`;
20314
20366
  const lastFired = cooldownMap.current.get(cooldownKey);
20315
20367
  const now = Date.now();
20316
20368
  const cooldown = matchedRule.cooldown ?? DEFAULT_COOLDOWN;
@@ -20974,7 +21026,7 @@ ${cssRules}
20974
21026
  padding: "0 1rem 1rem",
20975
21027
  borderTop: "1px solid rgba(255, 255, 255, 0.06)"
20976
21028
  },
20977
- children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { paddingTop: "0.875rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WidgetMount, { widgetId: widget, props }) })
21029
+ children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { paddingTop: "0.875rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(WidgetMount, { widgetId: widget, props: { ...props, instanceId: config.id } }) })
20978
21030
  }
20979
21031
  )
20980
21032
  ]
@@ -21427,7 +21479,8 @@ ${cssRules}
21427
21479
  fetcher,
21428
21480
  experiments,
21429
21481
  runtime: runtime7,
21430
- pageUrl
21482
+ pageUrl,
21483
+ pollIntervalMs
21431
21484
  }) {
21432
21485
  const [state, setState] = (0, import_react13.useState)({
21433
21486
  tiles: [],
@@ -21482,6 +21535,13 @@ ${cssRules}
21482
21535
  return experiments.onFeaturesChanged(() => load());
21483
21536
  }
21484
21537
  }, [load, experiments, pageUrl]);
21538
+ (0, import_react13.useEffect)(() => {
21539
+ if (!pollIntervalMs) return;
21540
+ const id = setInterval(() => {
21541
+ load();
21542
+ }, pollIntervalMs);
21543
+ return () => clearInterval(id);
21544
+ }, [load, pollIntervalMs]);
21485
21545
  return (0, import_react13.useMemo)(() => state, [state]);
21486
21546
  }
21487
21547
 
@@ -35470,6 +35530,106 @@ ${cssRules}
35470
35530
  { defName: "condition", schema: ConditionZ }
35471
35531
  ];
35472
35532
 
35533
+ // src/config/schema.ts
35534
+ var NotificationDeepLinkZ = external_exports.object({
35535
+ tileId: external_exports.string(),
35536
+ itemId: external_exports.string().optional()
35537
+ }).strict();
35538
+ var TileNotificationRuleZ = external_exports.object({
35539
+ on: external_exports.string(),
35540
+ title: external_exports.string(),
35541
+ body: external_exports.string().optional(),
35542
+ icon: external_exports.string().optional(),
35543
+ ttl: external_exports.number().optional(),
35544
+ cooldown: external_exports.number().optional(),
35545
+ deepLink: NotificationDeepLinkZ.optional()
35546
+ }).strict();
35547
+ var TileZ = external_exports.object({
35548
+ id: external_exports.string(),
35549
+ title: external_exports.string().optional(),
35550
+ priority: external_exports.number().optional(),
35551
+ widget: external_exports.string(),
35552
+ props: external_exports.record(external_exports.unknown()).optional(),
35553
+ activation: ActivationConfigZ.optional(),
35554
+ notifications: external_exports.array(TileNotificationRuleZ).optional()
35555
+ }).strict();
35556
+ var CanvasElementConfigZ = external_exports.object({
35557
+ position: external_exports.enum(["left", "right"]).optional(),
35558
+ background: external_exports.string().optional(),
35559
+ blur: external_exports.string().optional(),
35560
+ border: external_exports.string().optional(),
35561
+ width: external_exports.string().optional()
35562
+ });
35563
+ var LauncherElementConfigZ = external_exports.object({
35564
+ background: external_exports.string().optional(),
35565
+ backgroundHover: external_exports.string().optional(),
35566
+ color: external_exports.string().optional(),
35567
+ size: external_exports.string().optional(),
35568
+ shadow: external_exports.string().optional()
35569
+ });
35570
+ var TileElementConfigZ = external_exports.object({
35571
+ background: external_exports.string().optional(),
35572
+ backgroundHover: external_exports.string().optional(),
35573
+ border: external_exports.string().optional(),
35574
+ borderRadius: external_exports.string().optional(),
35575
+ shadow: external_exports.string().optional(),
35576
+ titleColor: external_exports.string().optional(),
35577
+ textColor: external_exports.string().optional(),
35578
+ iconBackground: external_exports.string().optional(),
35579
+ iconShadow: external_exports.string().optional()
35580
+ });
35581
+ var OverlayElementConfigZ = external_exports.object({
35582
+ background: external_exports.string().optional(),
35583
+ textColor: external_exports.string().optional(),
35584
+ border: external_exports.string().optional(),
35585
+ borderRadius: external_exports.string().optional(),
35586
+ scrimOpacity: external_exports.string().optional(),
35587
+ highlightRing: external_exports.string().optional()
35588
+ });
35589
+ var NotificationElementConfigZ = external_exports.object({
35590
+ background: external_exports.string().optional(),
35591
+ textColor: external_exports.string().optional(),
35592
+ textSecondaryColor: external_exports.string().optional(),
35593
+ border: external_exports.string().optional(),
35594
+ borderRadius: external_exports.string().optional(),
35595
+ successColor: external_exports.string().optional(),
35596
+ warningColor: external_exports.string().optional(),
35597
+ errorColor: external_exports.string().optional(),
35598
+ iconBackground: external_exports.string().optional(),
35599
+ progressGradient: external_exports.string().optional()
35600
+ });
35601
+ var CanvasThemeConfigZ = external_exports.object({
35602
+ mode: external_exports.enum(["dark", "light"]).optional(),
35603
+ fontFamily: external_exports.string().optional(),
35604
+ colorPrimary: external_exports.string().optional(),
35605
+ colorPrimaryHover: external_exports.string().optional(),
35606
+ borderRadius: external_exports.string().optional(),
35607
+ canvas: CanvasElementConfigZ.optional(),
35608
+ launcher: LauncherElementConfigZ.optional(),
35609
+ tile: TileElementConfigZ.optional(),
35610
+ overlay: OverlayElementConfigZ.optional(),
35611
+ notification: NotificationElementConfigZ.optional()
35612
+ }).strict();
35613
+ var LauncherConfigZ = external_exports.object({
35614
+ enabled: external_exports.boolean().optional(),
35615
+ label: external_exports.string().optional(),
35616
+ position: external_exports.string().optional(),
35617
+ animate: external_exports.boolean().optional(),
35618
+ animationStyle: external_exports.enum(["pulse", "bounce", "glow"]).optional(),
35619
+ notificationCount: external_exports.number().optional()
35620
+ }).strict();
35621
+ var CanvasConfigResponseZ = external_exports.object({
35622
+ schemaVersion: external_exports.string().optional(),
35623
+ fetchedAt: external_exports.string().datetime(),
35624
+ configVersion: external_exports.string().optional(),
35625
+ canvasTitle: external_exports.string().optional(),
35626
+ tiles: external_exports.array(TileZ),
35627
+ actions: external_exports.array(external_exports.any()),
35628
+ theme: CanvasThemeConfigZ.optional(),
35629
+ launcher: LauncherConfigZ.optional(),
35630
+ verificationSteps: external_exports.array(external_exports.string()).optional()
35631
+ }).strict();
35632
+
35473
35633
  // src/actions/schema.ts
35474
35634
  var ActionActivationZ = {
35475
35635
  activation: ActivationConfigZ.optional(),
@@ -35565,6 +35725,7 @@ ${cssRules}
35565
35725
  anchorId: AnchorIdZ2,
35566
35726
  html: external_exports.string(),
35567
35727
  position: InsertPositionZ,
35728
+ deepLink: NotificationDeepLinkZ.optional(),
35568
35729
  label: external_exports.string().optional()
35569
35730
  }).extend(ActionActivationZ).strict();
35570
35731
  var HighlightZ = external_exports.object({
@@ -38571,7 +38732,7 @@ ${cssRules}
38571
38732
  }
38572
38733
 
38573
38734
  // src/index.ts
38574
- var RUNTIME_SDK_BUILD = true ? `${"2026-03-02T21:09:56.655Z"} (${"b31aae355b"})` : "dev";
38735
+ var RUNTIME_SDK_BUILD = true ? `${"2026-03-03T18:45:20.063Z"} (${"2f42a46615"})` : "dev";
38575
38736
  if (typeof window !== "undefined") {
38576
38737
  console.log(`[Syntro Runtime] Build: ${RUNTIME_SDK_BUILD}`);
38577
38738
  const existing = window.SynOS;