@syntrologie/runtime-sdk 2.4.0-canary.23 → 2.4.0-canary.25

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.
@@ -12860,6 +12860,7 @@ var SyntrologieSDK = (() => {
12860
12860
  TooltipZ: () => TooltipZ,
12861
12861
  TourStepForSchemaZ: () => TourStepForSchemaZ,
12862
12862
  TourZ: () => TourZ,
12863
+ TriggerWhenZ: () => TriggerWhenZ,
12863
12864
  ViewportConditionZ: () => ViewportConditionZ,
12864
12865
  ViewportContextZ: () => ViewportContextZ,
12865
12866
  WaitZ: () => WaitZ,
@@ -12950,7 +12951,7 @@ var SyntrologieSDK = (() => {
12950
12951
  validateStrategy: () => validateStrategy,
12951
12952
  widgetRegistry: () => widgetRegistry
12952
12953
  });
12953
- var import_react17 = __toESM(require_react(), 1);
12954
+ var import_react19 = __toESM(require_react(), 1);
12954
12955
  var import_react_dom3 = __toESM(require_react_dom(), 1);
12955
12956
  var ReactDOMClient = __toESM(require_client(), 1);
12956
12957
 
@@ -13726,7 +13727,7 @@ var SyntrologieSDK = (() => {
13726
13727
  };
13727
13728
 
13728
13729
  // ../adaptives/adaptive-overlays/dist/celebrations/index.js
13729
- var DEFAULT_COLORS2 = [
13730
+ var FALLBACK_COLORS = [
13730
13731
  "#ff0000",
13731
13732
  "#00ff00",
13732
13733
  "#0000ff",
@@ -13736,6 +13737,21 @@ var SyntrologieSDK = (() => {
13736
13737
  "#ff8800",
13737
13738
  "#8800ff"
13738
13739
  ];
13740
+ function buildThemePalette(primary, hover) {
13741
+ return [primary, hover, `${primary}cc`, `${hover}cc`, "#ffffff", `${primary}80`];
13742
+ }
13743
+ function readThemeColors(overlayRoot) {
13744
+ try {
13745
+ const styles2 = getComputedStyle(overlayRoot);
13746
+ const primary = styles2.getPropertyValue("--sc-color-primary")?.trim();
13747
+ const hover = styles2.getPropertyValue("--sc-color-primary-hover")?.trim();
13748
+ if (primary?.startsWith("#") && primary.length >= 7) {
13749
+ return buildThemePalette(primary, hover || primary);
13750
+ }
13751
+ } catch {
13752
+ }
13753
+ return null;
13754
+ }
13739
13755
  var effectRegistry = /* @__PURE__ */ new Map([
13740
13756
  ["confetti", confettiEffect],
13741
13757
  ["fireworks", fireworksEffect],
@@ -13749,10 +13765,11 @@ var SyntrologieSDK = (() => {
13749
13765
  return { cleanup: () => {
13750
13766
  } };
13751
13767
  }
13768
+ const colors = action.colors ?? readThemeColors(context.overlayRoot) ?? FALLBACK_COLORS;
13752
13769
  const config = {
13753
13770
  duration: action.duration ?? 3e3,
13754
13771
  intensity: action.intensity ?? "medium",
13755
- colors: action.colors ?? DEFAULT_COLORS2,
13772
+ colors,
13756
13773
  props: action.props
13757
13774
  };
13758
13775
  const engine = new CelebrationEngine();
@@ -14622,6 +14639,13 @@ var SyntrologieSDK = (() => {
14622
14639
  }
14623
14640
 
14624
14641
  // ../adaptives/adaptive-overlays/dist/modal.js
14642
+ var V = {
14643
+ bg: "var(--sc-overlay-background, #ffffff)",
14644
+ title: "var(--sc-overlay-title-color, var(--sc-overlay-text-color, #111827))",
14645
+ text: "var(--sc-overlay-text-color, #4b5563)",
14646
+ accent: "var(--sc-color-primary, #4f46e5)",
14647
+ radius: "var(--sc-border-radius, 12px)"
14648
+ };
14625
14649
  var executeModal = async (action, context) => {
14626
14650
  const { content, size: size2 = "md", blocking = false, scrim, dismiss, ctaButtons } = action;
14627
14651
  const scrimEl = document.createElement("div");
@@ -14647,8 +14671,8 @@ var SyntrologieSDK = (() => {
14647
14671
  transform: translate(-50%, -50%) scale(0.95);
14648
14672
  max-width: ${sizeMap[size2]};
14649
14673
  width: 90%;
14650
- background: ${base.white};
14651
- border-radius: 12px;
14674
+ background: ${V.bg};
14675
+ border-radius: ${V.radius};
14652
14676
  box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
14653
14677
  z-index: 2147483646;
14654
14678
  opacity: 0;
@@ -14657,9 +14681,9 @@ var SyntrologieSDK = (() => {
14657
14681
  `;
14658
14682
  let html2 = "";
14659
14683
  if (content.title) {
14660
- html2 += `<h2 class="syntro-modal-title" style="margin: 0 0 12px 0; font-size: 18px; font-weight: 600; color: #111827;">${sanitizeHtml2(content.title)}</h2>`;
14684
+ 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>`;
14661
14685
  }
14662
- html2 += `<div class="syntro-modal-body" style="color: #4b5563; line-height: 1.5;">${sanitizeHtml2(content.body)}</div>`;
14686
+ html2 += `<div class="syntro-modal-body" style="color: ${V.text}; line-height: 1.5;">${sanitizeHtml2(content.body)}</div>`;
14663
14687
  if (dismiss?.closeButton !== false) {
14664
14688
  html2 += `
14665
14689
  <button class="syntro-modal-close" data-syntro-action="dismiss" style="
@@ -14670,7 +14694,8 @@ var SyntrologieSDK = (() => {
14670
14694
  border: none;
14671
14695
  cursor: pointer;
14672
14696
  padding: 4px;
14673
- color: #6b7280;
14697
+ color: ${V.text};
14698
+ opacity: 0.6;
14674
14699
  " aria-label="Close">
14675
14700
  <svg width="20" height="20" viewBox="0 0 20 20" fill="currentColor">
14676
14701
  <path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
@@ -14693,7 +14718,7 @@ var SyntrologieSDK = (() => {
14693
14718
  font-weight: 500;
14694
14719
  cursor: pointer;
14695
14720
  transition: background 150ms ease;
14696
- ${isPrimary ? "background: #4f46e5; color: white; border: none;" : "background: white; color: #374151; border: 1px solid #d1d5db;"}
14721
+ ${isPrimary ? `background: ${V.accent}; color: white; border: none;` : `background: transparent; color: ${V.accent}; border: 1px solid currentColor; opacity: 0.7;`}
14697
14722
  "
14698
14723
  >
14699
14724
  ${sanitizeHtml2(btn.label)}
@@ -16778,11 +16803,26 @@ var SyntrologieSDK = (() => {
16778
16803
  return { cleanup: () => {
16779
16804
  } };
16780
16805
  }
16806
+ const existing = anchorEl.getAttribute("data-syntro-highlight");
16807
+ if (existing) {
16808
+ const prev = context.overlayRoot.querySelectorAll(".syntro-spotlight-scrim, .syntro-spotlight-ring");
16809
+ prev.forEach((el) => el.remove());
16810
+ }
16811
+ anchorEl.setAttribute("data-syntro-highlight", "true");
16812
+ let ringColor = action.style?.color;
16813
+ if (!ringColor) {
16814
+ try {
16815
+ const primary = getComputedStyle(context.overlayRoot).getPropertyValue("--sc-color-primary")?.trim();
16816
+ if (primary)
16817
+ ringColor = primary;
16818
+ } catch {
16819
+ }
16820
+ }
16781
16821
  const handle = showHighlight(anchorEl, context.overlayRoot, {
16782
16822
  paddingPx: action.style?.paddingPx ?? 12,
16783
16823
  radiusPx: action.style?.radiusPx ?? 12,
16784
16824
  scrimOpacity: action.style?.scrimOpacity ?? 0.55,
16785
- ringColor: action.style?.color,
16825
+ ringColor,
16786
16826
  blocking: action.blocking ?? false,
16787
16827
  onClickOutside: action.onClickOutside ?? true,
16788
16828
  onEsc: action.onEsc ?? true
@@ -16795,6 +16835,7 @@ var SyntrologieSDK = (() => {
16795
16835
  return {
16796
16836
  cleanup: () => {
16797
16837
  handle.destroy();
16838
+ anchorEl.removeAttribute("data-syntro-highlight");
16798
16839
  }
16799
16840
  };
16800
16841
  };
@@ -17056,7 +17097,7 @@ var SyntrologieSDK = (() => {
17056
17097
  executors: executors2,
17057
17098
  widgets: [
17058
17099
  {
17059
- id: "workflow:tracker",
17100
+ id: "adaptive-overlays:workflow-tracker",
17060
17101
  component: WorkflowMountableWidget,
17061
17102
  metadata: {
17062
17103
  name: "Workflow Tracker",
@@ -18093,7 +18134,7 @@ var SyntrologieSDK = (() => {
18093
18134
  }
18094
18135
  var baseStyles = {
18095
18136
  container: {
18096
- fontFamily: "system-ui, -apple-system, sans-serif",
18137
+ fontFamily: "var(--sc-font-family, system-ui, -apple-system, sans-serif)",
18097
18138
  maxWidth: "800px",
18098
18139
  margin: "0 auto"
18099
18140
  },
@@ -18106,7 +18147,9 @@ var SyntrologieSDK = (() => {
18106
18147
  borderRadius: "8px",
18107
18148
  fontSize: "14px",
18108
18149
  outline: "none",
18109
- transition: "border-color 0.15s ease"
18150
+ transition: "border-color 0.15s ease",
18151
+ backgroundColor: "var(--sc-content-search-background)",
18152
+ color: "var(--sc-content-search-color)"
18110
18153
  },
18111
18154
  accordion: {
18112
18155
  display: "flex",
@@ -18132,8 +18175,9 @@ var SyntrologieSDK = (() => {
18132
18175
  transition: "background-color 0.15s ease"
18133
18176
  },
18134
18177
  chevron: {
18135
- fontSize: "18px",
18136
- transition: "transform 0.2s ease"
18178
+ fontSize: "20px",
18179
+ transition: "transform 0.2s ease",
18180
+ color: "var(--sc-content-chevron-color, currentColor)"
18137
18181
  },
18138
18182
  answer: {
18139
18183
  padding: "var(--sc-content-body-padding, 0 16px 12px 16px)",
@@ -18200,9 +18244,7 @@ var SyntrologieSDK = (() => {
18200
18244
  color: "inherit"
18201
18245
  },
18202
18246
  searchInput: {
18203
- backgroundColor: slateGrey[12],
18204
- border: `1px solid ${slateGrey[11]}`,
18205
- color: slateGrey[1]
18247
+ border: `1px solid ${slateGrey[11]}`
18206
18248
  },
18207
18249
  item: {
18208
18250
  backgroundColor: "var(--sc-content-background)",
@@ -18241,9 +18283,7 @@ var SyntrologieSDK = (() => {
18241
18283
  color: "inherit"
18242
18284
  },
18243
18285
  searchInput: {
18244
- backgroundColor: slateGrey[3],
18245
- border: `1px solid ${slateGrey[5]}`,
18246
- color: slateGrey[12]
18286
+ border: `1px solid ${slateGrey[5]}`
18247
18287
  },
18248
18288
  item: {
18249
18289
  backgroundColor: "var(--sc-content-background)",
@@ -18277,7 +18317,7 @@ var SyntrologieSDK = (() => {
18277
18317
  }
18278
18318
  }
18279
18319
  };
18280
- function FAQItem({ item, isExpanded, isHighlighted, onToggle, theme, feedbackConfig, feedbackValue, onFeedback }) {
18320
+ function FAQItem({ item, isExpanded, isHighlighted, isLast, onToggle, theme, feedbackConfig, feedbackValue, onFeedback }) {
18281
18321
  const [isHovered, setIsHovered] = (0, import_react4.useState)(false);
18282
18322
  const colors = themeStyles[theme];
18283
18323
  const { question, answer } = item.config;
@@ -18288,7 +18328,8 @@ var SyntrologieSDK = (() => {
18288
18328
  ...isHighlighted ? {
18289
18329
  boxShadow: "0 0 0 2px #6366f1, 0 0 12px rgba(99, 102, 241, 0.4)",
18290
18330
  transition: "box-shadow 0.3s ease"
18291
- } : {}
18331
+ } : {},
18332
+ ...!isLast ? { borderBottom: "var(--sc-content-item-divider, none)" } : {}
18292
18333
  };
18293
18334
  const questionStyle = {
18294
18335
  ...baseStyles.question,
@@ -18297,7 +18338,7 @@ var SyntrologieSDK = (() => {
18297
18338
  };
18298
18339
  const chevronStyle = {
18299
18340
  ...baseStyles.chevron,
18300
- transform: isExpanded ? "rotate(180deg)" : "rotate(0deg)"
18341
+ transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)"
18301
18342
  };
18302
18343
  const answerStyle = {
18303
18344
  ...baseStyles.answer,
@@ -18309,7 +18350,7 @@ var SyntrologieSDK = (() => {
18309
18350
  ...baseStyles.feedback,
18310
18351
  ...colors.feedbackPrompt
18311
18352
  };
18312
- return (0, import_jsx_runtime4.jsxs)("div", { style: itemStyle, "data-faq-item-id": item.config.id, children: [(0, import_jsx_runtime4.jsxs)("button", { type: "button", style: questionStyle, onClick: onToggle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "aria-expanded": isExpanded, children: [(0, import_jsx_runtime4.jsx)("span", { children: question }), (0, import_jsx_runtime4.jsx)("span", { style: chevronStyle, children: "\u25BC" })] }), (0, import_jsx_runtime4.jsxs)("div", { style: answerStyle, "aria-hidden": !isExpanded, children: [renderAnswer(answer), isExpanded && feedbackConfig && (0, import_jsx_runtime4.jsxs)("div", { style: feedbackStyle, children: [(0, import_jsx_runtime4.jsx)("span", { children: getFeedbackPrompt(feedbackConfig) }), (0, import_jsx_runtime4.jsx)("button", { type: "button", style: {
18353
+ return (0, import_jsx_runtime4.jsxs)("div", { style: itemStyle, "data-faq-item-id": item.config.id, children: [(0, import_jsx_runtime4.jsxs)("button", { type: "button", style: questionStyle, onClick: onToggle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "aria-expanded": isExpanded, children: [(0, import_jsx_runtime4.jsx)("span", { children: question }), (0, import_jsx_runtime4.jsx)("span", { style: chevronStyle, children: "\u203A" })] }), (0, import_jsx_runtime4.jsxs)("div", { style: answerStyle, "aria-hidden": !isExpanded, children: [renderAnswer(answer), isExpanded && feedbackConfig && (0, import_jsx_runtime4.jsxs)("div", { style: feedbackStyle, children: [(0, import_jsx_runtime4.jsx)("span", { children: getFeedbackPrompt(feedbackConfig) }), (0, import_jsx_runtime4.jsx)("button", { type: "button", style: {
18313
18354
  ...baseStyles.feedbackButton,
18314
18355
  ...feedbackValue === "up" ? baseStyles.feedbackButtonSelected : {}
18315
18356
  }, "aria-label": "Thumbs up", onClick: () => onFeedback(item.config.id, question, "up"), children: "\u{1F44D}" }), (0, import_jsx_runtime4.jsx)("button", { type: "button", style: {
@@ -18490,11 +18531,11 @@ var SyntrologieSDK = (() => {
18490
18531
  ...baseStyles.categoryHeader,
18491
18532
  ...themeStyles[resolvedTheme].categoryHeader
18492
18533
  };
18493
- 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));
18534
+ const renderItems = (items) => items.map((q2, index2) => (0, import_jsx_runtime4.jsx)(FAQItem, { item: q2, isExpanded: expandedIds.has(q2.config.id), isHighlighted: highlightId === q2.config.id, isLast: index2 === items.length - 1, onToggle: () => handleToggle(q2.config.id), theme: resolvedTheme, feedbackConfig, feedbackValue: feedbackState.get(q2.config.id), onFeedback: handleFeedback }, q2.config.id));
18494
18535
  if (visibleQuestions.length === 0) {
18495
- 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." }) });
18536
+ 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: "You're all set for now! We'll surface answers here when they're relevant to what you're doing." }) });
18496
18537
  }
18497
- return (0, import_jsx_runtime4.jsxs)("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-faq", children: [config.searchable && (0, import_jsx_runtime4.jsx)("div", { style: baseStyles.searchWrapper, children: (0, import_jsx_runtime4.jsx)("input", { type: "text", placeholder: "Search questions...", value: searchQuery, onChange: (e2) => setSearchQuery(e2.target.value), style: searchInputStyle }) }), (0, import_jsx_runtime4.jsx)("div", { style: baseStyles.accordion, children: hasCategories ? Array.from(categoryGroups.entries()).map(([category, items]) => (0, import_jsx_runtime4.jsxs)(import_react4.default.Fragment, { children: [category && (0, import_jsx_runtime4.jsx)("div", { style: categoryHeaderStyle, "data-category-header": category, children: category }), renderItems(items)] }, category ?? "__ungrouped")) : renderItems(filteredQuestions) }), config.searchable && filteredQuestions.length === 0 && searchQuery && (0, import_jsx_runtime4.jsxs)("div", { style: { ...baseStyles.noResults, ...themeStyles[resolvedTheme].emptyState }, children: ['No questions found matching "', searchQuery, '"'] })] });
18538
+ return (0, import_jsx_runtime4.jsxs)("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-faq", children: [config.searchable && (0, import_jsx_runtime4.jsxs)("div", { style: baseStyles.searchWrapper, children: [(0, import_jsx_runtime4.jsx)("style", { children: `[data-adaptive-id="${instanceId}"] input::placeholder { color: var(--sc-content-search-color, inherit); opacity: 0.7; }` }), (0, import_jsx_runtime4.jsx)("input", { type: "text", placeholder: "Search questions...", value: searchQuery, onChange: (e2) => setSearchQuery(e2.target.value), style: searchInputStyle })] }), (0, import_jsx_runtime4.jsx)("div", { style: baseStyles.accordion, children: hasCategories ? Array.from(categoryGroups.entries()).map(([category, items]) => (0, import_jsx_runtime4.jsxs)(import_react4.default.Fragment, { children: [category && (0, import_jsx_runtime4.jsx)("div", { style: categoryHeaderStyle, "data-category-header": category, children: category }), renderItems(items)] }, category ?? "__ungrouped")) : renderItems(filteredQuestions) }), config.searchable && filteredQuestions.length === 0 && searchQuery && (0, import_jsx_runtime4.jsxs)("div", { style: { ...baseStyles.noResults, ...themeStyles[resolvedTheme].emptyState }, children: ['No questions found matching "', searchQuery, '"'] })] });
18498
18539
  }
18499
18540
  var FAQMountableWidget = {
18500
18541
  mount(container, config) {
@@ -18552,7 +18593,8 @@ var SyntrologieSDK = (() => {
18552
18593
  metadata: {
18553
18594
  name: "FAQ Accordion",
18554
18595
  description: "Collapsible Q&A accordion with search, categories, and feedback",
18555
- icon: "\u2753"
18596
+ icon: "\u2753",
18597
+ subtitle: "Curated just for you."
18556
18598
  }
18557
18599
  }
18558
18600
  ],
@@ -18921,7 +18963,7 @@ var SyntrologieSDK = (() => {
18921
18963
  };
18922
18964
  const renderItems = (items) => items.map((tip, index2) => (0, import_jsx_runtime5.jsx)(NavTipItem, { item: tip, isExpanded: expandedIds.has(tip.config.id), isLast: index2 === items.length - 1, onToggle: () => handleToggle(tip.config.id), onNavigate: handleNavigate, theme: resolvedTheme }, tip.config.id));
18923
18965
  if (visibleTips.length === 0) {
18924
- return (0, import_jsx_runtime5.jsx)("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-nav", children: (0, import_jsx_runtime5.jsx)("div", { style: emptyStateStyle, children: "No navigation tips available." }) });
18966
+ return (0, import_jsx_runtime5.jsx)("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-nav", children: (0, import_jsx_runtime5.jsx)("div", { style: emptyStateStyle, children: "You're all set for now! We'll share helpful tips here when they're relevant to what you're doing." }) });
18925
18967
  }
18926
18968
  return (0, import_jsx_runtime5.jsx)("div", { style: containerStyle, "data-adaptive-id": instanceId, "data-adaptive-type": "adaptive-nav", children: (0, import_jsx_runtime5.jsx)("div", { style: baseStyles2.accordion, children: hasCategories ? Array.from(categoryGroups.entries()).map(([category, items]) => (0, import_jsx_runtime5.jsxs)(import_react5.default.Fragment, { children: [category && (0, import_jsx_runtime5.jsx)("div", { style: categoryHeaderStyle, "data-category-header": category, children: category }), renderItems(items)] }, category ?? "__ungrouped")) : renderItems(visibleTips) }) });
18927
18969
  }
@@ -19218,7 +19260,7 @@ var SyntrologieSDK = (() => {
19218
19260
  }
19219
19261
 
19220
19262
  // src/version.ts
19221
- var SDK_VERSION = "2.4.0-canary.23";
19263
+ var SDK_VERSION = "2.4.0-canary.25";
19222
19264
 
19223
19265
  // src/types.ts
19224
19266
  var SDK_SCHEMA_VERSION = "2.0";
@@ -19683,6 +19725,9 @@ var SyntrologieSDK = (() => {
19683
19725
  --syntro-border: var(--sc-overlay-border, #2b333f);
19684
19726
  --syntro-tooltip-bg: var(--syntro-surface);
19685
19727
  --syntro-tooltip-fg: var(--syntro-fg);
19728
+ --syntro-tooltip-title-color: var(--sc-overlay-title-color, var(--syntro-fg));
19729
+ --syntro-tooltip-arrow-bg: var(--sc-overlay-arrow-color, var(--syntro-tooltip-bg));
19730
+ --syntro-tooltip-arrow-size: var(--sc-overlay-arrow-size, 8px);
19686
19731
  --syntro-tooltip-radius: var(--syntro-radius);
19687
19732
  --syntro-tooltip-padding: 12px 16px;
19688
19733
  --syntro-tooltip-shadow: var(--syntro-shadow);
@@ -19709,14 +19754,13 @@ var SyntrologieSDK = (() => {
19709
19754
  transform 200ms cubic-bezier(0.16, 1, 0.3, 1);
19710
19755
  }
19711
19756
 
19712
- /* Tooltip arrow */
19757
+ /* Tooltip arrow \u2014 triangle via clip-path (square box so rotation is symmetric) */
19713
19758
  .syntro-tooltip-arrow {
19714
19759
  position: absolute;
19715
- width: 8px;
19716
- height: 8px;
19717
- background: inherit;
19718
- transform: rotate(45deg);
19719
- z-index: -1;
19760
+ width: var(--syntro-tooltip-arrow-size);
19761
+ height: var(--syntro-tooltip-arrow-size);
19762
+ background: var(--syntro-tooltip-arrow-bg);
19763
+ clip-path: polygon(0 0, 100% 0, 50% 100%);
19720
19764
  }
19721
19765
 
19722
19766
  /* Tooltip content */
@@ -19724,6 +19768,7 @@ var SyntrologieSDK = (() => {
19724
19768
  font-weight: 600;
19725
19769
  font-size: 15px;
19726
19770
  margin-bottom: 6px;
19771
+ color: var(--syntro-tooltip-title-color);
19727
19772
  }
19728
19773
 
19729
19774
  .syntro-tt-body {
@@ -20006,10 +20051,10 @@ var SyntrologieSDK = (() => {
20006
20051
  }
20007
20052
 
20008
20053
  // src/SmartCanvasApp.tsx
20009
- var import_react14 = __toESM(require_react(), 1);
20054
+ var import_react16 = __toESM(require_react(), 1);
20010
20055
 
20011
20056
  // src/components/ShadowCanvasOverlay.tsx
20012
- var import_react12 = __toESM(require_react(), 1);
20057
+ var import_react14 = __toESM(require_react(), 1);
20013
20058
  var import_react_dom = __toESM(require_react_dom(), 1);
20014
20059
 
20015
20060
  // src/events/types.ts
@@ -20759,7 +20804,10 @@ var SyntrologieSDK = (() => {
20759
20804
  background: withAlpha(slateGrey[1], 0.6),
20760
20805
  blur: "blur(24px)",
20761
20806
  border: "none",
20762
- width: "clamp(380px, 25vw, 520px)"
20807
+ width: "clamp(380px, 25vw, 520px)",
20808
+ transitionDuration: "300ms",
20809
+ transitionEasing: "cubic-bezier(0.16, 1, 0.3, 1)",
20810
+ transitionFade: "6%"
20763
20811
  },
20764
20812
  launcher: {
20765
20813
  background: button.primary.backgroundDefault,
@@ -20839,7 +20887,10 @@ var SyntrologieSDK = (() => {
20839
20887
  background: withAlpha(slateGrey[12], 0.7),
20840
20888
  blur: "blur(24px)",
20841
20889
  border: "none",
20842
- width: "clamp(380px, 25vw, 520px)"
20890
+ width: "clamp(380px, 25vw, 520px)",
20891
+ transitionDuration: "300ms",
20892
+ transitionEasing: "cubic-bezier(0.16, 1, 0.3, 1)",
20893
+ transitionFade: "6%"
20843
20894
  },
20844
20895
  launcher: {
20845
20896
  background: brand[3],
@@ -21014,16 +21065,257 @@ ${cssRules}
21014
21065
  }
21015
21066
 
21016
21067
  // src/components/TileCard.tsx
21017
- var import_react11 = __toESM(require_react(), 1);
21068
+ var import_react13 = __toESM(require_react(), 1);
21069
+
21070
+ // ../../node_modules/lucide-react/dist/esm/createLucideIcon.js
21071
+ var import_react12 = __toESM(require_react());
21072
+
21073
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/mergeClasses.js
21074
+ var mergeClasses = (...classes2) => classes2.filter((className, index2, array) => {
21075
+ return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index2;
21076
+ }).join(" ").trim();
21077
+
21078
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/toKebabCase.js
21079
+ var toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
21080
+
21081
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/toCamelCase.js
21082
+ var toCamelCase = (string) => string.replace(
21083
+ /^([A-Z])|[\s-_]+(\w)/g,
21084
+ (match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
21085
+ );
21086
+
21087
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/toPascalCase.js
21088
+ var toPascalCase = (string) => {
21089
+ const camelCase = toCamelCase(string);
21090
+ return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
21091
+ };
21092
+
21093
+ // ../../node_modules/lucide-react/dist/esm/Icon.js
21094
+ var import_react11 = __toESM(require_react());
21095
+
21096
+ // ../../node_modules/lucide-react/dist/esm/defaultAttributes.js
21097
+ var defaultAttributes = {
21098
+ xmlns: "http://www.w3.org/2000/svg",
21099
+ width: 24,
21100
+ height: 24,
21101
+ viewBox: "0 0 24 24",
21102
+ fill: "none",
21103
+ stroke: "currentColor",
21104
+ strokeWidth: 2,
21105
+ strokeLinecap: "round",
21106
+ strokeLinejoin: "round"
21107
+ };
21108
+
21109
+ // ../../node_modules/lucide-react/dist/esm/shared/src/utils/hasA11yProp.js
21110
+ var hasA11yProp = (props) => {
21111
+ for (const prop in props) {
21112
+ if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
21113
+ return true;
21114
+ }
21115
+ }
21116
+ return false;
21117
+ };
21118
+
21119
+ // ../../node_modules/lucide-react/dist/esm/Icon.js
21120
+ var Icon = (0, import_react11.forwardRef)(
21121
+ ({
21122
+ color = "currentColor",
21123
+ size: size2 = 24,
21124
+ strokeWidth = 2,
21125
+ absoluteStrokeWidth,
21126
+ className = "",
21127
+ children,
21128
+ iconNode,
21129
+ ...rest
21130
+ }, ref) => (0, import_react11.createElement)(
21131
+ "svg",
21132
+ {
21133
+ ref,
21134
+ ...defaultAttributes,
21135
+ width: size2,
21136
+ height: size2,
21137
+ stroke: color,
21138
+ strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size2) : strokeWidth,
21139
+ className: mergeClasses("lucide", className),
21140
+ ...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
21141
+ ...rest
21142
+ },
21143
+ [
21144
+ ...iconNode.map(([tag2, attrs]) => (0, import_react11.createElement)(tag2, attrs)),
21145
+ ...Array.isArray(children) ? children : [children]
21146
+ ]
21147
+ )
21148
+ );
21149
+
21150
+ // ../../node_modules/lucide-react/dist/esm/createLucideIcon.js
21151
+ var createLucideIcon = (iconName, iconNode) => {
21152
+ const Component = (0, import_react12.forwardRef)(
21153
+ ({ className, ...props }, ref) => (0, import_react12.createElement)(Icon, {
21154
+ ref,
21155
+ iconNode,
21156
+ className: mergeClasses(
21157
+ `lucide-${toKebabCase(toPascalCase(iconName))}`,
21158
+ `lucide-${iconName}`,
21159
+ className
21160
+ ),
21161
+ ...props
21162
+ })
21163
+ );
21164
+ Component.displayName = toPascalCase(iconName);
21165
+ return Component;
21166
+ };
21167
+
21168
+ // ../../node_modules/lucide-react/dist/esm/icons/circle-question-mark.js
21169
+ var __iconNode = [
21170
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
21171
+ ["path", { d: "M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3", key: "1u773s" }],
21172
+ ["path", { d: "M12 17h.01", key: "p32p05" }]
21173
+ ];
21174
+ var CircleQuestionMark = createLucideIcon("circle-question-mark", __iconNode);
21175
+
21176
+ // ../../node_modules/lucide-react/dist/esm/icons/compass.js
21177
+ var __iconNode2 = [
21178
+ ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
21179
+ [
21180
+ "path",
21181
+ {
21182
+ d: "m16.24 7.76-1.804 5.411a2 2 0 0 1-1.265 1.265L7.76 16.24l1.804-5.411a2 2 0 0 1 1.265-1.265z",
21183
+ key: "9ktpf1"
21184
+ }
21185
+ ]
21186
+ ];
21187
+ var Compass = createLucideIcon("compass", __iconNode2);
21188
+
21189
+ // ../../node_modules/lucide-react/dist/esm/icons/file-text.js
21190
+ var __iconNode3 = [
21191
+ [
21192
+ "path",
21193
+ {
21194
+ d: "M6 22a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h8a2.4 2.4 0 0 1 1.704.706l3.588 3.588A2.4 2.4 0 0 1 20 8v12a2 2 0 0 1-2 2z",
21195
+ key: "1oefj6"
21196
+ }
21197
+ ],
21198
+ ["path", { d: "M14 2v5a1 1 0 0 0 1 1h5", key: "wfsgrz" }],
21199
+ ["path", { d: "M10 9H8", key: "b1mrlr" }],
21200
+ ["path", { d: "M16 13H8", key: "t4e002" }],
21201
+ ["path", { d: "M16 17H8", key: "z1uh3a" }]
21202
+ ];
21203
+ var FileText = createLucideIcon("file-text", __iconNode3);
21204
+
21205
+ // ../../node_modules/lucide-react/dist/esm/icons/gamepad-2.js
21206
+ var __iconNode4 = [
21207
+ ["line", { x1: "6", x2: "10", y1: "11", y2: "11", key: "1gktln" }],
21208
+ ["line", { x1: "8", x2: "8", y1: "9", y2: "13", key: "qnk9ow" }],
21209
+ ["line", { x1: "15", x2: "15.01", y1: "12", y2: "12", key: "krot7o" }],
21210
+ ["line", { x1: "18", x2: "18.01", y1: "10", y2: "10", key: "1lcuu1" }],
21211
+ [
21212
+ "path",
21213
+ {
21214
+ d: "M17.32 5H6.68a4 4 0 0 0-3.978 3.59c-.006.052-.01.101-.017.152C2.604 9.416 2 14.456 2 16a3 3 0 0 0 3 3c1 0 1.5-.5 2-1l1.414-1.414A2 2 0 0 1 9.828 16h4.344a2 2 0 0 1 1.414.586L17 18c.5.5 1 1 2 1a3 3 0 0 0 3-3c0-1.545-.604-6.584-.685-7.258-.007-.05-.011-.1-.017-.151A4 4 0 0 0 17.32 5z",
21215
+ key: "mfqc10"
21216
+ }
21217
+ ]
21218
+ ];
21219
+ var Gamepad2 = createLucideIcon("gamepad-2", __iconNode4);
21220
+
21221
+ // ../../node_modules/lucide-react/dist/esm/icons/layers.js
21222
+ var __iconNode5 = [
21223
+ [
21224
+ "path",
21225
+ {
21226
+ d: "M12.83 2.18a2 2 0 0 0-1.66 0L2.6 6.08a1 1 0 0 0 0 1.83l8.58 3.91a2 2 0 0 0 1.66 0l8.58-3.9a1 1 0 0 0 0-1.83z",
21227
+ key: "zw3jo"
21228
+ }
21229
+ ],
21230
+ [
21231
+ "path",
21232
+ {
21233
+ d: "M2 12a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 12",
21234
+ key: "1wduqc"
21235
+ }
21236
+ ],
21237
+ [
21238
+ "path",
21239
+ {
21240
+ d: "M2 17a1 1 0 0 0 .58.91l8.6 3.91a2 2 0 0 0 1.65 0l8.58-3.9A1 1 0 0 0 22 17",
21241
+ key: "kqbvx6"
21242
+ }
21243
+ ]
21244
+ ];
21245
+ var Layers = createLucideIcon("layers", __iconNode5);
21246
+
21247
+ // ../../node_modules/lucide-react/dist/esm/icons/message-circle.js
21248
+ var __iconNode6 = [
21249
+ [
21250
+ "path",
21251
+ {
21252
+ d: "M2.992 16.342a2 2 0 0 1 .094 1.167l-1.065 3.29a1 1 0 0 0 1.236 1.168l3.413-.998a2 2 0 0 1 1.099.092 10 10 0 1 0-4.777-4.719",
21253
+ key: "1sd12s"
21254
+ }
21255
+ ]
21256
+ ];
21257
+ var MessageCircle = createLucideIcon("message-circle", __iconNode6);
21258
+
21259
+ // ../../node_modules/lucide-react/dist/esm/icons/sparkles.js
21260
+ var __iconNode7 = [
21261
+ [
21262
+ "path",
21263
+ {
21264
+ d: "M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z",
21265
+ key: "1s2grr"
21266
+ }
21267
+ ],
21268
+ ["path", { d: "M20 2v4", key: "1rf3ol" }],
21269
+ ["path", { d: "M22 4h-4", key: "gwowj6" }],
21270
+ ["circle", { cx: "4", cy: "20", r: "2", key: "6kqj1y" }]
21271
+ ];
21272
+ var Sparkles = createLucideIcon("sparkles", __iconNode7);
21273
+
21274
+ // ../../node_modules/lucide-react/dist/esm/icons/trophy.js
21275
+ var __iconNode8 = [
21276
+ ["path", { d: "M10 14.66v1.626a2 2 0 0 1-.976 1.696A5 5 0 0 0 7 21.978", key: "1n3hpd" }],
21277
+ ["path", { d: "M14 14.66v1.626a2 2 0 0 0 .976 1.696A5 5 0 0 1 17 21.978", key: "rfe1zi" }],
21278
+ ["path", { d: "M18 9h1.5a1 1 0 0 0 0-5H18", key: "7xy6bh" }],
21279
+ ["path", { d: "M4 22h16", key: "57wxv0" }],
21280
+ ["path", { d: "M6 9a6 6 0 0 0 12 0V3a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1z", key: "1mhfuq" }],
21281
+ ["path", { d: "M6 9H4.5a1 1 0 0 1 0-5H6", key: "tex48p" }]
21282
+ ];
21283
+ var Trophy = createLucideIcon("trophy", __iconNode8);
21284
+
21285
+ // src/components/TileIcon.tsx
21018
21286
  var import_jsx_runtime10 = __toESM(require_jsx_runtime(), 1);
21287
+ var ICON_MAP = {
21288
+ "\u2753": CircleQuestionMark,
21289
+ "\u{1F9ED}": Compass,
21290
+ "\u{1F4DD}": FileText,
21291
+ "\u{1F3AF}": Layers,
21292
+ "\u{1F3C6}": Trophy,
21293
+ "\u2728": Sparkles,
21294
+ "\u{1F4AC}": MessageCircle,
21295
+ "\u{1F3AE}": Gamepad2
21296
+ };
21297
+ function TileIcon({
21298
+ emoji,
21299
+ size: size2 = 18,
21300
+ color = "currentColor"
21301
+ }) {
21302
+ const Icon2 = ICON_MAP[emoji];
21303
+ if (!Icon2) {
21304
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: emoji });
21305
+ }
21306
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Icon2, { size: size2, color });
21307
+ }
21308
+
21309
+ // src/components/TileCard.tsx
21310
+ var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
21019
21311
  function WidgetMount({ widgetId, props }) {
21020
21312
  const runtime7 = useRuntime();
21021
- const containerRef = (0, import_react11.useRef)(null);
21022
- const handleRef = (0, import_react11.useRef)(null);
21313
+ const containerRef = (0, import_react13.useRef)(null);
21314
+ const handleRef = (0, import_react13.useRef)(null);
21023
21315
  const registry = runtime7?.widgets;
21024
21316
  const widgetAvailable = registry?.has(widgetId) ?? false;
21025
- const [, forceUpdate] = (0, import_react11.useReducer)((x2) => x2 + 1, 0);
21026
- (0, import_react11.useEffect)(() => {
21317
+ const [, forceUpdate] = (0, import_react13.useReducer)((x2) => x2 + 1, 0);
21318
+ (0, import_react13.useEffect)(() => {
21027
21319
  if (!registry || widgetAvailable) return;
21028
21320
  return registry.subscribe((event) => {
21029
21321
  if (event.type === "registered" && event.widgetId === widgetId) {
@@ -21031,7 +21323,7 @@ ${cssRules}
21031
21323
  }
21032
21324
  });
21033
21325
  }, [registry, widgetId, widgetAvailable]);
21034
- (0, import_react11.useEffect)(() => {
21326
+ (0, import_react13.useEffect)(() => {
21035
21327
  if (!containerRef.current || !registry || !widgetAvailable) return;
21036
21328
  const handle = registry.mount(widgetId, containerRef.current, props);
21037
21329
  handleRef.current = handle;
@@ -21041,7 +21333,7 @@ ${cssRules}
21041
21333
  };
21042
21334
  }, [registry, widgetId, props, widgetAvailable]);
21043
21335
  if (!registry || !registry.has(widgetId)) {
21044
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
21336
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
21045
21337
  "div",
21046
21338
  {
21047
21339
  style: {
@@ -21057,7 +21349,7 @@ ${cssRules}
21057
21349
  }
21058
21350
  );
21059
21351
  }
21060
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { ref: containerRef, style: { width: "100%", minHeight: "40px" } });
21352
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { ref: containerRef, style: { width: "100%", minHeight: "40px" } });
21061
21353
  }
21062
21354
  function TileCard({
21063
21355
  config,
@@ -21065,15 +21357,27 @@ ${cssRules}
21065
21357
  telemetry: _telemetry,
21066
21358
  style
21067
21359
  }) {
21068
- const { title, widget, props } = config;
21069
- const [, setTick] = (0, import_react11.useState)(0);
21360
+ const { title, subtitle, widget, props, icon } = config;
21361
+ const [, setTick] = (0, import_react13.useState)(0);
21070
21362
  const runtime7 = useRuntime();
21071
- (0, import_react11.useEffect)(() => {
21363
+ (0, import_react13.useEffect)(() => {
21072
21364
  if (runtime7) setTick((t2) => t2 + 1);
21073
21365
  }, [runtime7]);
21074
- const [hovered, setHovered] = (0, import_react11.useState)(false);
21075
- const onMouseEnter = (0, import_react11.useCallback)(() => setHovered(true), []);
21076
- const onMouseLeave = (0, import_react11.useCallback)(() => setHovered(false), []);
21366
+ const registration = (0, import_react13.useMemo)(
21367
+ () => runtime7?.widgets?.getRegistration?.(widget),
21368
+ [runtime7?.widgets, widget]
21369
+ );
21370
+ const resolvedIcon = (0, import_react13.useMemo)(() => {
21371
+ if (icon) return icon;
21372
+ return registration?.metadata?.icon ?? "+";
21373
+ }, [icon, registration]);
21374
+ const resolvedSubtitle = (0, import_react13.useMemo)(() => {
21375
+ if (subtitle) return subtitle;
21376
+ return registration?.metadata?.subtitle;
21377
+ }, [subtitle, registration]);
21378
+ const [hovered, setHovered] = (0, import_react13.useState)(false);
21379
+ const onMouseEnter = (0, import_react13.useCallback)(() => setHovered(true), []);
21380
+ const onMouseLeave = (0, import_react13.useCallback)(() => setHovered(false), []);
21077
21381
  const cardStyle = {
21078
21382
  display: "flex",
21079
21383
  flexDirection: "column",
@@ -21094,23 +21398,17 @@ ${cssRules}
21094
21398
  const headerStyle = {
21095
21399
  display: "flex",
21096
21400
  alignItems: "center",
21097
- gap: "0.75rem",
21098
- padding: "0.875rem 1rem",
21099
- minHeight: "72px"
21401
+ gap: "var(--sc-tile-gap, 0.25rem)",
21402
+ padding: "var(--sc-tile-header-padding, 0.375rem 0.75rem)",
21403
+ minHeight: "44px"
21100
21404
  };
21101
21405
  const iconStyle = {
21102
- width: "40px",
21103
- height: "40px",
21104
- borderRadius: "10px",
21105
- background: "var(--sc-tile-icon-background)",
21106
21406
  display: "flex",
21107
21407
  alignItems: "center",
21108
21408
  justifyContent: "center",
21109
- fontSize: "1.25rem",
21110
- flexShrink: 0,
21111
- boxShadow: "var(--sc-tile-icon-shadow)"
21409
+ flexShrink: 0
21112
21410
  };
21113
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
21411
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
21114
21412
  "article",
21115
21413
  {
21116
21414
  "data-shadow-canvas-id": `tile-${config.id}`,
@@ -21118,32 +21416,49 @@ ${cssRules}
21118
21416
  onMouseEnter,
21119
21417
  onMouseLeave,
21120
21418
  children: [
21121
- /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { style: headerStyle, children: [
21122
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: iconStyle, children: "+" }),
21123
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
21124
- "h3",
21125
- {
21126
- style: {
21127
- fontSize: "0.95rem",
21128
- fontWeight: 600,
21129
- color: "var(--sc-tile-title-color)",
21130
- margin: "0.125rem 0 0",
21131
- whiteSpace: "nowrap",
21132
- overflow: "hidden",
21133
- textOverflow: "ellipsis"
21134
- },
21135
- children: title ?? widget
21136
- }
21137
- ) })
21419
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: headerStyle, children: [
21420
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: iconStyle, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(TileIcon, { emoji: resolvedIcon, size: resolvedSubtitle ? 36 : 24 }) }),
21421
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
21422
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21423
+ "h3",
21424
+ {
21425
+ style: {
21426
+ fontSize: "1.14rem",
21427
+ fontWeight: 600,
21428
+ color: "var(--sc-tile-title-color)",
21429
+ margin: "0.125rem 0 0",
21430
+ whiteSpace: "nowrap",
21431
+ overflow: "hidden",
21432
+ textOverflow: "ellipsis"
21433
+ },
21434
+ children: title ?? widget
21435
+ }
21436
+ ),
21437
+ resolvedSubtitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21438
+ "p",
21439
+ {
21440
+ style: {
21441
+ fontSize: "0.8rem",
21442
+ fontWeight: 400,
21443
+ color: "var(--sc-tile-text-color)",
21444
+ margin: "0.125rem 0 0",
21445
+ whiteSpace: "nowrap",
21446
+ overflow: "hidden",
21447
+ textOverflow: "ellipsis"
21448
+ },
21449
+ children: resolvedSubtitle
21450
+ }
21451
+ )
21452
+ ] })
21138
21453
  ] }),
21139
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
21454
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21140
21455
  "div",
21141
21456
  {
21142
21457
  style: {
21143
- padding: "0 1rem 1rem",
21458
+ padding: "var(--sc-tile-body-padding, 0 0.75rem 0.5rem)",
21144
21459
  borderTop: "1px solid rgba(255, 255, 255, 0.06)"
21145
21460
  },
21146
- 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 } }) })
21461
+ children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { paddingTop: "var(--sc-tile-gap, 0.25rem)" }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(WidgetMount, { widgetId: widget, props: { ...props, instanceId: config.id } }) })
21147
21462
  }
21148
21463
  )
21149
21464
  ]
@@ -21152,7 +21467,7 @@ ${cssRules}
21152
21467
  }
21153
21468
 
21154
21469
  // src/components/ShadowCanvasOverlay.tsx
21155
- var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
21470
+ var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
21156
21471
  var LAUNCHER_STYLES_ID = "syntro-launcher-styles";
21157
21472
  function ensureLauncherStyles(target, css) {
21158
21473
  if (target.querySelector(`#${LAUNCHER_STYLES_ID}`)) return;
@@ -21177,9 +21492,9 @@ ${cssRules}
21177
21492
  canvasTitle,
21178
21493
  displayMode = "standard"
21179
21494
  }) {
21180
- const [mounted, setMounted] = (0, import_react12.useState)(false);
21181
- const [launcherPos, setLauncherPos] = (0, import_react12.useState)(null);
21182
- const dragRef = (0, import_react12.useRef)(null);
21495
+ const [mounted, setMounted] = (0, import_react14.useState)(false);
21496
+ const [launcherPos, setLauncherPos] = (0, import_react14.useState)(null);
21497
+ const dragRef = (0, import_react14.useRef)(null);
21183
21498
  const runtime7 = useRuntime();
21184
21499
  const { shadowRoot, portalRoot } = useShadowRoot();
21185
21500
  const { config } = useTheme();
@@ -21188,7 +21503,7 @@ ${cssRules}
21188
21503
  tiles
21189
21504
  );
21190
21505
  useNotifyWatcher(runtime7, tiles, runtime7?.apps);
21191
- const handleNotificationClick = (0, import_react12.useCallback)(
21506
+ const handleNotificationClick = (0, import_react14.useCallback)(
21192
21507
  (notif) => {
21193
21508
  if (runtime7) {
21194
21509
  runtime7.events.publish(StandardEvents.NOTIFICATION_CLICKED, {
@@ -21210,7 +21525,7 @@ ${cssRules}
21210
21525
  },
21211
21526
  [runtime7, isOpen, onToggle, dismissNotification]
21212
21527
  );
21213
- const launcherCss = (0, import_react12.useMemo)(
21528
+ const launcherCss = (0, import_react14.useMemo)(
21214
21529
  () => `
21215
21530
  @keyframes syntro-launcher-pulse {
21216
21531
  0%, 100% {
@@ -21247,7 +21562,7 @@ ${cssRules}
21247
21562
  `,
21248
21563
  [config.colorPrimary, config.colorPrimaryHover]
21249
21564
  );
21250
- (0, import_react12.useEffect)(() => {
21565
+ (0, import_react14.useEffect)(() => {
21251
21566
  if (!isOpen) return;
21252
21567
  tiles.forEach((tile) => {
21253
21568
  telemetry?.trackRectangleViewed(tile.id, "overlay");
@@ -21257,11 +21572,11 @@ ${cssRules}
21257
21572
  }
21258
21573
  });
21259
21574
  }, [telemetry, runtime7, isOpen, tiles]);
21260
- (0, import_react12.useEffect)(() => {
21575
+ (0, import_react14.useEffect)(() => {
21261
21576
  setMounted(true);
21262
21577
  ensureLauncherStyles(shadowRoot, launcherCss);
21263
21578
  }, [shadowRoot, launcherCss]);
21264
- const toggle2 = (0, import_react12.useCallback)(() => {
21579
+ const toggle2 = (0, import_react14.useCallback)(() => {
21265
21580
  const next = !isOpen;
21266
21581
  if (next) {
21267
21582
  telemetry?.trackCanvasOpened("overlay");
@@ -21274,7 +21589,7 @@ ${cssRules}
21274
21589
  }
21275
21590
  onToggle();
21276
21591
  }, [isOpen, telemetry, runtime7, onToggle]);
21277
- const onLauncherPointerDown = (0, import_react12.useCallback)((e2) => {
21592
+ const onLauncherPointerDown = (0, import_react14.useCallback)((e2) => {
21278
21593
  const rect = e2.currentTarget.getBoundingClientRect();
21279
21594
  dragRef.current = {
21280
21595
  startX: e2.clientX,
@@ -21285,7 +21600,7 @@ ${cssRules}
21285
21600
  };
21286
21601
  e2.currentTarget.setPointerCapture(e2.pointerId);
21287
21602
  }, []);
21288
- const onLauncherPointerMove = (0, import_react12.useCallback)((e2) => {
21603
+ const onLauncherPointerMove = (0, import_react14.useCallback)((e2) => {
21289
21604
  const drag = dragRef.current;
21290
21605
  if (!drag) return;
21291
21606
  const dx = e2.clientX - drag.startX;
@@ -21297,7 +21612,7 @@ ${cssRules}
21297
21612
  setLauncherPos({ x: drag.startElX + dx, y: drag.startElY + dy });
21298
21613
  }
21299
21614
  }, []);
21300
- const onLauncherPointerUp = (0, import_react12.useCallback)(
21615
+ const onLauncherPointerUp = (0, import_react14.useCallback)(
21301
21616
  (_e2) => {
21302
21617
  const drag = dragRef.current;
21303
21618
  dragRef.current = null;
@@ -21310,14 +21625,17 @@ ${cssRules}
21310
21625
  const isFocused = displayMode === "focused";
21311
21626
  const isRight = config.canvas.position === "right";
21312
21627
  const isPush = config.canvas.layout === "push";
21313
- const containerRef = (0, import_react12.useRef)(null);
21628
+ const canvasBorder = config.canvas.border ?? "none";
21629
+ const containerRef = (0, import_react14.useRef)(null);
21314
21630
  const zIndex = 2147483600;
21315
- (0, import_react12.useEffect)(() => {
21631
+ (0, import_react14.useEffect)(() => {
21316
21632
  if (!isPush) return;
21317
21633
  const root = document.documentElement;
21318
21634
  const prop = isRight ? "marginRight" : "marginLeft";
21635
+ const duration = config.canvas.transitionDuration ?? "300ms";
21636
+ const easing = config.canvas.transitionEasing ?? "cubic-bezier(0.16, 1, 0.3, 1)";
21319
21637
  const prevTransition = root.style.transition;
21320
- root.style.transition = `${prop} 340ms cubic-bezier(0.16, 1, 0.3, 1)`;
21638
+ root.style.transition = `${prop} ${duration} ${easing}`;
21321
21639
  if (isOpen) {
21322
21640
  const width = containerRef.current?.offsetWidth ?? 380;
21323
21641
  root.style[prop] = `${width}px`;
@@ -21328,8 +21646,8 @@ ${cssRules}
21328
21646
  root.style[prop] = "";
21329
21647
  root.style.transition = prevTransition;
21330
21648
  };
21331
- }, [isPush, isOpen, isRight]);
21332
- (0, import_react12.useEffect)(() => {
21649
+ }, [isPush, isOpen, isRight, config.canvas.transitionDuration, config.canvas.transitionEasing]);
21650
+ (0, import_react14.useEffect)(() => {
21333
21651
  if (!isPush || !isOpen) return;
21334
21652
  const container = containerRef.current;
21335
21653
  if (!container) return;
@@ -21349,19 +21667,28 @@ ${cssRules}
21349
21667
  maxHeight: "100%",
21350
21668
  pointerEvents: "auto",
21351
21669
  opacity: isOpen ? 1 : 0,
21352
- transition: isOpen ? "transform 340ms cubic-bezier(0.16, 1, 0.3, 1), opacity 280ms ease-out" : "transform 280ms cubic-bezier(0.4, 0, 0.2, 1), opacity 200ms ease-in",
21670
+ transition: (() => {
21671
+ const dur = config.canvas.transitionDuration ?? "300ms";
21672
+ const ease = config.canvas.transitionEasing ?? "cubic-bezier(0.16, 1, 0.3, 1)";
21673
+ return isOpen ? `transform ${dur} ${ease}, opacity ${dur} ease-out` : `transform ${dur} ${ease}, opacity ${dur} ease-in`;
21674
+ })(),
21353
21675
  color: "var(--sc-overlay-text-color)",
21354
- // Standard mode: no tint, just blur with a tight fade mask at the leading edge
21355
- // Focused mode: full frosted glass
21356
- background: isFocused ? "var(--sc-canvas-background)" : "var(--sc-canvas-background, transparent)",
21357
- backdropFilter: isFocused ? `${config.canvas.blur ?? "blur(24px)"} saturate(1.2)` : "blur(6px)",
21358
- WebkitBackdropFilter: isFocused ? `${config.canvas.blur ?? "blur(24px)"} saturate(1.2)` : "blur(6px)",
21359
- // Tight fade mask so blur cuts off sharply at the leading edge
21360
- ...!isFocused ? {
21361
- maskImage: isRight ? "linear-gradient(to right, transparent, black 6%)" : "linear-gradient(to left, transparent, black 6%)",
21362
- WebkitMaskImage: isRight ? "linear-gradient(to right, transparent, black 6%)" : "linear-gradient(to left, transparent, black 6%)"
21363
- } : {},
21364
- border: "none",
21676
+ background: "var(--sc-canvas-background)",
21677
+ // Standard mode: config blur only. Focused mode: config blur + saturate boost.
21678
+ ...(() => {
21679
+ const blur = config.canvas.blur ?? "blur(24px)";
21680
+ const filter = isFocused && blur !== "none" ? `${blur} saturate(1.2)` : blur;
21681
+ return { backdropFilter: filter, WebkitBackdropFilter: filter };
21682
+ })(),
21683
+ // Tight fade mask so blur cuts off sharply at the leading edge.
21684
+ // Disabled when a visible border is configured (mask would fade the border).
21685
+ ...(() => {
21686
+ if (isFocused || canvasBorder && canvasBorder !== "none") return {};
21687
+ const fade = config.canvas.transitionFade ?? "6%";
21688
+ const mask = isRight ? `linear-gradient(to right, transparent, black ${fade})` : `linear-gradient(to left, transparent, black ${fade})`;
21689
+ return { maskImage: mask, WebkitMaskImage: mask };
21690
+ })(),
21691
+ border: canvasBorder,
21365
21692
  borderRadius: "var(--sc-overlay-border-radius, 0)",
21366
21693
  boxShadow: "none",
21367
21694
  // Transform logic
@@ -21376,7 +21703,7 @@ ${cssRules}
21376
21703
  pointerEvents: "none",
21377
21704
  padding: "0"
21378
21705
  };
21379
- const content = /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21706
+ const content = /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21380
21707
  "div",
21381
21708
  {
21382
21709
  "data-shadow-canvas-id": "overlay-root",
@@ -21386,9 +21713,9 @@ ${cssRules}
21386
21713
  pointerEvents: isOpen ? "auto" : "none",
21387
21714
  zIndex
21388
21715
  },
21389
- children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: wrapperStyle, children: [
21390
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { ref: containerRef, "data-shadow-canvas-id": "overlay-container", style: containerStyle, children: [
21391
- isFocused && canvasTitle && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("header", { style: { color: "white", padding: "1.5rem 1.5rem 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21716
+ children: /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: wrapperStyle, children: [
21717
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { ref: containerRef, "data-shadow-canvas-id": "overlay-container", style: containerStyle, children: [
21718
+ isFocused && canvasTitle && /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("header", { style: { color: "white", padding: "1.5rem 1.5rem 0" }, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21392
21719
  "p",
21393
21720
  {
21394
21721
  style: {
@@ -21401,13 +21728,13 @@ ${cssRules}
21401
21728
  children: canvasTitle
21402
21729
  }
21403
21730
  ) }),
21404
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { flex: 1, overflowY: "auto", padding: isFocused ? "0" : "1rem" }, children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21731
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { style: { flex: 1, overflowY: "auto", padding: isFocused ? "0" : "1rem" }, children: isLoading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21405
21732
  "div",
21406
21733
  {
21407
21734
  style: { color: "var(--sc-overlay-text-color)", padding: isFocused ? "1rem" : "0" },
21408
21735
  children: "Loading..."
21409
21736
  }
21410
- ) : error2 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
21737
+ ) : error2 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
21411
21738
  "div",
21412
21739
  {
21413
21740
  style: {
@@ -21421,7 +21748,7 @@ ${cssRules}
21421
21748
  }
21422
21749
  ) : isFocused ? (
21423
21750
  /* Focused Mode: Render first tile full size */
21424
- tiles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21751
+ tiles.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21425
21752
  TileCard,
21426
21753
  {
21427
21754
  config: tiles[0],
@@ -21432,7 +21759,7 @@ ${cssRules}
21432
21759
  ) : null
21433
21760
  ) : (
21434
21761
  /* Standard Mode: Stacked cards — widgets always visible */
21435
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21762
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21436
21763
  "div",
21437
21764
  {
21438
21765
  style: {
@@ -21441,7 +21768,7 @@ ${cssRules}
21441
21768
  gap: "0.75rem",
21442
21769
  width: "100%"
21443
21770
  },
21444
- children: tiles.map((tile) => /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21771
+ children: tiles.map((tile) => /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21445
21772
  TileCard,
21446
21773
  {
21447
21774
  config: tile,
@@ -21456,7 +21783,7 @@ ${cssRules}
21456
21783
  ) }),
21457
21784
  footerSlot
21458
21785
  ] }),
21459
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21786
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21460
21787
  "div",
21461
21788
  {
21462
21789
  onClick: toggle2,
@@ -21471,9 +21798,9 @@ ${cssRules}
21471
21798
  }
21472
21799
  );
21473
21800
  if (!mounted) return null;
21474
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(import_jsx_runtime11.Fragment, { children: [
21801
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(import_jsx_runtime12.Fragment, { children: [
21475
21802
  (0, import_react_dom.createPortal)(
21476
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
21803
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
21477
21804
  "div",
21478
21805
  {
21479
21806
  "data-shadow-canvas-id": "overlay-launcher",
@@ -21484,7 +21811,7 @@ ${cssRules}
21484
21811
  zIndex: zIndex + 47
21485
21812
  },
21486
21813
  children: [
21487
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21814
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21488
21815
  NotificationToastStack,
21489
21816
  {
21490
21817
  notifications,
@@ -21493,7 +21820,7 @@ ${cssRules}
21493
21820
  position: config.canvas.position ?? "right"
21494
21821
  }
21495
21822
  ),
21496
- /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
21823
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
21497
21824
  "button",
21498
21825
  {
21499
21826
  type: "button",
@@ -21537,7 +21864,7 @@ ${cssRules}
21537
21864
  }
21538
21865
  },
21539
21866
  children: [
21540
- isOpen ? /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
21867
+ isOpen ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
21541
21868
  "svg",
21542
21869
  {
21543
21870
  width: "24",
@@ -21552,11 +21879,11 @@ ${cssRules}
21552
21879
  focusable: "false",
21553
21880
  style: { transition: "transform 200ms ease" },
21554
21881
  children: [
21555
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M18 6L6 18" }),
21556
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M6 6l12 12" })
21882
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M18 6L6 18" }),
21883
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M6 6l12 12" })
21557
21884
  ]
21558
21885
  }
21559
- ) : launcherIcon ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21886
+ ) : launcherIcon ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21560
21887
  "img",
21561
21888
  {
21562
21889
  src: launcherIcon,
@@ -21569,7 +21896,7 @@ ${cssRules}
21569
21896
  pointerEvents: "none"
21570
21897
  }
21571
21898
  }
21572
- ) : /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
21899
+ ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
21573
21900
  "svg",
21574
21901
  {
21575
21902
  width: "24",
@@ -21584,16 +21911,16 @@ ${cssRules}
21584
21911
  focusable: "false",
21585
21912
  style: { transition: "transform 200ms ease" },
21586
21913
  children: [
21587
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("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" }),
21588
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M5 3v4" }),
21589
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M3 5h4" }),
21590
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M19 17v4" }),
21591
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("path", { d: "M17 19h4" })
21914
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("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" }),
21915
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M5 3v4" }),
21916
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M3 5h4" }),
21917
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M19 17v4" }),
21918
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("path", { d: "M17 19h4" })
21592
21919
  ]
21593
21920
  }
21594
21921
  ),
21595
- !isOpen && notifications.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { style: { position: "absolute", top: -2, right: -2, pointerEvents: "none" }, children: [
21596
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21922
+ !isOpen && notifications.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("div", { style: { position: "absolute", top: -2, right: -2, pointerEvents: "none" }, children: [
21923
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21597
21924
  "span",
21598
21925
  {
21599
21926
  className: "syntro-badge-ping",
@@ -21605,7 +21932,7 @@ ${cssRules}
21605
21932
  }
21606
21933
  }
21607
21934
  ),
21608
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21935
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21609
21936
  "span",
21610
21937
  {
21611
21938
  className: "syntro-badge-glow",
@@ -21616,7 +21943,7 @@ ${cssRules}
21616
21943
  }
21617
21944
  }
21618
21945
  ),
21619
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
21946
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
21620
21947
  "span",
21621
21948
  {
21622
21949
  className: "syntro-badge-bounce",
@@ -21645,12 +21972,12 @@ ${cssRules}
21645
21972
  ),
21646
21973
  portalRoot
21647
21974
  ),
21648
- isOpen ? (0, import_react_dom.createPortal)(content, portalRoot) : null
21975
+ (0, import_react_dom.createPortal)(content, portalRoot)
21649
21976
  ] });
21650
21977
  }
21651
21978
 
21652
21979
  // src/hooks/useShadowCanvasConfig.ts
21653
- var import_react13 = __toESM(require_react(), 1);
21980
+ var import_react15 = __toESM(require_react(), 1);
21654
21981
  var sortTiles = (tiles) => [...tiles].sort((a2, b2) => (b2.priority ?? 0) - (a2.priority ?? 0));
21655
21982
  function useShadowCanvasConfig({
21656
21983
  fetcher,
@@ -21659,17 +21986,29 @@ ${cssRules}
21659
21986
  pageUrl,
21660
21987
  pollIntervalMs
21661
21988
  }) {
21662
- const [state, setState] = (0, import_react13.useState)({
21989
+ const [state, setState] = (0, import_react15.useState)({
21663
21990
  tiles: [],
21664
21991
  actions: [],
21665
21992
  isLoading: true
21666
21993
  });
21667
- const prevActionsJsonRef = (0, import_react13.useRef)("[]");
21668
- const load = (0, import_react13.useCallback)(async () => {
21994
+ const prevActionsJsonRef = (0, import_react15.useRef)("[]");
21995
+ const rawConfigRef = (0, import_react15.useRef)(null);
21996
+ const refilter = (0, import_react15.useCallback)(async () => {
21997
+ const raw = rawConfigRef.current;
21998
+ if (!raw || !runtime7) return;
21999
+ let tiles = raw.tiles || [];
22000
+ tiles = await runtime7.filterTiles(tiles);
22001
+ if (experiments) {
22002
+ tiles = tiles.filter((tile) => experiments.shouldRenderRectangle(tile));
22003
+ }
22004
+ setState((prev) => ({ ...prev, tiles: sortTiles(tiles) }));
22005
+ }, [runtime7, experiments]);
22006
+ const load = (0, import_react15.useCallback)(async () => {
21669
22007
  try {
21670
22008
  setState((prev) => ({ ...prev, isLoading: true, error: void 0 }));
21671
22009
  const response = await fetcher();
21672
22010
  debug("SmartCanvas Config", "Raw config response", response);
22011
+ rawConfigRef.current = response;
21673
22012
  let tiles = response.tiles || [];
21674
22013
  if (runtime7) {
21675
22014
  tiles = await runtime7.filterTiles(tiles);
@@ -21706,24 +22045,36 @@ ${cssRules}
21706
22045
  }));
21707
22046
  }
21708
22047
  }, [experiments, fetcher, runtime7]);
21709
- (0, import_react13.useEffect)(() => {
22048
+ (0, import_react15.useEffect)(() => {
21710
22049
  load();
21711
22050
  if (experiments?.onFeaturesChanged) {
21712
22051
  return experiments.onFeaturesChanged(() => load());
21713
22052
  }
21714
22053
  }, [load, experiments, pageUrl]);
21715
- (0, import_react13.useEffect)(() => {
22054
+ (0, import_react15.useEffect)(() => {
22055
+ if (!runtime7?.accumulator) return;
22056
+ return runtime7.accumulator.subscribe(() => {
22057
+ refilter();
22058
+ });
22059
+ }, [runtime7, refilter]);
22060
+ (0, import_react15.useEffect)(() => {
22061
+ if (!runtime7?.context) return;
22062
+ return runtime7.context.subscribe(() => {
22063
+ refilter();
22064
+ });
22065
+ }, [runtime7, refilter]);
22066
+ (0, import_react15.useEffect)(() => {
21716
22067
  if (!pollIntervalMs) return;
21717
22068
  const id = setInterval(() => {
21718
22069
  load();
21719
22070
  }, pollIntervalMs);
21720
22071
  return () => clearInterval(id);
21721
22072
  }, [load, pollIntervalMs]);
21722
- return (0, import_react13.useMemo)(() => state, [state]);
22073
+ return (0, import_react15.useMemo)(() => state, [state]);
21723
22074
  }
21724
22075
 
21725
22076
  // src/SmartCanvasApp.tsx
21726
- var import_jsx_runtime12 = __toESM(require_jsx_runtime(), 1);
22077
+ var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
21727
22078
  function SmartCanvasApp({
21728
22079
  controller,
21729
22080
  fetcher,
@@ -21746,7 +22097,7 @@ ${cssRules}
21746
22097
  workspaceTheme
21747
22098
  }) {
21748
22099
  if (runtime7) {
21749
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(RuntimeProvider, { runtime: runtime7, children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
22100
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(RuntimeProvider, { runtime: runtime7, children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
21750
22101
  SmartCanvasAppInner,
21751
22102
  {
21752
22103
  controller,
@@ -21771,7 +22122,7 @@ ${cssRules}
21771
22122
  }
21772
22123
  ) });
21773
22124
  }
21774
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
22125
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
21775
22126
  SmartCanvasAppInner,
21776
22127
  {
21777
22128
  controller,
@@ -21816,13 +22167,13 @@ ${cssRules}
21816
22167
  initialBatchHandle,
21817
22168
  workspaceTheme
21818
22169
  }) {
21819
- const [open, setOpen] = (0, import_react14.useState)(controller.getState().open);
22170
+ const [open, setOpen] = (0, import_react16.useState)(controller.getState().open);
21820
22171
  const pageContext = usePageContext();
21821
- const [localUrl, setLocalUrl] = (0, import_react14.useState)(
22172
+ const [localUrl, setLocalUrl] = (0, import_react16.useState)(
21822
22173
  () => typeof window !== "undefined" ? window.location.href : "/"
21823
22174
  );
21824
22175
  const pageUrl = pageContext?.url ?? localUrl;
21825
- (0, import_react14.useEffect)(() => {
22176
+ (0, import_react16.useEffect)(() => {
21826
22177
  if (runtime7) return;
21827
22178
  if (typeof window === "undefined") return;
21828
22179
  const updateUrl = () => setLocalUrl(window.location.href);
@@ -21845,7 +22196,7 @@ ${cssRules}
21845
22196
  history.replaceState = originalReplaceState;
21846
22197
  };
21847
22198
  }, [runtime7]);
21848
- const derivedFetcher = (0, import_react14.useMemo)(() => {
22199
+ const derivedFetcher = (0, import_react16.useMemo)(() => {
21849
22200
  if (fetcher) return fetcher;
21850
22201
  return createCanvasConfigFetcher({
21851
22202
  configUri,
@@ -21862,15 +22213,16 @@ ${cssRules}
21862
22213
  pageUrl
21863
22214
  });
21864
22215
  const hasContent = configState.tiles.length > 0 && !configState.error;
21865
- (0, import_react14.useEffect)(() => controller.subscribe((state) => setOpen(state.open)), [controller]);
21866
- (0, import_react14.useEffect)(() => {
22216
+ (0, import_react16.useEffect)(() => controller.subscribe((state) => setOpen(state.open)), [controller]);
22217
+ (0, import_react16.useEffect)(() => {
21867
22218
  if (!configState.isLoading && !hasContent && controller.getState().open) {
21868
22219
  controller.setOpen(false);
21869
22220
  }
21870
22221
  }, [controller, hasContent, configState.isLoading]);
21871
- const batchHandleRef = (0, import_react14.useRef)(initialBatchHandle ?? null);
21872
- const adoptedInitialRef = (0, import_react14.useRef)(!!initialBatchHandle);
21873
- (0, import_react14.useEffect)(() => {
22222
+ const batchHandleRef = (0, import_react16.useRef)(initialBatchHandle ?? null);
22223
+ const adoptedInitialRef = (0, import_react16.useRef)(!!initialBatchHandle);
22224
+ const runVersionRef = (0, import_react16.useRef)(0);
22225
+ (0, import_react16.useEffect)(() => {
21874
22226
  if (!runtime7?.actions) return;
21875
22227
  if (adoptedInitialRef.current) {
21876
22228
  if (configState.actions.length > 0) {
@@ -21878,7 +22230,8 @@ ${cssRules}
21878
22230
  }
21879
22231
  return;
21880
22232
  }
21881
- let cancelled = false;
22233
+ const version = ++runVersionRef.current;
22234
+ const stale = () => version !== runVersionRef.current;
21882
22235
  const run = async () => {
21883
22236
  if (batchHandleRef.current) {
21884
22237
  try {
@@ -21888,17 +22241,17 @@ ${cssRules}
21888
22241
  }
21889
22242
  batchHandleRef.current = null;
21890
22243
  }
21891
- if (cancelled) return;
22244
+ if (stale()) return;
21892
22245
  if (configState.actions.length > 0) {
21893
22246
  try {
21894
22247
  const handle = await runtime7.actions.applyBatch(configState.actions);
21895
- if (cancelled) {
22248
+ if (stale()) {
21896
22249
  await handle.revertAll();
21897
22250
  } else {
21898
22251
  batchHandleRef.current = handle;
21899
22252
  }
21900
22253
  } catch (err) {
21901
- if (!cancelled) {
22254
+ if (!stale()) {
21902
22255
  console.error("[SmartCanvasApp] Failed to apply actions:", err);
21903
22256
  }
21904
22257
  }
@@ -21906,7 +22259,6 @@ ${cssRules}
21906
22259
  };
21907
22260
  run();
21908
22261
  return () => {
21909
- cancelled = true;
21910
22262
  if (batchHandleRef.current) {
21911
22263
  batchHandleRef.current.revertAll().catch((err) => {
21912
22264
  console.error("[SmartCanvasApp] Failed to revert actions on cleanup:", err);
@@ -21915,7 +22267,7 @@ ${cssRules}
21915
22267
  }
21916
22268
  };
21917
22269
  }, [runtime7, configState.actions, pageUrl]);
21918
- (0, import_react14.useEffect)(() => {
22270
+ (0, import_react16.useEffect)(() => {
21919
22271
  if (!runtime7) return;
21920
22272
  return runtime7.events.subscribe(
21921
22273
  { names: ["canvas.requestOpen"] },
@@ -21927,13 +22279,13 @@ ${cssRules}
21927
22279
  if (!configState.isLoading && !hasContent) {
21928
22280
  return null;
21929
22281
  }
21930
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
22282
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
21931
22283
  ThemeProvider,
21932
22284
  {
21933
22285
  themeConfig,
21934
22286
  workspaceTheme,
21935
22287
  shadowRoot,
21936
- children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
22288
+ children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
21937
22289
  ShadowCanvasOverlay,
21938
22290
  {
21939
22291
  tiles: configState.tiles,
@@ -21942,6 +22294,7 @@ ${cssRules}
21942
22294
  canvasTitle: configState.canvasTitle,
21943
22295
  telemetry,
21944
22296
  launcherLabel: launcherLabel ?? configState.launcher?.label,
22297
+ launcherIcon: configState.launcher?.icon,
21945
22298
  launcherAnimate: configState.launcher?.animate,
21946
22299
  launcherAnimationStyle: configState.launcher?.animationStyle,
21947
22300
  notificationCount: configState.launcher?.notificationCount ?? configState.tiles.length,
@@ -21956,7 +22309,7 @@ ${cssRules}
21956
22309
  }
21957
22310
 
21958
22311
  // src/SmartCanvasElement.tsx
21959
- var import_jsx_runtime13 = __toESM(require_jsx_runtime(), 1);
22312
+ var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
21960
22313
  var TAG_NAME = "smart-canvas";
21961
22314
  var BASE_CSS = `
21962
22315
  :host {
@@ -22056,13 +22409,13 @@ ${cssRules}
22056
22409
  __privateSet(this, _root, (0, import_client5.createRoot)(__privateGet(this, _mount)));
22057
22410
  }
22058
22411
  __privateGet(this, _root).render(
22059
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
22412
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
22060
22413
  ShadowRootProvider,
22061
22414
  {
22062
22415
  shadowRoot: __privateGet(this, _shadow),
22063
22416
  portalRoot: __privateGet(this, _portalRoot),
22064
22417
  overlayContainer: __privateGet(this, _overlayContainer),
22065
- children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(SmartCanvasApp, { ...__privateGet(this, _lastAppProps), controller: __privateGet(this, _controller), canvasHost: this })
22418
+ children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SmartCanvasApp, { ...__privateGet(this, _lastAppProps), controller: __privateGet(this, _controller), canvasHost: this })
22066
22419
  }
22067
22420
  )
22068
22421
  );
@@ -22288,32 +22641,32 @@ ${cssRules}
22288
22641
  }
22289
22642
 
22290
22643
  // src/components/TileWheel.tsx
22291
- var import_react15 = __toESM(require_react(), 1);
22292
- var import_jsx_runtime14 = __toESM(require_jsx_runtime(), 1);
22644
+ var import_react17 = __toESM(require_react(), 1);
22645
+ var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
22293
22646
  function TileWheel({ tiles, intervalMs = 7e3, telemetry }) {
22294
- const [index2, setIndex] = (0, import_react15.useState)(0);
22295
- const ordered = (0, import_react15.useMemo)(
22647
+ const [index2, setIndex] = (0, import_react17.useState)(0);
22648
+ const ordered = (0, import_react17.useMemo)(
22296
22649
  () => [...tiles].sort((a2, b2) => (a2.priority ?? 0) - (b2.priority ?? 0)),
22297
22650
  [tiles]
22298
22651
  );
22299
- (0, import_react15.useEffect)(() => {
22652
+ (0, import_react17.useEffect)(() => {
22300
22653
  telemetry?.trackCanvasOpened("wheel");
22301
22654
  }, [telemetry]);
22302
- (0, import_react15.useEffect)(() => {
22655
+ (0, import_react17.useEffect)(() => {
22303
22656
  if (ordered.length <= 1) return;
22304
22657
  const id = setInterval(() => {
22305
22658
  setIndex((prev) => (prev + 1) % ordered.length);
22306
22659
  }, intervalMs);
22307
22660
  return () => clearInterval(id);
22308
22661
  }, [ordered, intervalMs]);
22309
- (0, import_react15.useEffect)(() => {
22662
+ (0, import_react17.useEffect)(() => {
22310
22663
  const current = ordered[index2];
22311
22664
  if (current) {
22312
22665
  telemetry?.trackRectangleViewed(current.id, "wheel");
22313
22666
  }
22314
22667
  }, [index2, ordered, telemetry]);
22315
22668
  if (!ordered.length) return null;
22316
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
22669
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(
22317
22670
  "div",
22318
22671
  {
22319
22672
  style: {
@@ -22327,7 +22680,7 @@ ${cssRules}
22327
22680
  },
22328
22681
  "data-shadow-canvas-id": "wheel",
22329
22682
  children: [
22330
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
22683
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
22331
22684
  "div",
22332
22685
  {
22333
22686
  style: {
@@ -22336,10 +22689,10 @@ ${cssRules}
22336
22689
  transform: `translateX(-${index2 * 100}%)`,
22337
22690
  width: `${ordered.length * 100}%`
22338
22691
  },
22339
- children: ordered.map((tile) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { width: "100%", flexShrink: 0, padding: "0 1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(TileCard, { config: tile, surface: "wheel", telemetry }) }, tile.id))
22692
+ children: ordered.map((tile) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { width: "100%", flexShrink: 0, padding: "0 1rem" }, children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(TileCard, { config: tile, surface: "wheel", telemetry }) }, tile.id))
22340
22693
  }
22341
22694
  ),
22342
- /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("div", { style: { marginTop: "1rem", display: "flex", justifyContent: "center", gap: "0.5rem" }, children: ordered.map((tile, idx) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
22695
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { marginTop: "1rem", display: "flex", justifyContent: "center", gap: "0.5rem" }, children: ordered.map((tile, idx) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
22343
22696
  "button",
22344
22697
  {
22345
22698
  type: "button",
@@ -22436,18 +22789,7 @@ ${cssRules}
22436
22789
  if (config.tiles && Array.isArray(config.tiles)) {
22437
22790
  migrated.tiles = config.tiles.map((tile) => {
22438
22791
  const migratedTile = { ...tile };
22439
- if (tile.experiment && !tile.activation) {
22440
- const exp = tile.experiment;
22441
- if (exp.featureKey) {
22442
- migratedTile.activation = {
22443
- strategy: {
22444
- type: "external",
22445
- provider: "growthbook",
22446
- featureKey: exp.featureKey,
22447
- fallback: false
22448
- }
22449
- };
22450
- }
22792
+ if (tile.experiment) {
22451
22793
  delete migratedTile.experiment;
22452
22794
  }
22453
22795
  return migratedTile;
@@ -29543,11 +29885,11 @@ ${cssRules}
29543
29885
  };
29544
29886
 
29545
29887
  // src/SmartCanvasPortal.tsx
29546
- var import_react16 = __toESM(require_react(), 1);
29888
+ var import_react18 = __toESM(require_react(), 1);
29547
29889
  var import_react_dom2 = __toESM(require_react_dom(), 1);
29548
29890
  function SmartCanvasPortal({ element, children }) {
29549
- const [mountNode, setMountNode] = (0, import_react16.useState)(null);
29550
- (0, import_react16.useLayoutEffect)(() => {
29891
+ const [mountNode, setMountNode] = (0, import_react18.useState)(null);
29892
+ (0, import_react18.useLayoutEffect)(() => {
29551
29893
  if (!element) {
29552
29894
  setMountNode(null);
29553
29895
  return;
@@ -29732,7 +30074,7 @@ ${cssRules}
29732
30074
  }
29733
30075
  var W = [true, "true", 1, "1", "yes"];
29734
30076
  var G = (t2) => w(W, t2);
29735
- var V = [false, "false", 0, "0", "no"];
30077
+ var V2 = [false, "false", 0, "0", "no"];
29736
30078
  function J(t2, i2, e2, r2, s2) {
29737
30079
  return i2 > e2 && (r2.warn("min cannot be greater than max."), i2 = e2), L(t2) ? t2 > e2 ? (r2.warn(" cannot be greater than max: " + e2 + ". Using max value instead."), e2) : t2 < i2 ? (r2.warn(" cannot be less than min: " + i2 + ". Using min value instead."), i2) : t2 : (r2.warn(" must be a number. using max or fallback. max: " + e2 + ", fallback: " + s2), J(s2 || e2, i2, e2, r2));
29738
30080
  }
@@ -30958,7 +31300,7 @@ ${cssRules}
30958
31300
  }
30959
31301
  get K() {
30960
31302
  var t2 = this.Y.q(this.X);
30961
- return G(t2) ? Ne.GRANTED : w(V, t2) ? Ne.DENIED : Ne.PENDING;
31303
+ return G(t2) ? Ne.GRANTED : w(V2, t2) ? Ne.DENIED : Ne.PENDING;
30962
31304
  }
30963
31305
  get Y() {
30964
31306
  if (!this.Z) {
@@ -31800,8 +32142,8 @@ ${cssRules}
31800
32142
  }
31801
32143
  if (D2) {
31802
32144
  w2[P2++] = 268435456 | Os[A2] << 18 | As[D2];
31803
- var V2 = 31 & Os[A2], J2 = 31 & As[D2];
31804
- k2 += Ts[V2] + Rs[J2], ++x2[257 + V2], ++S2[J2], T2 = h2 + A2, ++E2;
32145
+ var V3 = 31 & Os[A2], J2 = 31 & As[D2];
32146
+ k2 += Ts[V3] + Rs[J2], ++x2[257 + V3], ++S2[J2], T2 = h2 + A2, ++E2;
31805
32147
  } else w2[P2++] = t3[h2], ++x2[t3[h2]];
31806
32148
  }
31807
32149
  }
@@ -35678,12 +36020,16 @@ ${cssRules}
35678
36020
 
35679
36021
  // src/decisions/schema.ts
35680
36022
  var RouteFilterZ = external_exports.object({
35681
- include: external_exports.array(external_exports.string()).optional(),
35682
- exclude: external_exports.array(external_exports.string()).optional()
36023
+ include: external_exports.array(external_exports.string()).optional().describe(
36024
+ "URL patterns where this tile appears. Supports *, **, :param wildcards. Use sparingly \u2014 mostly to isolate to specific webapp functionality. Omit to appear on all routes."
36025
+ ),
36026
+ exclude: external_exports.array(external_exports.string()).optional().describe("URL patterns where this tile should NOT appear. Evaluated before include.")
35683
36027
  });
35684
36028
  var ActivationConfigZ = external_exports.object({
35685
36029
  routes: RouteFilterZ,
35686
- strategy: DecisionStrategyZ.optional()
36030
+ onlyIfPopulated: external_exports.boolean().optional().describe(
36031
+ "When true, tile is hidden if none of its props.actions[] have an active triggerWhen. Useful for tiles with all-deferred FAQ questions or nav tips. Default: false."
36032
+ )
35687
36033
  });
35688
36034
  function validateCondition(data) {
35689
36035
  return ConditionZ.safeParse(data);
@@ -35738,7 +36084,10 @@ ${cssRules}
35738
36084
  background: external_exports.string().optional(),
35739
36085
  blur: external_exports.string().optional(),
35740
36086
  border: external_exports.string().optional(),
35741
- width: external_exports.string().optional()
36087
+ width: external_exports.string().optional(),
36088
+ transitionDuration: external_exports.string().optional(),
36089
+ transitionEasing: external_exports.string().optional(),
36090
+ transitionFade: external_exports.string().optional()
35742
36091
  });
35743
36092
  var LauncherElementConfigZ = external_exports.object({
35744
36093
  background: external_exports.string().optional(),
@@ -35846,7 +36195,7 @@ ${cssRules}
35846
36195
 
35847
36196
  // src/actions/schema.ts
35848
36197
  var ActionTriggerZ = {
35849
- triggerWhen: DecisionStrategyZ.nullable().optional()
36198
+ triggerWhen: TriggerWhenZ
35850
36199
  };
35851
36200
  var AnchorIdZ2 = external_exports.object({
35852
36201
  selector: external_exports.string(),
@@ -36481,7 +36830,7 @@ ${cssRules}
36481
36830
  switch (condition.type) {
36482
36831
  case "page_url": {
36483
36832
  const { url } = condition;
36484
- const currentUrl = context.page.url;
36833
+ const currentUrl = context.page.url.split("?")[0].split("#")[0];
36485
36834
  const pattern = url.replace(/\*\*/g, "\0GLOBSTAR\0").replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\0GLOBSTAR\0/g, ".*");
36486
36835
  const regex = new RegExp(`^${pattern}$`);
36487
36836
  return regex.test(currentUrl);
@@ -38158,7 +38507,7 @@ ${cssRules}
38158
38507
  function matchRoutePattern(pathname, pattern) {
38159
38508
  const normalizedPattern = pattern.replace(/\/$/, "") || "/";
38160
38509
  if (pathname === normalizedPattern) return true;
38161
- const regexPattern = normalizedPattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*").replace(/:[^/]+/g, "[^/]+");
38510
+ const regexPattern = normalizedPattern.replace(/\*\*/g, "\0GLOBSTAR\0").replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, "[^/]*").replace(/\0GLOBSTAR\0/g, ".*").replace(/:[^/]+/g, "[^/]+");
38162
38511
  const regex = new RegExp(`^${regexPattern}$`);
38163
38512
  return regex.test(pathname);
38164
38513
  }
@@ -38261,14 +38610,20 @@ ${cssRules}
38261
38610
  if (!matchesRouteFilter(currentUrl, activation.routes)) {
38262
38611
  continue;
38263
38612
  }
38264
- if (!activation.strategy) {
38265
- results.push(tile);
38266
- continue;
38267
- }
38268
- const result = await this.evaluate(activation.strategy);
38269
- if (result.value) {
38270
- results.push(tile);
38613
+ if (activation.onlyIfPopulated) {
38614
+ const actions2 = tile.props?.actions ?? [];
38615
+ if (actions2.length > 0) {
38616
+ const hasVisible = actions2.some((a2) => {
38617
+ if (!a2.triggerWhen) return true;
38618
+ return decisionEngine.evaluateSync(
38619
+ a2.triggerWhen,
38620
+ context.get()
38621
+ ).value;
38622
+ });
38623
+ if (!hasVisible) continue;
38624
+ }
38271
38625
  }
38626
+ results.push(tile);
38272
38627
  }
38273
38628
  return results;
38274
38629
  },
@@ -38945,7 +39300,7 @@ ${cssRules}
38945
39300
  }
38946
39301
 
38947
39302
  // src/index.ts
38948
- var RUNTIME_SDK_BUILD = true ? `${"2026-03-03T23:31:20.312Z"} (${"19510df2c8"})` : "dev";
39303
+ var RUNTIME_SDK_BUILD = true ? `${"2026-03-04T05:03:35.535Z"} (${"485144000d"})` : "dev";
38949
39304
  if (typeof window !== "undefined") {
38950
39305
  console.log(`[Syntro Runtime] Build: ${RUNTIME_SDK_BUILD}`);
38951
39306
  const existing = window.SynOS;
@@ -38954,7 +39309,7 @@ ${cssRules}
38954
39309
  ...existing,
38955
39310
  appRegistry: registry,
38956
39311
  _runtimeBuild: RUNTIME_SDK_BUILD,
38957
- React: import_react17.default,
39312
+ React: import_react19.default,
38958
39313
  ReactDOM: { ...ReactDOMClient, createPortal: import_react_dom3.createPortal, flushSync: import_react_dom3.flushSync }
38959
39314
  };
38960
39315
  registerBuiltinRuntimeModules(registry);
@@ -39017,6 +39372,30 @@ react/cjs/react-jsx-runtime.production.js:
39017
39372
  * This source code is licensed under the MIT license found in the
39018
39373
  * LICENSE file in the root directory of this source tree.
39019
39374
  *)
39375
+
39376
+ lucide-react/dist/esm/shared/src/utils/mergeClasses.js:
39377
+ lucide-react/dist/esm/shared/src/utils/toKebabCase.js:
39378
+ lucide-react/dist/esm/shared/src/utils/toCamelCase.js:
39379
+ lucide-react/dist/esm/shared/src/utils/toPascalCase.js:
39380
+ lucide-react/dist/esm/defaultAttributes.js:
39381
+ lucide-react/dist/esm/shared/src/utils/hasA11yProp.js:
39382
+ lucide-react/dist/esm/Icon.js:
39383
+ lucide-react/dist/esm/createLucideIcon.js:
39384
+ lucide-react/dist/esm/icons/circle-question-mark.js:
39385
+ lucide-react/dist/esm/icons/compass.js:
39386
+ lucide-react/dist/esm/icons/file-text.js:
39387
+ lucide-react/dist/esm/icons/gamepad-2.js:
39388
+ lucide-react/dist/esm/icons/layers.js:
39389
+ lucide-react/dist/esm/icons/message-circle.js:
39390
+ lucide-react/dist/esm/icons/sparkles.js:
39391
+ lucide-react/dist/esm/icons/trophy.js:
39392
+ lucide-react/dist/esm/lucide-react.js:
39393
+ (**
39394
+ * @license lucide-react v0.576.0 - ISC
39395
+ *
39396
+ * This source code is licensed under the ISC license.
39397
+ * See the LICENSE file in the root directory of this source tree.
39398
+ *)
39020
39399
  */
39021
39400
  window.Syntro=SyntrologieSDK.Syntro;
39022
39401
  //# sourceMappingURL=smart-canvas.js.map