@syntrologie/adapt-nav 2.8.0-canary.13 → 2.8.0-canary.131

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/NavWidget.d.ts +1 -1
  2. package/dist/NavWidget.d.ts.map +1 -1
  3. package/dist/NavWidget.js +14 -27
  4. package/dist/NavWidgetLit.d.ts +56 -0
  5. package/dist/NavWidgetLit.d.ts.map +1 -0
  6. package/dist/NavWidgetLit.js +495 -0
  7. package/dist/NavWidgetLit.test.d.ts +8 -0
  8. package/dist/NavWidgetLit.test.d.ts.map +1 -0
  9. package/dist/NavWidgetLit.test.js +199 -0
  10. package/dist/cdn.d.ts +1 -1
  11. package/dist/cdn.d.ts.map +1 -1
  12. package/dist/editor-lit.d.ts +49 -0
  13. package/dist/editor-lit.d.ts.map +1 -0
  14. package/dist/editor-lit.js +320 -0
  15. package/dist/editor.d.ts.map +1 -1
  16. package/dist/editor.js +3 -3
  17. package/dist/runtime-lit.d.ts +108 -0
  18. package/dist/runtime-lit.d.ts.map +1 -0
  19. package/dist/runtime-lit.js +241 -0
  20. package/dist/runtime.d.ts +26 -4
  21. package/dist/runtime.d.ts.map +1 -1
  22. package/dist/runtime.js +90 -3
  23. package/dist/schema.d.ts +210 -210
  24. package/dist/schema.d.ts.map +1 -1
  25. package/node_modules/@syntro/design-system/dist/tailwind-preset.d.ts.map +1 -1
  26. package/node_modules/@syntro/design-system/dist/tailwind-preset.js +4 -2
  27. package/node_modules/@syntro/design-system/dist/tokens/colors.css +1 -1
  28. package/node_modules/@syntro/design-system/dist/tokens/colors.d.ts +2 -2
  29. package/node_modules/@syntro/design-system/dist/tokens/colors.js +1 -1
  30. package/node_modules/@syntro/design-system/dist/tokens/effects.d.ts +54 -0
  31. package/node_modules/@syntro/design-system/dist/tokens/effects.d.ts.map +1 -1
  32. package/node_modules/@syntro/design-system/dist/tokens/effects.js +44 -0
  33. package/node_modules/@syntro/design-system/dist/tokens/index.d.ts +2 -0
  34. package/node_modules/@syntro/design-system/dist/tokens/index.d.ts.map +1 -1
  35. package/node_modules/@syntro/design-system/dist/tokens/index.js +2 -0
  36. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.d.ts +93 -0
  37. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.d.ts.map +1 -0
  38. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.js +72 -0
  39. package/node_modules/@syntro/design-system/package.json +2 -2
  40. package/node_modules/@syntrologie/sdk-contracts/dist/index.d.ts +1 -1
  41. package/node_modules/@syntrologie/sdk-contracts/dist/index.js +5 -3
  42. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.d.ts +150 -79
  43. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.js +266 -67
  44. package/node_modules/@syntrologie/sdk-contracts/package.json +2 -2
  45. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.d.ts.map +1 -1
  46. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.js +8 -7
  47. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.d.ts +84 -0
  48. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.d.ts.map +1 -0
  49. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.js +323 -0
  50. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.d.ts +25 -0
  51. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.d.ts.map +1 -0
  52. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.js +55 -0
  53. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.d.ts +33 -0
  54. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.d.ts.map +1 -0
  55. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.js +118 -0
  56. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.d.ts +32 -0
  57. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.d.ts.map +1 -0
  58. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.js +68 -0
  59. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.d.ts +34 -0
  60. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.d.ts.map +1 -0
  61. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.js +57 -0
  62. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.d.ts +13 -0
  63. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.d.ts.map +1 -0
  64. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.js +31 -0
  65. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.d.ts +7 -0
  66. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.d.ts.map +1 -0
  67. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.js +15 -0
  68. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.d.ts +36 -0
  69. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.d.ts.map +1 -0
  70. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.js +102 -0
  71. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.d.ts +20 -0
  72. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.d.ts.map +1 -0
  73. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.js +48 -0
  74. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.d.ts +16 -0
  75. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.d.ts.map +1 -0
  76. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.js +25 -0
  77. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.d.ts +66 -0
  78. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.d.ts.map +1 -0
  79. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.js +87 -0
  80. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.d.ts +7 -0
  81. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.d.ts.map +1 -0
  82. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.js +15 -0
  83. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts.map +1 -1
  84. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.js +28 -17
  85. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.d.ts +66 -0
  86. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.d.ts.map +1 -0
  87. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.js +528 -0
  88. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.d.ts +41 -0
  89. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.d.ts.map +1 -0
  90. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.js +63 -0
  91. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.d.ts +55 -0
  92. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.d.ts.map +1 -0
  93. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.js +92 -0
  94. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlight.js +2 -4
  95. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.d.ts +90 -0
  96. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.d.ts.map +1 -0
  97. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.js +242 -0
  98. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.d.ts +12 -0
  99. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.d.ts.map +1 -0
  100. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.js +21 -0
  101. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.d.ts +21 -0
  102. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.d.ts.map +1 -0
  103. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.js +33 -0
  104. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.d.ts +28 -0
  105. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.d.ts.map +1 -0
  106. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.js +121 -0
  107. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.d.ts +110 -0
  108. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.d.ts.map +1 -0
  109. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.js +481 -0
  110. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.d.ts.map +1 -1
  111. package/node_modules/@syntrologie/shared-editor-ui/dist/hooks/useTriggerWhenStatus.js +0 -1
  112. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts +2 -0
  113. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts.map +1 -1
  114. package/node_modules/@syntrologie/shared-editor-ui/dist/index.js +1 -0
  115. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.d.ts +15 -0
  116. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.d.ts.map +1 -0
  117. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.js +14 -0
  118. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts +0 -4
  119. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts.map +1 -1
  120. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.js +17 -1
  121. package/node_modules/@syntrologie/shared-editor-ui/package.json +19 -9
  122. package/package.json +20 -9
@@ -25,7 +25,7 @@ export declare const NavMountableWidget: {
25
25
  mount(container: HTMLElement, config?: NavConfig & {
26
26
  runtime?: NavWidgetRuntime;
27
27
  instanceId?: string;
28
- }): () => void;
28
+ }): (() => void) | undefined;
29
29
  };
30
30
  export default NavWidget;
31
31
  //# sourceMappingURL=NavWidget.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NavWidget.d.ts","sourceRoot":"","sources":["../src/NavWidget.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAOH,OAAO,KAAK,EAAE,SAAS,EAAgB,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AA+UzF;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,cAAc,2CA8NxE;AAMD;;GAEG;AACH,eAAO,MAAM,kBAAkB;qBAEhB,WAAW,WACb,SAAS,GAAG;QAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;CAiD3E,CAAC;AAEF,eAAe,SAAS,CAAC"}
1
+ {"version":3,"file":"NavWidget.d.ts","sourceRoot":"","sources":["../src/NavWidget.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAQH,OAAO,KAAK,EAAE,SAAS,EAAgB,cAAc,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAkVzF;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,UAAU,EAAE,EAAE,cAAc,2CA8NxE;AAMD;;GAEG;AACH,eAAO,MAAM,kBAAkB;qBAEhB,WAAW,WACb,SAAS,GAAG;QAAE,OAAO,CAAC,EAAE,gBAAgB,CAAC;QAAC,UAAU,CAAC,EAAE,MAAM,CAAA;KAAE;CA2B3E,CAAC;AAEF,eAAe,SAAS,CAAC"}
package/dist/NavWidget.js CHANGED
@@ -11,6 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  import { purple, slateGrey } from '@syntro/design-system/tokens';
12
12
  import React, { useCallback, useEffect, useMemo, useReducer, useState } from 'react';
13
13
  import { createRoot } from 'react-dom/client';
14
+ import { navigateWithFrameworkRouter } from './runtime';
14
15
  // ============================================================================
15
16
  // Emoji → Lucide SVG inline mapping (no lucide-react dependency)
16
17
  // ============================================================================
@@ -144,7 +145,8 @@ const themeStyles = {
144
145
  color: 'var(--sc-content-text-secondary-color)',
145
146
  },
146
147
  linkButton: {
147
- backgroundColor: 'var(--sc-color-primary, #6366f1)',
148
+ // purple[4] = #6a59ce — design system primary purple, used as fallback when --sc-color-primary is not set
149
+ backgroundColor: `var(--sc-color-primary, ${purple[4]})`,
148
150
  color: '#ffffff',
149
151
  },
150
152
  categoryHeader: {
@@ -177,7 +179,8 @@ const themeStyles = {
177
179
  color: 'var(--sc-content-text-secondary-color)',
178
180
  },
179
181
  linkButton: {
180
- backgroundColor: 'var(--sc-color-primary, #6366f1)',
182
+ // purple[4] = #6a59ce — design system primary purple, used as fallback when --sc-color-primary is not set
183
+ backgroundColor: `var(--sc-color-primary, ${purple[4]})`,
181
184
  color: '#ffffff',
182
185
  },
183
186
  categoryHeader: {
@@ -266,7 +269,9 @@ function NavTipItem({ item, isExpanded, isLast, onToggle, onNavigate, onFocusAnc
266
269
  };
267
270
  // CTA label
268
271
  const ctaLabel = isFocusAction ? `Focus \u2192` : external ? `Go \u2197` : `Go \u2192`;
269
- return (_jsxs("div", { style: itemStyle, "data-nav-tip-id": item.config.id, children: [_jsxs("button", { type: "button", style: headerStyle, onClick: onToggle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "aria-expanded": isExpanded, children: [icon && (_jsx("span", { style: baseStyles.icon, dangerouslySetInnerHTML: { __html: renderIcon(icon) } })), _jsx("span", { children: title }), _jsx("span", { style: chevronStyle, children: '\u203A' })] }), _jsxs("div", { style: bodyStyle, "aria-hidden": !isExpanded, children: [_jsx("p", { style: baseStyles.description, children: description }), hasAction && (_jsx("a", { href: effectiveHref || '#', onClick: handleLinkClick, style: { ...baseStyles.linkButton, ...colors.linkButton }, target: external ? '_blank' : undefined, rel: external ? 'noopener noreferrer' : undefined, children: ctaLabel }))] })] }));
272
+ return (_jsxs("div", { style: itemStyle, "data-nav-tip-id": item.config.id, children: [_jsxs("button", { type: "button", style: headerStyle, onClick: onToggle, onMouseEnter: () => setIsHovered(true), onMouseLeave: () => setIsHovered(false), "aria-expanded": isExpanded, children: [icon && (
273
+ // biome-ignore lint/security/noDangerouslySetInnerHtml: renderIcon returns sanitized SVG from EMOJI_SVG_MAP or escapeHtml
274
+ _jsx("span", { style: baseStyles.icon, dangerouslySetInnerHTML: { __html: renderIcon(icon) } })), _jsx("span", { children: title }), _jsx("span", { style: chevronStyle, children: '\u203A' })] }), _jsxs("div", { style: bodyStyle, "aria-hidden": !isExpanded, children: [_jsx("p", { style: baseStyles.description, children: description }), hasAction && (_jsx("a", { href: effectiveHref || '#', onClick: handleLinkClick, style: { ...baseStyles.linkButton, ...colors.linkButton }, target: external ? '_blank' : undefined, rel: external ? 'noopener noreferrer' : undefined, children: ctaLabel }))] })] }));
270
275
  }
271
276
  // ============================================================================
272
277
  // NavWidget Component
@@ -392,14 +397,14 @@ export function NavWidget({ config, runtime, instanceId }) {
392
397
  window.open(href, '_blank', 'noopener,noreferrer');
393
398
  }
394
399
  else {
395
- // SPA navigation: pushState updates the URL, then popstate tells the
396
- // host app's router (e.g. React Router) to render the new page.
397
- // Cleanup functions in revertAll() are resilient to detached DOM nodes,
398
- // so no timing hack is needed between pushState and popstate.
400
+ // Try the host framework's native router first (Next.js, Nuxt, etc.)
401
+ // Falls back to pushState for vanilla SPAs.
399
402
  const url = new URL(href, window.location.origin);
400
403
  url.search = window.location.search;
401
- window.history.pushState(null, '', url.toString());
402
- window.dispatchEvent(new PopStateEvent('popstate'));
404
+ if (!navigateWithFrameworkRouter(url.toString())) {
405
+ window.history.pushState(null, '', url.toString());
406
+ window.dispatchEvent(new PopStateEvent('popstate'));
407
+ }
403
408
  }
404
409
  }, [runtime.events, instanceId]);
405
410
  // Handle same-page anchor focus: scroll + pulse + focus
@@ -466,24 +471,6 @@ export const NavMountableWidget = {
466
471
  root.unmount();
467
472
  };
468
473
  }
469
- // HTML fallback for non-React environments
470
- const tips = navConfig.actions || [];
471
- container.innerHTML = `
472
- <div style="font-family: system-ui; max-width: 100%;">
473
- ${tips
474
- .map((tip) => `
475
- <div style="margin-bottom: 4px; padding: 12px 16px; background: ${slateGrey[12]}; border-radius: 8px;">
476
- ${tip.config.icon ? `<span>${renderIcon(tip.config.icon)}</span> ` : ''}<strong>${escapeHtml(tip.config.title)}</strong>
477
- <p style="margin-top: 8px; color: ${slateGrey[6]}; font-size: 13px;">${escapeHtml(tip.config.description)}</p>
478
- ${tip.config.href ? `<a href="${escapeHtml(tip.config.href)}" style="color: ${purple[2]}; font-size: 13px;">Go &rarr;</a>` : ''}
479
- </div>
480
- `)
481
- .join('')}
482
- </div>
483
- `;
484
- return () => {
485
- container.innerHTML = '';
486
- };
487
474
  },
488
475
  };
489
476
  export default NavWidget;
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Adaptive Nav - NavWidgetLit Web Component
3
+ *
4
+ * Lit web component equivalent of NavWidget.tsx. Renders a collapsible
5
+ * navigation tips accordion with per-item conditional visibility, framework-aware
6
+ * navigation, and CSS variable theming.
7
+ *
8
+ * Decorator-free: uses `static override properties` (tsconfig has no
9
+ * experimentalDecorators).
10
+ *
11
+ * Uses light DOM (createRenderRoot returns this) so host-page CSS variables
12
+ * (--sc-*) are inherited without crossing a shadow boundary.
13
+ */
14
+ import { LitElement } from 'lit';
15
+ import type { NavConfig, NavWidgetRuntime } from './types';
16
+ export declare class NavWidgetLit extends LitElement {
17
+ #private;
18
+ createRenderRoot(): this;
19
+ static properties: {
20
+ config: {
21
+ attribute: boolean;
22
+ };
23
+ runtime: {
24
+ attribute: boolean;
25
+ };
26
+ instanceId: {
27
+ type: StringConstructor;
28
+ };
29
+ _expandedIds: {
30
+ state: boolean;
31
+ };
32
+ _renderTick: {
33
+ state: boolean;
34
+ };
35
+ _hoveredId: {
36
+ state: boolean;
37
+ };
38
+ };
39
+ config: NavConfig;
40
+ runtime: NavWidgetRuntime | undefined;
41
+ instanceId: string;
42
+ /** @internal */ _expandedIds: Set<string>;
43
+ /** @internal */ _renderTick: number;
44
+ /** @internal */ _hoveredId: string | null;
45
+ connectedCallback(): void;
46
+ disconnectedCallback(): void;
47
+ updated(changed: Map<string, unknown>): void;
48
+ render(): import("lit-html").TemplateResult<1>;
49
+ }
50
+ export declare function registerNavWidgetLit(): void;
51
+ declare global {
52
+ interface HTMLElementTagNameMap {
53
+ 'syntro-nav-tips': NavWidgetLit;
54
+ }
55
+ }
56
+ //# sourceMappingURL=NavWidgetLit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NavWidgetLit.d.ts","sourceRoot":"","sources":["../src/NavWidgetLit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAQ,UAAU,EAAW,MAAM,KAAK,CAAC;AAKhD,OAAO,KAAK,EAAE,SAAS,EAAgB,gBAAgB,EAAE,MAAM,SAAS,CAAC;AAqGzE,qBAAa,YAAa,SAAQ,UAAU;;IAGjC,gBAAgB;IAMzB,OAAgB,UAAU;;;;;;;;;;;;;;;;;;;MAUxB;IAIF,MAAM,EAAE,SAAS,CAA4D;IAC7E,OAAO,EAAE,gBAAgB,GAAG,SAAS,CAAa;IAClD,UAAU,EAAE,MAAM,CAAgB;IAIlC,gBAAgB,CAAC,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAa;IACvD,gBAAgB,CAAC,WAAW,SAAK;IACjC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAQ;IASzC,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAO5B,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IA0T5C,MAAM;CAuFhB;AAQD,wBAAgB,oBAAoB,IAAI,IAAI,CAK3C;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,YAAY,CAAC;KACjC;CACF"}
@@ -0,0 +1,495 @@
1
+ /**
2
+ * Adaptive Nav - NavWidgetLit Web Component
3
+ *
4
+ * Lit web component equivalent of NavWidget.tsx. Renders a collapsible
5
+ * navigation tips accordion with per-item conditional visibility, framework-aware
6
+ * navigation, and CSS variable theming.
7
+ *
8
+ * Decorator-free: uses `static override properties` (tsconfig has no
9
+ * experimentalDecorators).
10
+ *
11
+ * Uses light DOM (createRenderRoot returns this) so host-page CSS variables
12
+ * (--sc-*) are inherited without crossing a shadow boundary.
13
+ */
14
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
15
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
16
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
17
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
18
+ };
19
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
20
+ if (kind === "m") throw new TypeError("Private method is not writable");
21
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
22
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
23
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
24
+ };
25
+ var _NavWidgetLit_instances, _NavWidgetLit_contextUnsub, _NavWidgetLit_accumulatorUnsub, _NavWidgetLit_subscribeRuntime, _NavWidgetLit_unsubscribeRuntime, _NavWidgetLit_getVisibleTips, _NavWidgetLit_getResolvedTheme, _NavWidgetLit_handleToggle, _NavWidgetLit_handleNavigate, _NavWidgetLit_handleFocusAnchor, _NavWidgetLit_publishEvent, _NavWidgetLit_renderTipItem;
26
+ import { html, LitElement, nothing } from 'lit';
27
+ import { styleMap } from 'lit/directives/style-map.js';
28
+ import { unsafeHTML } from 'lit/directives/unsafe-html.js';
29
+ import { navigateWithFrameworkRouter } from './runtime';
30
+ // ============================================================================
31
+ // Design system token fallbacks (inlined to avoid bundling @syntro/design-system
32
+ // as a hard dep for this file; values match packages/design-system/src/tokens/colors.ts)
33
+ // ============================================================================
34
+ const TOKEN_PURPLE_4 = '#6a59ce';
35
+ const TOKEN_SLATE_GREY_7 = '#677384';
36
+ const TOKEN_SLATE_GREY_8 = '#87919f';
37
+ // ============================================================================
38
+ // Emoji → Lucide SVG inline mapping (matches NavWidget.tsx EMOJI_SVG_MAP)
39
+ // ============================================================================
40
+ const EMOJI_SVG_MAP = {
41
+ '💵': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="12" x="2" y="6" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12h.01M18 12h.01"/></svg>',
42
+ '🏛️': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="3" x2="21" y1="22" y2="22"/><line x1="6" x2="6" y1="18" y2="11"/><line x1="10" x2="10" y1="18" y2="11"/><line x1="14" x2="14" y1="18" y2="11"/><line x1="18" x2="18" y1="18" y2="11"/><polygon points="12 2 20 7 4 7"/></svg>',
43
+ '⏭️': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="5 4 15 12 5 20 5 4"/><line x1="19" x2="19" y1="5" y2="19"/></svg>',
44
+ '➡️': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="m12 5 7 7-7 7"/></svg>',
45
+ '💡': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5"/><path d="M9 18h6"/><path d="M10 22h4"/></svg>',
46
+ '💰': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="20" height="12" x="2" y="6" rx="2"/><circle cx="12" cy="12" r="2"/><path d="M6 12h.01M18 12h.01"/></svg>',
47
+ '📋': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect width="8" height="4" x="8" y="2" rx="1" ry="1"/><path d="M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2"/><path d="M12 11h4"/><path d="M12 16h4"/><path d="M8 11h.01"/><path d="M8 16h.01"/></svg>',
48
+ '✅': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><path d="m9 11 3 3L22 4"/></svg>',
49
+ '⚠️': '<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/></svg>',
50
+ };
51
+ // ============================================================================
52
+ // Sanitization helpers
53
+ // ============================================================================
54
+ function escapeHtml(str) {
55
+ return str
56
+ .replace(/&/g, '&amp;')
57
+ .replace(/</g, '&lt;')
58
+ .replace(/>/g, '&gt;')
59
+ .replace(/"/g, '&quot;')
60
+ .replace(/'/g, '&#39;');
61
+ }
62
+ function renderIcon(emoji) {
63
+ return EMOJI_SVG_MAP[emoji] ?? escapeHtml(emoji);
64
+ }
65
+ // ============================================================================
66
+ // Route matching helper
67
+ // ============================================================================
68
+ function routeMatchesCurrent(routes) {
69
+ if (typeof window === 'undefined')
70
+ return false;
71
+ const current = window.location.pathname;
72
+ return routes.some((route) => {
73
+ const routePath = route.split('?')[0].split('#')[0];
74
+ if (routePath.endsWith('/**')) {
75
+ return current.startsWith(routePath.slice(0, -3));
76
+ }
77
+ return current === routePath;
78
+ });
79
+ }
80
+ // ============================================================================
81
+ // Pulse animation helper
82
+ // ============================================================================
83
+ function pulseElement(el) {
84
+ const keyframes = [
85
+ { boxShadow: '0 0 0 0 rgba(13, 148, 136, 0.5)' },
86
+ { boxShadow: '0 0 0 8px rgba(13, 148, 136, 0)' },
87
+ ];
88
+ el.animate(keyframes, { duration: 600, iterations: 3, easing: 'ease-out' });
89
+ }
90
+ function resolveTheme(theme) {
91
+ if (theme === 'dark')
92
+ return 'dark';
93
+ if (theme === 'light')
94
+ return 'light';
95
+ // auto or undefined: detect system preference
96
+ if (typeof window !== 'undefined') {
97
+ return window.matchMedia?.('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
98
+ }
99
+ return 'light';
100
+ }
101
+ // ============================================================================
102
+ // NavWidgetLit — LitElement
103
+ // ============================================================================
104
+ export class NavWidgetLit extends LitElement {
105
+ constructor() {
106
+ // ---------- No shadow DOM — inherit host CSS variables --------------------
107
+ super(...arguments);
108
+ _NavWidgetLit_instances.add(this);
109
+ // ---------- Public properties --------------------------------------------
110
+ this.config = { expandBehavior: 'single', theme: 'auto', actions: [] };
111
+ this.runtime = undefined;
112
+ this.instanceId = 'nav-widget';
113
+ // ---------- Internal state -----------------------------------------------
114
+ /** @internal */ this._expandedIds = new Set();
115
+ /** @internal */ this._renderTick = 0;
116
+ /** @internal */ this._hoveredId = null;
117
+ // ---------- Private subscriptions ----------------------------------------
118
+ _NavWidgetLit_contextUnsub.set(this, null);
119
+ _NavWidgetLit_accumulatorUnsub.set(this, null);
120
+ }
121
+ createRenderRoot() {
122
+ return this;
123
+ }
124
+ // ---------- Lifecycle: connectedCallback ---------------------------------
125
+ connectedCallback() {
126
+ super.connectedCallback();
127
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_subscribeRuntime).call(this);
128
+ }
129
+ // ---------- Lifecycle: disconnectedCallback ------------------------------
130
+ disconnectedCallback() {
131
+ super.disconnectedCallback();
132
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_unsubscribeRuntime).call(this);
133
+ }
134
+ // ---------- Lifecycle: updated -------------------------------------------
135
+ updated(changed) {
136
+ if (changed.has('runtime')) {
137
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_unsubscribeRuntime).call(this);
138
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_subscribeRuntime).call(this);
139
+ }
140
+ }
141
+ // ---------- Render --------------------------------------------------------
142
+ render() {
143
+ const visibleTips = __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_getVisibleTips).call(this);
144
+ const theme = __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_getResolvedTheme).call(this);
145
+ const containerStyle = styleMap({
146
+ fontFamily: 'var(--sc-font-family, system-ui, -apple-system, sans-serif)',
147
+ maxWidth: '100%',
148
+ overflow: 'hidden',
149
+ backgroundColor: 'transparent',
150
+ color: 'inherit',
151
+ });
152
+ const accordionStyle = styleMap({
153
+ display: 'flex',
154
+ flexDirection: 'column',
155
+ gap: 'var(--sc-content-item-gap, 6px)',
156
+ });
157
+ const categoryHeaderStyle = styleMap({
158
+ fontSize: 'var(--sc-content-category-font-size, 12px)',
159
+ fontWeight: '600',
160
+ textTransform: 'uppercase',
161
+ letterSpacing: '0.05em',
162
+ padding: 'var(--sc-content-category-padding, 8px 4px 4px 4px)',
163
+ color: theme === 'dark' ? TOKEN_SLATE_GREY_8 : TOKEN_SLATE_GREY_7,
164
+ });
165
+ const emptyStateStyle = styleMap({
166
+ fontSize: '13px',
167
+ padding: '16px',
168
+ textAlign: 'center',
169
+ color: theme === 'dark' ? TOKEN_SLATE_GREY_7 : TOKEN_SLATE_GREY_8,
170
+ });
171
+ // Empty state
172
+ if (visibleTips.length === 0) {
173
+ return html `
174
+ <div
175
+ style=${containerStyle}
176
+ data-adaptive-id=${this.instanceId}
177
+ data-adaptive-type="adaptive-nav"
178
+ >
179
+ <div style=${emptyStateStyle}>
180
+ You're all set for now! We'll share helpful tips here when they're relevant to what
181
+ you're doing.
182
+ </div>
183
+ </div>
184
+ `;
185
+ }
186
+ // Group by category
187
+ const categoryGroups = new Map();
188
+ for (const tip of visibleTips) {
189
+ const cat = tip.config.category;
190
+ if (!categoryGroups.has(cat)) {
191
+ categoryGroups.set(cat, []);
192
+ }
193
+ categoryGroups.get(cat).push(tip);
194
+ }
195
+ const hasCategories = visibleTips.some((t) => t.config.category);
196
+ return html `
197
+ <div
198
+ style=${containerStyle}
199
+ data-adaptive-id=${this.instanceId}
200
+ data-adaptive-type="adaptive-nav"
201
+ >
202
+ <div style=${accordionStyle}>
203
+ ${hasCategories
204
+ ? Array.from(categoryGroups.entries()).map(([category, items]) => html `
205
+ ${category
206
+ ? html `<div style=${categoryHeaderStyle} data-category-header=${category}>${category}</div>`
207
+ : nothing}
208
+ ${items.map((tip, idx) => __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_renderTipItem).call(this, tip, idx, items.length))}
209
+ `)
210
+ : visibleTips.map((tip, idx) => __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_renderTipItem).call(this, tip, idx, visibleTips.length))}
211
+ </div>
212
+ </div>
213
+ `;
214
+ }
215
+ }
216
+ _NavWidgetLit_contextUnsub = new WeakMap(), _NavWidgetLit_accumulatorUnsub = new WeakMap(), _NavWidgetLit_instances = new WeakSet(), _NavWidgetLit_subscribeRuntime = function _NavWidgetLit_subscribeRuntime() {
217
+ if (!this.runtime)
218
+ return;
219
+ __classPrivateFieldSet(this, _NavWidgetLit_contextUnsub, this.runtime.context.subscribe(() => {
220
+ this._renderTick += 1;
221
+ }), "f");
222
+ if (this.runtime.accumulator?.subscribe) {
223
+ __classPrivateFieldSet(this, _NavWidgetLit_accumulatorUnsub, this.runtime.accumulator.subscribe(() => {
224
+ this._renderTick += 1;
225
+ }), "f");
226
+ }
227
+ }, _NavWidgetLit_unsubscribeRuntime = function _NavWidgetLit_unsubscribeRuntime() {
228
+ __classPrivateFieldGet(this, _NavWidgetLit_contextUnsub, "f")?.call(this);
229
+ __classPrivateFieldSet(this, _NavWidgetLit_contextUnsub, null, "f");
230
+ __classPrivateFieldGet(this, _NavWidgetLit_accumulatorUnsub, "f")?.call(this);
231
+ __classPrivateFieldSet(this, _NavWidgetLit_accumulatorUnsub, null, "f");
232
+ }, _NavWidgetLit_getVisibleTips = function _NavWidgetLit_getVisibleTips() {
233
+ // _renderTick is read here to ensure this re-runs when context/accumulator
234
+ // notify (same pattern as useMemo with renderTick dep in React version).
235
+ void this._renderTick;
236
+ if (!this.runtime)
237
+ return this.config.actions;
238
+ return this.config.actions.filter((tip) => {
239
+ if (!tip.triggerWhen)
240
+ return true;
241
+ try {
242
+ const result = this.runtime.evaluateSync(tip.triggerWhen);
243
+ return result.value;
244
+ }
245
+ catch {
246
+ // Fail-closed: hide tip when strategy evaluation throws
247
+ return false;
248
+ }
249
+ });
250
+ }, _NavWidgetLit_getResolvedTheme = function _NavWidgetLit_getResolvedTheme() {
251
+ return resolveTheme(this.config.theme);
252
+ }, _NavWidgetLit_handleToggle = function _NavWidgetLit_handleToggle(id) {
253
+ const wasExpanded = this._expandedIds.has(id);
254
+ let next;
255
+ if (this.config.expandBehavior === 'single') {
256
+ // Emit collapse events for previously-expanded tips (single mode)
257
+ for (const prevId of this._expandedIds) {
258
+ if (prevId !== id) {
259
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_publishEvent).call(this, 'nav:toggled', {
260
+ tipId: prevId,
261
+ expanded: false,
262
+ });
263
+ }
264
+ }
265
+ next = wasExpanded ? new Set() : new Set([id]);
266
+ }
267
+ else {
268
+ next = new Set(this._expandedIds);
269
+ if (wasExpanded) {
270
+ next.delete(id);
271
+ }
272
+ else {
273
+ next.add(id);
274
+ }
275
+ }
276
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_publishEvent).call(this, 'nav:toggled', {
277
+ tipId: id,
278
+ expanded: !wasExpanded,
279
+ });
280
+ this._expandedIds = next;
281
+ }, _NavWidgetLit_handleNavigate = function _NavWidgetLit_handleNavigate(href, external) {
282
+ // Reject dangerous URIs
283
+ const normalized = href.trim().toLowerCase();
284
+ if (normalized.startsWith('javascript:') || normalized.startsWith('data:'))
285
+ return;
286
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_publishEvent).call(this, 'nav:tip_clicked', { href, external });
287
+ // Also fire a standard custom event for host-page listeners
288
+ this.dispatchEvent(new CustomEvent('nav-tip-clicked', {
289
+ bubbles: true,
290
+ detail: { href, external, instanceId: this.instanceId },
291
+ }));
292
+ if (external) {
293
+ window.open(href, '_blank', 'noopener,noreferrer');
294
+ }
295
+ else {
296
+ const url = new URL(href, window.location.origin);
297
+ url.search = window.location.search;
298
+ if (!navigateWithFrameworkRouter(url.toString())) {
299
+ window.history.pushState(null, '', url.toString());
300
+ window.dispatchEvent(new PopStateEvent('popstate'));
301
+ }
302
+ }
303
+ }, _NavWidgetLit_handleFocusAnchor = function _NavWidgetLit_handleFocusAnchor(anchor) {
304
+ const el = document.querySelector(anchor.selector);
305
+ if (!(el instanceof HTMLElement))
306
+ return;
307
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_publishEvent).call(this, 'nav:tip_focused', {
308
+ selector: anchor.selector,
309
+ route: anchor.route,
310
+ });
311
+ this.dispatchEvent(new CustomEvent('nav-tip-focused', {
312
+ bubbles: true,
313
+ detail: { selector: anchor.selector, instanceId: this.instanceId },
314
+ }));
315
+ el.scrollIntoView({ behavior: 'smooth', block: 'center' });
316
+ pulseElement(el);
317
+ setTimeout(() => el.focus(), 400);
318
+ }, _NavWidgetLit_publishEvent = function _NavWidgetLit_publishEvent(name, props) {
319
+ this.runtime?.events.publish(name, {
320
+ instanceId: this.instanceId,
321
+ timestamp: Date.now(),
322
+ ...props,
323
+ });
324
+ }, _NavWidgetLit_renderTipItem = function _NavWidgetLit_renderTipItem(tip, index, total) {
325
+ const { id, title, description, href, icon, external, anchor, category: _cat } = tip.config;
326
+ const isExpanded = this._expandedIds.has(id);
327
+ const isLast = index === total - 1;
328
+ const isHovered = this._hoveredId === id;
329
+ const theme = __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_getResolvedTheme).call(this);
330
+ // Determine the effective href from anchor or legacy href
331
+ const effectiveHref = anchor
332
+ ? Array.isArray(anchor.route)
333
+ ? anchor.route[0]
334
+ : anchor.route
335
+ : href;
336
+ // Same-page check
337
+ const isSamePage = anchor
338
+ ? routeMatchesCurrent(Array.isArray(anchor.route) ? anchor.route : [anchor.route])
339
+ : effectiveHref
340
+ ? routeMatchesCurrent([effectiveHref])
341
+ : false;
342
+ const hasSelector = anchor?.selector && anchor.selector !== '*';
343
+ const isFocusAction = isSamePage && hasSelector;
344
+ const hasAction = !!effectiveHref || isFocusAction;
345
+ const ctaLabel = isFocusAction ? 'Focus \u2192' : external ? 'Go \u2197' : 'Go \u2192';
346
+ // Item container styles
347
+ const itemStyle = styleMap({
348
+ borderRadius: 'var(--sc-content-border-radius, 8px)',
349
+ overflow: 'hidden',
350
+ transition: 'box-shadow 0.2s ease',
351
+ backgroundColor: 'var(--sc-content-background)',
352
+ border: 'var(--sc-content-border)',
353
+ ...(isExpanded
354
+ ? {
355
+ boxShadow: theme === 'dark'
356
+ ? '0 4px 12px rgba(0, 0, 0, 0.15)'
357
+ : '0 4px 12px rgba(0, 0, 0, 0.08)',
358
+ }
359
+ : {}),
360
+ ...(!isLast ? { borderBottom: 'var(--sc-content-item-divider, none)' } : {}),
361
+ });
362
+ // Header styles
363
+ const headerStyle = styleMap({
364
+ display: 'flex',
365
+ alignItems: 'center',
366
+ gap: '8px',
367
+ width: '100%',
368
+ padding: 'var(--sc-content-item-padding, 12px 16px)',
369
+ border: 'none',
370
+ cursor: 'pointer',
371
+ fontSize: 'var(--sc-content-item-font-size, 15px)',
372
+ fontWeight: '500',
373
+ fontFamily: 'inherit',
374
+ textAlign: 'left',
375
+ transition: 'background-color 0.15s ease',
376
+ backgroundColor: isHovered ? 'var(--sc-content-background-hover)' : 'transparent',
377
+ color: 'var(--sc-content-text-color)',
378
+ });
379
+ // Chevron styles
380
+ const chevronStyle = styleMap({
381
+ fontSize: '20px',
382
+ transition: 'transform 0.2s ease',
383
+ marginLeft: 'auto',
384
+ flexShrink: '0',
385
+ color: 'var(--sc-content-chevron-color, currentColor)',
386
+ transform: isExpanded ? 'rotate(90deg)' : 'rotate(0deg)',
387
+ });
388
+ // Body styles
389
+ const bodyStyle = styleMap({
390
+ overflow: 'hidden',
391
+ transition: 'max-height 0.25s ease, padding-bottom 0.25s ease',
392
+ padding: 'var(--sc-content-body-padding, 0 16px 12px 16px)',
393
+ color: 'var(--sc-content-text-secondary-color)',
394
+ maxHeight: isExpanded ? '500px' : '0',
395
+ paddingBottom: isExpanded ? '16px' : '0',
396
+ });
397
+ // Description styles
398
+ const descriptionStyle = styleMap({
399
+ fontSize: 'var(--sc-content-body-font-size, 14px)',
400
+ lineHeight: '1.5',
401
+ margin: '0',
402
+ });
403
+ // CTA / link button styles
404
+ const linkButtonStyle = styleMap({
405
+ display: 'inline-flex',
406
+ alignItems: 'center',
407
+ gap: '4px',
408
+ marginTop: '10px',
409
+ padding: '6px 12px',
410
+ borderRadius: '6px',
411
+ textDecoration: 'none',
412
+ fontSize: '13px',
413
+ fontWeight: '500',
414
+ cursor: 'pointer',
415
+ border: 'none',
416
+ transition: 'background-color 0.15s ease',
417
+ backgroundColor: `var(--sc-color-primary, ${TOKEN_PURPLE_4})`,
418
+ color: '#ffffff',
419
+ });
420
+ // Icon styles
421
+ const iconStyle = styleMap({
422
+ fontSize: '16px',
423
+ flexShrink: '0',
424
+ });
425
+ // Anchor click handler
426
+ const onLinkClick = (e) => {
427
+ e.preventDefault();
428
+ e.stopPropagation();
429
+ if (isFocusAction && anchor) {
430
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_handleFocusAnchor).call(this, anchor);
431
+ }
432
+ else if (effectiveHref) {
433
+ __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_handleNavigate).call(this, effectiveHref, external ?? false);
434
+ }
435
+ };
436
+ return html `
437
+ <div
438
+ style=${itemStyle}
439
+ data-nav-tip-id=${id}
440
+ >
441
+ <button
442
+ type="button"
443
+ style=${headerStyle}
444
+ aria-expanded=${isExpanded}
445
+ @click=${() => __classPrivateFieldGet(this, _NavWidgetLit_instances, "m", _NavWidgetLit_handleToggle).call(this, id)}
446
+ @mouseenter=${() => {
447
+ this._hoveredId = id;
448
+ }}
449
+ @mouseleave=${() => {
450
+ this._hoveredId = null;
451
+ }}
452
+ >
453
+ ${icon ? html `<span style=${iconStyle}>${unsafeHTML(renderIcon(icon))}</span>` : nothing}
454
+ <span>${title}</span>
455
+ <span style=${chevronStyle}>${'\u203A'}</span>
456
+ </button>
457
+ <div style=${bodyStyle} aria-hidden=${!isExpanded}>
458
+ <p style=${descriptionStyle}>${description}</p>
459
+ ${hasAction
460
+ ? html `
461
+ <a
462
+ href=${effectiveHref || '#'}
463
+ style=${linkButtonStyle}
464
+ target=${external ? '_blank' : nothing}
465
+ rel=${external ? 'noopener noreferrer' : nothing}
466
+ @click=${onLinkClick}
467
+ >${ctaLabel}</a>
468
+ `
469
+ : nothing}
470
+ </div>
471
+ </div>
472
+ `;
473
+ };
474
+ // ---------- Reactive properties (no decorators) --------------------------
475
+ NavWidgetLit.properties = {
476
+ // Public inputs
477
+ config: { attribute: false },
478
+ runtime: { attribute: false },
479
+ instanceId: { type: String },
480
+ // Internal reactive state
481
+ _expandedIds: { state: true },
482
+ _renderTick: { state: true },
483
+ _hoveredId: { state: true },
484
+ };
485
+ // ============================================================================
486
+ // Custom element registration
487
+ // ============================================================================
488
+ const TAG_NAME = 'syntro-nav-tips';
489
+ export function registerNavWidgetLit() {
490
+ if (typeof window === 'undefined')
491
+ return;
492
+ if (!customElements.get(TAG_NAME)) {
493
+ customElements.define(TAG_NAME, NavWidgetLit);
494
+ }
495
+ }