@syntrologie/runtime-sdk 0.2.21 → 1.0.0-canary.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CAPABILITIES.md +721 -460
- package/README.md +310 -68
- package/dist/RuntimeProvider.d.ts +51 -0
- package/dist/RuntimeProvider.js +113 -0
- package/dist/RuntimeProvider.js.map +1 -0
- package/dist/SmartCanvasApp.d.ts +16 -10
- package/dist/SmartCanvasApp.js +45 -49
- package/dist/SmartCanvasApp.js.map +1 -1
- package/dist/SmartCanvasElement.d.ts +5 -5
- package/dist/SmartCanvasElement.js +24 -14
- package/dist/SmartCanvasElement.js.map +1 -1
- package/dist/SmartCanvasPortal.d.ts +2 -2
- package/dist/SmartCanvasPortal.js +2 -2
- package/dist/actions/ActionEngine.d.ts +11 -0
- package/dist/actions/ActionEngine.js +274 -0
- package/dist/actions/ActionEngine.js.map +1 -0
- package/dist/actions/executors/index.d.ts +117 -0
- package/dist/actions/executors/index.js +242 -0
- package/dist/actions/executors/index.js.map +1 -0
- package/dist/actions/executors/tour.d.ts +18 -0
- package/dist/actions/executors/tour.js +332 -0
- package/dist/actions/executors/tour.js.map +1 -0
- package/dist/actions/index.d.ts +10 -0
- package/dist/actions/index.js +12 -0
- package/dist/actions/index.js.map +1 -0
- package/dist/actions/types.d.ts +399 -0
- package/dist/actions/types.js +8 -0
- package/dist/actions/types.js.map +1 -0
- package/dist/actions/validation.d.ts +14 -0
- package/dist/actions/validation.js +602 -0
- package/dist/actions/validation.js.map +1 -0
- package/dist/antiFlicker.js +1 -1
- package/dist/api.d.ts +40 -26
- package/dist/api.js +86 -56
- package/dist/api.js.map +1 -1
- package/dist/apps/AppContext.d.ts +31 -0
- package/dist/apps/AppContext.js +93 -0
- package/dist/apps/AppContext.js.map +1 -0
- package/dist/apps/AppLoader.d.ts +84 -0
- package/dist/apps/AppLoader.js +256 -0
- package/dist/apps/AppLoader.js.map +1 -0
- package/dist/apps/AppRegistry.d.ts +102 -0
- package/dist/apps/AppRegistry.js +317 -0
- package/dist/apps/AppRegistry.js.map +1 -0
- package/dist/apps/adaptive-chatbot/index.js +7 -0
- package/dist/apps/adaptive-chatbot/index.js.map +7 -0
- package/dist/apps/examples/gamification-app.example.d.ts +305 -0
- package/dist/apps/examples/gamification-app.example.js +329 -0
- package/dist/apps/examples/gamification-app.example.js.map +1 -0
- package/dist/apps/faq/index.js +11 -0
- package/dist/apps/faq/index.js.map +7 -0
- package/dist/apps/gamification/index.js +2 -0
- package/dist/apps/gamification/index.js.map +7 -0
- package/dist/apps/index.d.ts +15 -0
- package/dist/apps/index.js +17 -0
- package/dist/apps/index.js.map +1 -0
- package/dist/apps/nav/index.js +11 -0
- package/dist/apps/nav/index.js.map +7 -0
- package/dist/apps/types.d.ts +231 -0
- package/dist/apps/types.js +8 -0
- package/dist/apps/types.js.map +1 -0
- package/dist/blocks/data/ComparisonBlock.d.ts +1 -1
- package/dist/blocks/data/ComparisonBlock.js +40 -40
- package/dist/blocks/data/ComparisonBlock.js.map +1 -1
- package/dist/blocks/data/StatsBlock.d.ts +1 -1
- package/dist/blocks/data/StatsBlock.js +41 -41
- package/dist/blocks/data/StatsBlock.js.map +1 -1
- package/dist/blocks/data/index.d.ts +2 -2
- package/dist/blocks/data/index.js +2 -2
- package/dist/blocks/index.d.ts +5 -5
- package/dist/blocks/index.js +29 -29
- package/dist/blocks/index.js.map +1 -1
- package/dist/blocks/interactive/ChecklistBlock.d.ts +1 -1
- package/dist/blocks/interactive/ChecklistBlock.js +60 -60
- package/dist/blocks/interactive/ChecklistBlock.js.map +1 -1
- package/dist/blocks/interactive/RatingBlock.d.ts +1 -1
- package/dist/blocks/interactive/RatingBlock.js +75 -65
- package/dist/blocks/interactive/RatingBlock.js.map +1 -1
- package/dist/blocks/interactive/index.d.ts +2 -2
- package/dist/blocks/interactive/index.js +2 -2
- package/dist/blocks/notification/NotificationBlock.d.ts +2 -2
- package/dist/blocks/notification/NotificationBlock.js +67 -63
- package/dist/blocks/notification/NotificationBlock.js.map +1 -1
- package/dist/blocks/notification/index.d.ts +1 -1
- package/dist/blocks/notification/index.js +1 -1
- package/dist/bootstrap.d.ts +32 -8
- package/dist/bootstrap.js +204 -85
- package/dist/bootstrap.js.map +1 -1
- package/dist/components/ShadowCanvasOverlay.d.ts +6 -6
- package/dist/components/ShadowCanvasOverlay.js +144 -107
- package/dist/components/ShadowCanvasOverlay.js.map +1 -1
- package/dist/components/TileCard.d.ts +5 -5
- package/dist/components/TileCard.js +204 -154
- package/dist/components/TileCard.js.map +1 -1
- package/dist/components/TileWheel.d.ts +3 -3
- package/dist/components/TileWheel.js +7 -7
- package/dist/components/TileWheel.js.map +1 -1
- package/dist/config-validator.d.ts +49 -0
- package/dist/config-validator.js +173 -0
- package/dist/config-validator.js.map +1 -0
- package/dist/configFetcher.d.ts +2 -2
- package/dist/configFetcher.js +20 -8
- package/dist/configFetcher.js.map +1 -1
- package/dist/context/ContextManager.d.ts +3 -3
- package/dist/context/ContextManager.js +15 -15
- package/dist/context/ContextManager.js.map +1 -1
- package/dist/context/index.d.ts +4 -4
- package/dist/context/index.js +3 -3
- package/dist/context/schema.d.ts +17 -17
- package/dist/context/schema.js +1 -1
- package/dist/decisions/engine.d.ts +5 -5
- package/dist/decisions/engine.js +13 -13
- package/dist/decisions/index.d.ts +6 -6
- package/dist/decisions/index.js +5 -5
- package/dist/decisions/schema.d.ts +97 -97
- package/dist/decisions/schema.js +20 -20
- package/dist/decisions/strategies/rules.d.ts +1 -1
- package/dist/decisions/strategies/rules.js +24 -24
- package/dist/decisions/strategies/rules.js.map +1 -1
- package/dist/decisions/strategies/score.d.ts +1 -1
- package/dist/decisions/strategies/score.js +3 -3
- package/dist/decisions/types.d.ts +19 -19
- package/dist/earlyPatcher.d.ts +8 -20
- package/dist/earlyPatcher.js +13 -62
- package/dist/earlyPatcher.js.map +1 -1
- package/dist/editorLoader.d.ts +2 -0
- package/dist/editorLoader.js +104 -58
- package/dist/editorLoader.js.map +1 -1
- package/dist/events/EventBus.d.ts +3 -3
- package/dist/events/EventBus.js +5 -7
- package/dist/events/EventBus.js.map +1 -1
- package/dist/events/index.d.ts +6 -6
- package/dist/events/index.js +5 -5
- package/dist/events/normalizers/canvas.d.ts +2 -2
- package/dist/events/normalizers/canvas.js +3 -3
- package/dist/events/normalizers/canvas.js.map +1 -1
- package/dist/events/normalizers/posthog.d.ts +25 -1
- package/dist/events/normalizers/posthog.js +35 -27
- package/dist/events/normalizers/posthog.js.map +1 -1
- package/dist/events/schema.d.ts +13 -13
- package/dist/events/schema.js +2 -2
- package/dist/events/types.d.ts +7 -1
- package/dist/events/types.js +29 -21
- package/dist/events/types.js.map +1 -1
- package/dist/experiments/adapters/growthbook.d.ts +4 -4
- package/dist/experiments/adapters/growthbook.js +5 -5
- package/dist/experiments/adapters/growthbook.js.map +1 -1
- package/dist/experiments/index.d.ts +3 -3
- package/dist/experiments/index.js +1 -1
- package/dist/experiments/registry.d.ts +2 -2
- package/dist/experiments/registry.js +2 -2
- package/dist/experiments/types.d.ts +5 -1
- package/dist/fetchers/cdnFetcher.d.ts +1 -1
- package/dist/fetchers/cdnFetcher.js +4 -8
- package/dist/fetchers/cdnFetcher.js.map +1 -1
- package/dist/fetchers/experimentsFetcher.d.ts +2 -2
- package/dist/fetchers/experimentsFetcher.js +7 -7
- package/dist/fetchers/experimentsFetcher.js.map +1 -1
- package/dist/fetchers/index.d.ts +3 -3
- package/dist/fetchers/index.js +2 -2
- package/dist/fetchers/index.js.map +1 -1
- package/dist/fetchers/registry.d.ts +1 -1
- package/dist/fetchers/registry.js +4 -4
- package/dist/fetchers/types.d.ts +1 -1
- package/dist/hooks/useCanvasOverlays.d.ts +8 -5
- package/dist/hooks/useCanvasOverlays.js +66 -17
- package/dist/hooks/useCanvasOverlays.js.map +1 -1
- package/dist/hooks/useHostPatches.d.ts +2 -2
- package/dist/hooks/useHostPatches.js +8 -8
- package/dist/hooks/useHostPatches.js.map +1 -1
- package/dist/hooks/useShadowCanvasConfig.d.ts +5 -9
- package/dist/hooks/useShadowCanvasConfig.js +7 -5
- package/dist/hooks/useShadowCanvasConfig.js.map +1 -1
- package/dist/hostPatcher/core/patcher.d.ts +1 -1
- package/dist/hostPatcher/core/patcher.js +18 -9
- package/dist/hostPatcher/core/patcher.js.map +1 -1
- package/dist/hostPatcher/core/sanitizer.js +24 -3
- package/dist/hostPatcher/core/sanitizer.js.map +1 -1
- package/dist/hostPatcher/policy/defaultPolicy.js +15 -5
- package/dist/hostPatcher/policy/defaultPolicy.js.map +1 -1
- package/dist/hostPatcher/utils/anchors.js +4 -6
- package/dist/hostPatcher/utils/anchors.js.map +1 -1
- package/dist/index.d.ts +34 -27
- package/dist/index.js +36 -24
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +29 -0
- package/dist/logger.js +81 -0
- package/dist/logger.js.map +1 -0
- package/dist/metrics/index.d.ts +1 -1
- package/dist/metrics/index.js +1 -1
- package/dist/metrics/sessionMetrics.d.ts +1 -1
- package/dist/metrics/sessionMetrics.js +6 -6
- package/dist/overlays/fetcher.d.ts +2 -2
- package/dist/overlays/fetcher.js +4 -4
- package/dist/overlays/recipeRegistry.js +2 -2
- package/dist/overlays/recipeRegistry.js.map +1 -1
- package/dist/overlays/runtime/anchor/resolve.js +1 -1
- package/dist/overlays/runtime/anchor/resolve.js.map +1 -1
- package/dist/overlays/runtime/index.d.ts +7 -7
- package/dist/overlays/runtime/index.js +7 -7
- package/dist/overlays/runtime/overlay/highlight.js +39 -39
- package/dist/overlays/runtime/overlay/highlight.js.map +1 -1
- package/dist/overlays/runtime/overlay/modal.js +5 -5
- package/dist/overlays/runtime/overlay/modal.js.map +1 -1
- package/dist/overlays/runtime/overlay/root.js +1 -1
- package/dist/overlays/runtime/overlay/runner.js +70 -23
- package/dist/overlays/runtime/overlay/runner.js.map +1 -1
- package/dist/overlays/runtime/overlay/tooltip.d.ts +1 -1
- package/dist/overlays/runtime/overlay/tooltip.js +10 -10
- package/dist/overlays/runtime/overlay/tooltip.js.map +1 -1
- package/dist/overlays/runtime/utils/dom.js +4 -1
- package/dist/overlays/runtime/utils/dom.js.map +1 -1
- package/dist/overlays/schema.d.ts +146 -146
- package/dist/overlays/schema.js +12 -8
- package/dist/overlays/schema.js.map +1 -1
- package/dist/react.d.ts +7 -7
- package/dist/react.js +4 -4
- package/dist/react.js.map +1 -1
- package/dist/render/RenderContext.d.ts +2 -2
- package/dist/render/RenderContext.js +5 -5
- package/dist/render/RenderContext.js.map +1 -1
- package/dist/render/index.d.ts +3 -3
- package/dist/render/index.js +1 -1
- package/dist/render/types.d.ts +4 -4
- package/dist/runtime.d.ts +32 -8
- package/dist/runtime.js +87 -13
- package/dist/runtime.js.map +1 -1
- package/dist/smart-canvas.esm.js +155 -78
- package/dist/smart-canvas.esm.js.map +4 -4
- package/dist/smart-canvas.js +38776 -33216
- package/dist/smart-canvas.js.map +4 -4
- package/dist/smart-canvas.min.js +156 -78
- package/dist/smart-canvas.min.js.map +4 -4
- package/dist/state/StateStore.d.ts +1 -1
- package/dist/state/StateStore.js +9 -9
- package/dist/state/StateStore.js.map +1 -1
- package/dist/state/helpers/cooldowns.d.ts +1 -1
- package/dist/state/helpers/cooldowns.js +1 -1
- package/dist/state/helpers/dismissals.d.ts +1 -1
- package/dist/state/helpers/dismissals.js +1 -1
- package/dist/state/helpers/frequency.d.ts +1 -1
- package/dist/state/helpers/frequency.js +1 -1
- package/dist/state/index.d.ts +4 -4
- package/dist/state/index.js +3 -3
- package/dist/state/schema.d.ts +1 -1
- package/dist/state/schema.js +1 -1
- package/dist/store/example.d.ts +1 -0
- package/dist/store/example.js +43 -0
- package/dist/store/example.js.map +1 -0
- package/dist/store/mini-effector.d.ts +46 -0
- package/dist/store/mini-effector.js +88 -0
- package/dist/store/mini-effector.js.map +1 -0
- package/dist/surfaces/Surfaces.d.ts +11 -0
- package/dist/surfaces/Surfaces.js +361 -0
- package/dist/surfaces/Surfaces.js.map +1 -0
- package/dist/surfaces/index.d.ts +9 -0
- package/dist/surfaces/index.js +12 -0
- package/dist/surfaces/index.js.map +1 -0
- package/dist/surfaces/positioning.d.ts +50 -0
- package/dist/surfaces/positioning.js +228 -0
- package/dist/surfaces/positioning.js.map +1 -0
- package/dist/surfaces/types.d.ts +167 -0
- package/dist/surfaces/types.js +23 -0
- package/dist/surfaces/types.js.map +1 -0
- package/dist/telemetry/adapters/noop.d.ts +12 -0
- package/dist/telemetry/adapters/noop.js +42 -0
- package/dist/telemetry/adapters/noop.js.map +1 -0
- package/dist/telemetry/adapters/posthog.d.ts +8 -2
- package/dist/telemetry/adapters/posthog.js +36 -14
- package/dist/telemetry/adapters/posthog.js.map +1 -1
- package/dist/telemetry/index.d.ts +4 -3
- package/dist/telemetry/index.js +3 -2
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/registry.d.ts +2 -2
- package/dist/telemetry/registry.js +4 -2
- package/dist/telemetry/registry.js.map +1 -1
- package/dist/telemetry/types.d.ts +1 -1
- package/dist/theme/ThemeProvider.d.ts +2 -2
- package/dist/theme/ThemeProvider.js +21 -21
- package/dist/theme/ThemeProvider.js.map +1 -1
- package/dist/theme/defaultTheme.d.ts +2 -2
- package/dist/theme/defaultTheme.js +111 -111
- package/dist/theme/defaultTheme.js.map +1 -1
- package/dist/theme/extractHostTheme.d.ts +1 -1
- package/dist/theme/extractHostTheme.js +42 -44
- package/dist/theme/extractHostTheme.js.map +1 -1
- package/dist/theme/index.d.ts +5 -5
- package/dist/theme/index.js +3 -3
- package/dist/theme/index.js.map +1 -1
- package/dist/theme/types.d.ts +2 -2
- package/dist/token.d.ts +2 -0
- package/dist/token.js +3 -6
- package/dist/token.js.map +1 -1
- package/dist/types-only.d.ts +32 -0
- package/dist/types-only.js +11 -0
- package/dist/types-only.js.map +1 -0
- package/dist/types.d.ts +89 -56
- package/dist/types.js +15 -2
- package/dist/types.js.map +1 -1
- package/dist/version.d.ts +13 -0
- package/dist/version.js +14 -0
- package/dist/version.js.map +1 -0
- package/dist/widgets/WidgetRegistry.d.ts +139 -0
- package/dist/widgets/WidgetRegistry.js +182 -0
- package/dist/widgets/WidgetRegistry.js.map +1 -0
- package/dist/widgets/index.d.ts +7 -0
- package/dist/widgets/index.js +7 -0
- package/dist/widgets/index.js.map +1 -0
- package/package.json +26 -10
- package/schema/canvas-config.schema.json +488 -254
- package/schema/runtime-context.schema.json +1 -5
package/CAPABILITIES.md
CHANGED
|
@@ -1,611 +1,872 @@
|
|
|
1
1
|
# SmartCanvas SDK Capabilities
|
|
2
2
|
|
|
3
|
-
This document describes all available operations and capabilities of the SmartCanvas SDK for DOM manipulation and
|
|
3
|
+
This document describes all available operations and capabilities of the SmartCanvas SDK for DOM manipulation, interventions, and UI rendering.
|
|
4
|
+
|
|
5
|
+
> **Auto-generated**: This file is assembled from individual adaptive package capabilities during build.
|
|
4
6
|
|
|
5
7
|
## Table of Contents
|
|
6
8
|
- [Overview](#overview)
|
|
7
|
-
- [
|
|
8
|
-
- [
|
|
9
|
-
- [
|
|
10
|
-
- [
|
|
11
|
-
- [
|
|
9
|
+
- [Quick Start Example](#quick-start-example)
|
|
10
|
+
- [Adaptive Packages](#adaptive-packages)
|
|
11
|
+
- [Surfaces](#surfaces)
|
|
12
|
+
- [Anchor Resolution](#anchor-resolution)
|
|
13
|
+
- [Decision Strategies](#decision-strategies)
|
|
12
14
|
- [Best Practices](#best-practices)
|
|
13
15
|
|
|
16
|
+
---
|
|
17
|
+
|
|
14
18
|
## Overview
|
|
15
19
|
|
|
16
|
-
The SmartCanvas SDK
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
+
The SmartCanvas SDK provides three main systems for modifying web pages:
|
|
21
|
+
|
|
22
|
+
1. **ActionEngine** - Unified execution layer for interventions (highlight, tooltip, badge, DOM modifications)
|
|
23
|
+
2. **Surfaces** - Managed surface system for rendering UI into named slots
|
|
24
|
+
3. **Runtime** - Context, events, state, and decision management
|
|
25
|
+
|
|
26
|
+
All modifications are reversible and publish events to the EventBus for tracking.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Quick Start Example
|
|
31
|
+
|
|
32
|
+
### Simple Header Text Change
|
|
33
|
+
|
|
34
|
+
Change a page header when the element is visible:
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{
|
|
38
|
+
"id": "welcome-header-change",
|
|
39
|
+
"activation": {
|
|
40
|
+
"routes": { "include": ["/", "/home"] },
|
|
41
|
+
"strategy": {
|
|
42
|
+
"type": "rules",
|
|
43
|
+
"rules": [
|
|
44
|
+
{
|
|
45
|
+
"conditions": [
|
|
46
|
+
{ "type": "anchor_visible", "anchorId": "h1.hero-title", "state": "visible" }
|
|
47
|
+
],
|
|
48
|
+
"value": true
|
|
49
|
+
}
|
|
50
|
+
],
|
|
51
|
+
"default": false
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"actions": [
|
|
55
|
+
{
|
|
56
|
+
"kind": "set_text",
|
|
57
|
+
"anchorId": "h1.hero-title",
|
|
58
|
+
"text": "Welcome to Our New Experience"
|
|
59
|
+
}
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
20
65
|
|
|
21
|
-
##
|
|
66
|
+
## Adaptive Packages
|
|
22
67
|
|
|
23
|
-
The SDK
|
|
68
|
+
The SDK includes the following adaptive packages, each providing specific capabilities:
|
|
24
69
|
|
|
25
|
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
70
|
+
- [@syntrologie/adapt-chatbot](#syntrologieadapt-chatbot)
|
|
71
|
+
- [@syntrologie/adapt-content](#syntrologieadapt-content)
|
|
72
|
+
- [@syntrologie/adapt-faq](#syntrologieadapt-faq)
|
|
73
|
+
- [@syntrologie/adapt-gamification](#syntrologieadapt-gamification)
|
|
74
|
+
- [@syntrologie/adapt-nav](#syntrologieadapt-nav)
|
|
75
|
+
- [@syntrologie/adapt-navigation](#syntrologieadapt-navigation)
|
|
76
|
+
- [@syntrologie/adapt-overlays](#syntrologieadapt-overlays)
|
|
30
77
|
|
|
31
|
-
|
|
32
|
-
- **Purpose**: Allows limited modifications to existing elements
|
|
33
|
-
- **Allowed**: Everything from additive + title attribute
|
|
34
|
-
- **Not Allowed**: Text changes, color changes
|
|
35
|
-
- **Use When**: Adding accessibility improvements or metadata
|
|
78
|
+
---
|
|
36
79
|
|
|
37
|
-
|
|
38
|
-
- **Purpose**: Full control over content modification
|
|
39
|
-
- **Allowed**: Everything including setText, background/text colors
|
|
40
|
-
- **Required For**: Changing headlines, CTAs, or any text content
|
|
41
|
-
- **Use When**: A/B testing copy variations or personalizing content
|
|
80
|
+
# @syntrologie/adapt-chatbot
|
|
42
81
|
|
|
43
|
-
|
|
82
|
+
AI chat assistant widget with action execution capabilities.
|
|
44
83
|
|
|
45
|
-
|
|
84
|
+
## Widgets
|
|
85
|
+
|
|
86
|
+
### adaptive-chatbot:assistant
|
|
87
|
+
|
|
88
|
+
Mounts an AI-powered chat assistant that connects to a backend LLM endpoint. The assistant can parse action instructions from the LLM response and execute them on the page via the runtime's ActionEngine.
|
|
89
|
+
|
|
90
|
+
**Tile config example:**
|
|
46
91
|
|
|
47
|
-
### 1. CSS Selector
|
|
48
92
|
```json
|
|
49
93
|
{
|
|
50
|
-
"
|
|
51
|
-
"
|
|
94
|
+
"id": "chatbot-assistant",
|
|
95
|
+
"title": "Ask Assistant",
|
|
96
|
+
"content": {
|
|
97
|
+
"type": "custom",
|
|
98
|
+
"component": "adaptive-chatbot:assistant",
|
|
99
|
+
"props": {
|
|
100
|
+
"backendUrl": "/api/chat/message",
|
|
101
|
+
"mlflowRunId": "abc123",
|
|
102
|
+
"greeting": "Hi! How can I help?"
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
"size": "full",
|
|
106
|
+
"defaultExpanded": true
|
|
52
107
|
}
|
|
53
108
|
```
|
|
54
|
-
- **Use**: Standard CSS selectors
|
|
55
|
-
- **Example**: `"h1"`, `".button-primary"`, `"#hero-section h2"`
|
|
56
109
|
|
|
57
|
-
###
|
|
110
|
+
### Config Props
|
|
111
|
+
|
|
112
|
+
| Property | Type | Required | Default | Description |
|
|
113
|
+
| ------------- | ------ | -------- | --------------------- | --------------------------------------- |
|
|
114
|
+
| `backendUrl` | string | Yes | — | URL for the chat API endpoint |
|
|
115
|
+
| `mlflowRunId` | string | No | — | MLflow run ID for experiment tracking |
|
|
116
|
+
| `greeting` | string | No | "Hi! How can I help?" | Initial greeting message |
|
|
117
|
+
| `maxHistory` | number | No | 20 | Max messages sent as history to backend |
|
|
118
|
+
|
|
119
|
+
## Action Execution
|
|
120
|
+
|
|
121
|
+
The chatbot does **not** define its own action kinds. Instead, it parses JSON action blocks from the LLM response and executes them via `runtime.actions.applyBatch()`. This means the chatbot can trigger any action kind registered in the runtime (highlights, tooltips, text changes, navigation, tours, etc.).
|
|
122
|
+
|
|
123
|
+
### LLM Response Format
|
|
124
|
+
|
|
125
|
+
The backend returns a text reply that may contain embedded JSON action blocks in fenced code blocks:
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Here's what I found. Let me highlight the pricing section for you.
|
|
129
|
+
|
|
130
|
+
\`\`\`json
|
|
131
|
+
{"kind": "overlays:highlight", "anchorId": "pricing-section"}
|
|
132
|
+
\`\`\`
|
|
133
|
+
|
|
134
|
+
Is there anything else you'd like to know?
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
- JSON blocks with a `kind` field are extracted as actions and removed from display text
|
|
138
|
+
- JSON blocks without `kind` are left in the display text as-is
|
|
139
|
+
- Multiple action blocks can appear in a single response
|
|
140
|
+
- Actions with unknown kinds are silently ignored by the ActionEngine
|
|
141
|
+
|
|
142
|
+
## Authentication
|
|
143
|
+
|
|
144
|
+
The widget reads auth credentials from the browser:
|
|
145
|
+
|
|
146
|
+
- **JWT**: `stytch_session_jwt` cookie
|
|
147
|
+
- **Workspace ID**: `syntrologie_workspace_id` from localStorage
|
|
148
|
+
- Headers: `Authorization: Bearer <jwt>` + `X-Workspace-Id: <id>`
|
|
149
|
+
|
|
150
|
+
## Events
|
|
151
|
+
|
|
152
|
+
| Event | Props | Description |
|
|
153
|
+
| ------------------------- | ---------------------------- | --------------------------------- |
|
|
154
|
+
| `chatbot.actions_applied` | `count`, `kinds[]`, `tileId` | Emitted when actions are executed |
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
# @syntrologie/adapt-content
|
|
160
|
+
|
|
161
|
+
DOM content modification capabilities for text, attributes, styles, HTML, and classes.
|
|
162
|
+
|
|
163
|
+
## Actions
|
|
164
|
+
|
|
165
|
+
### set_text
|
|
166
|
+
|
|
167
|
+
Replaces the text content of an element.
|
|
168
|
+
|
|
169
|
+
| Property | Type | Required | Description |
|
|
170
|
+
| ---------- | ------------ | -------- | ---------------- |
|
|
171
|
+
| `kind` | `"set_text"` | Yes | Action type |
|
|
172
|
+
| `anchorId` | string | Yes | Element selector |
|
|
173
|
+
| `text` | string | Yes | New text content |
|
|
174
|
+
|
|
58
175
|
```json
|
|
59
176
|
{
|
|
60
|
-
"
|
|
61
|
-
"
|
|
62
|
-
"
|
|
177
|
+
"kind": "set_text",
|
|
178
|
+
"anchorId": "h1.hero-title",
|
|
179
|
+
"text": "Start Your Free Trial Today"
|
|
63
180
|
}
|
|
64
181
|
```
|
|
65
|
-
- **Use**: Target elements by data attributes
|
|
66
|
-
- **Example**: Finds `<div data-testid="hero-banner">`
|
|
67
|
-
- **Note**: If value is omitted, matches any element with that data attribute
|
|
68
182
|
|
|
69
|
-
###
|
|
183
|
+
### set_attr
|
|
184
|
+
|
|
185
|
+
Sets an HTML attribute on an element.
|
|
186
|
+
|
|
187
|
+
| Property | Type | Required | Description |
|
|
188
|
+
| ---------- | ------------ | -------- | ---------------- |
|
|
189
|
+
| `kind` | `"set_attr"` | Yes | Action type |
|
|
190
|
+
| `anchorId` | string | Yes | Element selector |
|
|
191
|
+
| `attr` | string | Yes | Attribute name |
|
|
192
|
+
| `value` | string | Yes | Attribute value |
|
|
193
|
+
|
|
194
|
+
**Blocked attributes:** Event handlers (`onclick`, `onerror`, etc.) are not allowed.
|
|
195
|
+
|
|
70
196
|
```json
|
|
71
197
|
{
|
|
72
|
-
"
|
|
73
|
-
"
|
|
74
|
-
"
|
|
198
|
+
"kind": "set_attr",
|
|
199
|
+
"anchorId": "#signup-form",
|
|
200
|
+
"attr": "data-experiment",
|
|
201
|
+
"value": "signup-v2"
|
|
75
202
|
}
|
|
76
203
|
```
|
|
77
|
-
- **Use**: Target accessible elements
|
|
78
|
-
- **Example**: Finds `<button role="button" aria-label="Submit">`
|
|
79
|
-
- **Note**: Can use role, label, or both
|
|
80
204
|
|
|
81
|
-
###
|
|
205
|
+
### set_style
|
|
206
|
+
|
|
207
|
+
Sets inline CSS styles on an element.
|
|
208
|
+
|
|
209
|
+
| Property | Type | Required | Description |
|
|
210
|
+
| ---------- | ------------- | -------- | ------------------------ |
|
|
211
|
+
| `kind` | `"set_style"` | Yes | Action type |
|
|
212
|
+
| `anchorId` | string | Yes | Element selector |
|
|
213
|
+
| `styles` | object | Yes | CSS property/value pairs |
|
|
214
|
+
|
|
82
215
|
```json
|
|
83
216
|
{
|
|
84
|
-
"
|
|
85
|
-
"
|
|
217
|
+
"kind": "set_style",
|
|
218
|
+
"anchorId": ".hero-section",
|
|
219
|
+
"styles": {
|
|
220
|
+
"background-color": "#1e40af",
|
|
221
|
+
"padding": "2rem"
|
|
222
|
+
}
|
|
86
223
|
}
|
|
87
224
|
```
|
|
88
|
-
- **Use**: Direct element reference (programmatic use only)
|
|
89
|
-
- **Note**: Cannot be serialized in JSON configs
|
|
90
225
|
|
|
91
|
-
|
|
226
|
+
### insert_html
|
|
227
|
+
|
|
228
|
+
Inserts HTML content relative to an element.
|
|
229
|
+
|
|
230
|
+
| Property | Type | Required | Description |
|
|
231
|
+
| ---------- | --------------- | -------- | ----------------------------------------------------------- |
|
|
232
|
+
| `kind` | `"insert_html"` | Yes | Action type |
|
|
233
|
+
| `anchorId` | string | Yes | Element selector |
|
|
234
|
+
| `html` | string | Yes | HTML content (sanitized) |
|
|
235
|
+
| `position` | string | Yes | `"before"`, `"after"`, `"prepend"`, `"append"`, `"replace"` |
|
|
236
|
+
|
|
237
|
+
**Positions:**
|
|
238
|
+
|
|
239
|
+
- `before` - Insert before the element
|
|
240
|
+
- `after` - Insert after the element
|
|
241
|
+
- `prepend` - Insert inside, before first child
|
|
242
|
+
- `append` - Insert inside, after last child
|
|
243
|
+
- `replace` - Replace the entire element
|
|
92
244
|
|
|
93
|
-
### 1. setText
|
|
94
|
-
**Purpose**: Replace the text content of an element
|
|
95
245
|
```json
|
|
96
246
|
{
|
|
97
|
-
"kind": "
|
|
98
|
-
"
|
|
247
|
+
"kind": "insert_html",
|
|
248
|
+
"anchorId": ".cta-button",
|
|
249
|
+
"html": "<span class=\"badge\">NEW</span>",
|
|
250
|
+
"position": "append"
|
|
99
251
|
}
|
|
100
252
|
```
|
|
101
|
-
- **Requires**: `tier: "surgical"`
|
|
102
|
-
- **Effect**: Replaces all text content in the element
|
|
103
|
-
- **Common Use**: A/B testing headlines, CTAs, product descriptions
|
|
104
|
-
- **Note**: Removes all child elements, use carefully
|
|
105
253
|
|
|
106
|
-
###
|
|
107
|
-
|
|
254
|
+
### add_class
|
|
255
|
+
|
|
256
|
+
Adds a CSS class to an element.
|
|
257
|
+
|
|
258
|
+
| Property | Type | Required | Description |
|
|
259
|
+
| ----------- | ------------- | -------- | ----------------- |
|
|
260
|
+
| `kind` | `"add_class"` | Yes | Action type |
|
|
261
|
+
| `anchorId` | string | Yes | Element selector |
|
|
262
|
+
| `className` | string | Yes | Class name to add |
|
|
263
|
+
|
|
108
264
|
```json
|
|
109
265
|
{
|
|
110
|
-
"kind": "
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"important": true // optional, adds !important
|
|
266
|
+
"kind": "add_class",
|
|
267
|
+
"anchorId": ".pricing-card",
|
|
268
|
+
"className": "highlighted"
|
|
114
269
|
}
|
|
115
270
|
```
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
**Purpose**: Add a CSS class to an element
|
|
271
|
+
|
|
272
|
+
### remove_class
|
|
273
|
+
|
|
274
|
+
Removes a CSS class from an element.
|
|
275
|
+
|
|
276
|
+
| Property | Type | Required | Description |
|
|
277
|
+
| ----------- | ---------------- | -------- | -------------------- |
|
|
278
|
+
| `kind` | `"remove_class"` | Yes | Action type |
|
|
279
|
+
| `anchorId` | string | Yes | Element selector |
|
|
280
|
+
| `className` | string | Yes | Class name to remove |
|
|
281
|
+
|
|
128
282
|
```json
|
|
129
283
|
{
|
|
130
|
-
"kind": "
|
|
131
|
-
"
|
|
284
|
+
"kind": "remove_class",
|
|
285
|
+
"anchorId": ".pricing-card",
|
|
286
|
+
"className": "hidden"
|
|
132
287
|
}
|
|
133
288
|
```
|
|
134
|
-
- **Requirement**: Class must start with `syntro-`, `sc-`, or `sx-`
|
|
135
|
-
- **Common Use**: Apply pre-defined styles, mark elements
|
|
136
|
-
- **Note**: Won't add duplicate classes
|
|
137
289
|
|
|
138
|
-
|
|
139
|
-
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
# @syntrologie/adapt-faq
|
|
294
|
+
|
|
295
|
+
FAQ accordion widget with conditional item visibility.
|
|
296
|
+
|
|
297
|
+
## Actions
|
|
298
|
+
|
|
299
|
+
### mount_faq
|
|
300
|
+
|
|
301
|
+
Mounts an FAQ accordion widget to a surface slot.
|
|
302
|
+
|
|
303
|
+
| Property | Type | Required | Description |
|
|
304
|
+
| -------------- | ------------- | -------- | -------------------------------------------------------- |
|
|
305
|
+
| `kind` | `"mount_faq"` | Yes | Action type |
|
|
306
|
+
| `slot` | string | Yes | Target slot (e.g., `"drawer_right"`, `"overlay_center"`) |
|
|
307
|
+
| `config.title` | string | No | Widget title |
|
|
308
|
+
| `config.items` | array | Yes | FAQ items (see below) |
|
|
309
|
+
|
|
310
|
+
### FAQ Item Schema
|
|
311
|
+
|
|
312
|
+
Each item in the `items` array:
|
|
313
|
+
|
|
314
|
+
| Property | Type | Required | Description |
|
|
315
|
+
| ---------- | ---------------- | -------- | ----------------------------------- |
|
|
316
|
+
| `question` | string | Yes | The question text |
|
|
317
|
+
| `answer` | string | Yes | The answer text (supports markdown) |
|
|
318
|
+
| `showWhen` | DecisionStrategy | No | Conditional visibility strategy |
|
|
319
|
+
|
|
140
320
|
```json
|
|
141
321
|
{
|
|
142
|
-
"kind": "
|
|
143
|
-
"
|
|
322
|
+
"kind": "mount_faq",
|
|
323
|
+
"slot": "drawer_right",
|
|
324
|
+
"config": {
|
|
325
|
+
"title": "Frequently Asked Questions",
|
|
326
|
+
"items": [
|
|
327
|
+
{
|
|
328
|
+
"question": "How do I get started?",
|
|
329
|
+
"answer": "Sign up for a free account and follow our quickstart guide."
|
|
330
|
+
},
|
|
331
|
+
{
|
|
332
|
+
"question": "What payment methods do you accept?",
|
|
333
|
+
"answer": "We accept all major credit cards and PayPal.",
|
|
334
|
+
"showWhen": {
|
|
335
|
+
"type": "rules",
|
|
336
|
+
"rules": [
|
|
337
|
+
{
|
|
338
|
+
"conditions": [{ "type": "page_url", "pattern": "/pricing*" }],
|
|
339
|
+
"value": true
|
|
340
|
+
}
|
|
341
|
+
],
|
|
342
|
+
"default": false
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
]
|
|
346
|
+
}
|
|
144
347
|
}
|
|
145
348
|
```
|
|
146
|
-
- **Requirement**: Can only remove prefixed classes
|
|
147
|
-
- **Common Use**: Revealing hidden elements, removing states
|
|
148
|
-
- **Note**: Safe if class doesn't exist
|
|
149
349
|
|
|
150
|
-
|
|
151
|
-
|
|
350
|
+
## Compositional Pattern
|
|
351
|
+
|
|
352
|
+
The FAQ widget supports **per-item conditional visibility** using `showWhen` strategies. This allows different FAQ items to appear based on:
|
|
353
|
+
|
|
354
|
+
- Current page/route
|
|
355
|
+
- User segment or state
|
|
356
|
+
- Viewport conditions
|
|
357
|
+
- Any other DecisionStrategy condition
|
|
358
|
+
|
|
359
|
+
Items without `showWhen` are always visible.
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
---
|
|
363
|
+
|
|
364
|
+
# @syntrologie/adapt-gamification
|
|
365
|
+
|
|
366
|
+
Gamification capabilities including badges, points, and leaderboards.
|
|
367
|
+
|
|
368
|
+
## Actions
|
|
369
|
+
|
|
370
|
+
### mount_gamification
|
|
371
|
+
|
|
372
|
+
Mounts gamification UI elements.
|
|
373
|
+
|
|
374
|
+
| Property | Type | Required | Description |
|
|
375
|
+
| -------- | ---------------------- | -------- | -------------------------- |
|
|
376
|
+
| `kind` | `"mount_gamification"` | Yes | Action type |
|
|
377
|
+
| `slot` | string | Yes | Target slot |
|
|
378
|
+
| `config` | object | Yes | Gamification configuration |
|
|
379
|
+
|
|
380
|
+
### Configuration Schema
|
|
381
|
+
|
|
382
|
+
| Property | Type | Required | Default | Description |
|
|
383
|
+
| ----------------------------- | ------- | -------- | ------- | ---------------------- |
|
|
384
|
+
| `badges` | array | No | `[]` | Badge definitions |
|
|
385
|
+
| `points.enabled` | boolean | No | `false` | Enable points system |
|
|
386
|
+
| `points.multiplier` | number | No | `1` | Points multiplier |
|
|
387
|
+
| `leaderboard.enabled` | boolean | No | `false` | Show leaderboard |
|
|
388
|
+
| `leaderboard.refreshInterval` | number | No | `60000` | Refresh interval in ms |
|
|
389
|
+
|
|
390
|
+
### Badge Schema
|
|
391
|
+
|
|
392
|
+
| Property | Type | Required | Description |
|
|
393
|
+
| -------------------- | ------ | -------- | ----------------------------- |
|
|
394
|
+
| `id` | string | Yes | Unique badge identifier |
|
|
395
|
+
| `name` | string | Yes | Display name |
|
|
396
|
+
| `icon` | string | Yes | Icon identifier |
|
|
397
|
+
| `description` | string | No | Badge description |
|
|
398
|
+
| `trigger.event` | string | Yes | Event that triggers the badge |
|
|
399
|
+
| `trigger.conditions` | array | No | Additional conditions |
|
|
400
|
+
|
|
152
401
|
```json
|
|
153
402
|
{
|
|
154
|
-
"kind": "
|
|
155
|
-
"
|
|
156
|
-
"
|
|
403
|
+
"kind": "mount_gamification",
|
|
404
|
+
"slot": "overlay_corner_br",
|
|
405
|
+
"config": {
|
|
406
|
+
"badges": [
|
|
407
|
+
{
|
|
408
|
+
"id": "first-purchase",
|
|
409
|
+
"name": "First Purchase",
|
|
410
|
+
"icon": "shopping-cart",
|
|
411
|
+
"description": "Made your first purchase!",
|
|
412
|
+
"trigger": {
|
|
413
|
+
"event": "purchase_completed"
|
|
414
|
+
}
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
"id": "explorer",
|
|
418
|
+
"name": "Explorer",
|
|
419
|
+
"icon": "compass",
|
|
420
|
+
"description": "Visited 10 different pages",
|
|
421
|
+
"trigger": {
|
|
422
|
+
"event": "page_view",
|
|
423
|
+
"conditions": [
|
|
424
|
+
{ "type": "session_metric", "key": "unique_pages", "operator": ">=", "threshold": 10 }
|
|
425
|
+
]
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
],
|
|
429
|
+
"points": {
|
|
430
|
+
"enabled": true,
|
|
431
|
+
"multiplier": 2
|
|
432
|
+
},
|
|
433
|
+
"leaderboard": {
|
|
434
|
+
"enabled": true,
|
|
435
|
+
"refreshInterval": 30000
|
|
436
|
+
}
|
|
437
|
+
}
|
|
157
438
|
}
|
|
158
439
|
```
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
- **
|
|
164
|
-
|
|
165
|
-
- **
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
440
|
+
|
|
441
|
+
## Use Cases
|
|
442
|
+
|
|
443
|
+
- **Engagement rewards**: Award badges for completing onboarding steps
|
|
444
|
+
- **Loyalty programs**: Track points for purchases or interactions
|
|
445
|
+
- **Social proof**: Display leaderboards to encourage participation
|
|
446
|
+
- **Progress tracking**: Show achievement progress to motivate users
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
---
|
|
450
|
+
|
|
451
|
+
# @syntrologie/adapt-nav
|
|
452
|
+
|
|
453
|
+
Navigation link list widget with conditional item visibility.
|
|
454
|
+
|
|
455
|
+
## Actions
|
|
456
|
+
|
|
457
|
+
### mount_nav
|
|
458
|
+
|
|
459
|
+
Mounts a navigation link list widget to a surface slot.
|
|
460
|
+
|
|
461
|
+
| Property | Type | Required | Description |
|
|
462
|
+
| -------------- | ------------- | -------- | ---------------------------------------------------------- |
|
|
463
|
+
| `kind` | `"mount_nav"` | Yes | Action type |
|
|
464
|
+
| `slot` | string | Yes | Target slot (e.g., `"drawer_left"`, `"inline:{anchorId}"`) |
|
|
465
|
+
| `config.title` | string | No | Widget title |
|
|
466
|
+
| `config.items` | array | Yes | Navigation items (see below) |
|
|
467
|
+
|
|
468
|
+
### Nav Item Schema
|
|
469
|
+
|
|
470
|
+
Each item in the `items` array:
|
|
471
|
+
|
|
472
|
+
| Property | Type | Required | Description |
|
|
473
|
+
| ---------- | ---------------- | -------- | ------------------------------- |
|
|
474
|
+
| `label` | string | Yes | Link text |
|
|
475
|
+
| `href` | string | Yes | Link destination |
|
|
476
|
+
| `icon` | string | No | Icon identifier |
|
|
477
|
+
| `showWhen` | DecisionStrategy | No | Conditional visibility strategy |
|
|
478
|
+
|
|
170
479
|
```json
|
|
171
480
|
{
|
|
172
|
-
"kind": "
|
|
173
|
-
"
|
|
481
|
+
"kind": "mount_nav",
|
|
482
|
+
"slot": "drawer_left",
|
|
483
|
+
"config": {
|
|
484
|
+
"title": "Quick Links",
|
|
485
|
+
"items": [
|
|
486
|
+
{
|
|
487
|
+
"label": "Dashboard",
|
|
488
|
+
"href": "/dashboard",
|
|
489
|
+
"icon": "home"
|
|
490
|
+
},
|
|
491
|
+
{
|
|
492
|
+
"label": "Admin Settings",
|
|
493
|
+
"href": "/admin",
|
|
494
|
+
"icon": "settings",
|
|
495
|
+
"showWhen": {
|
|
496
|
+
"type": "rules",
|
|
497
|
+
"rules": [
|
|
498
|
+
{
|
|
499
|
+
"conditions": [{ "type": "state_equals", "key": "user.role", "value": "admin" }],
|
|
500
|
+
"value": true
|
|
501
|
+
}
|
|
502
|
+
],
|
|
503
|
+
"default": false
|
|
504
|
+
}
|
|
505
|
+
},
|
|
506
|
+
{
|
|
507
|
+
"label": "Upgrade",
|
|
508
|
+
"href": "/pricing",
|
|
509
|
+
"icon": "sparkles",
|
|
510
|
+
"showWhen": {
|
|
511
|
+
"type": "rules",
|
|
512
|
+
"rules": [
|
|
513
|
+
{
|
|
514
|
+
"conditions": [{ "type": "state_equals", "key": "user.plan", "value": "free" }],
|
|
515
|
+
"value": true
|
|
516
|
+
}
|
|
517
|
+
],
|
|
518
|
+
"default": false
|
|
519
|
+
}
|
|
520
|
+
}
|
|
521
|
+
]
|
|
522
|
+
}
|
|
174
523
|
}
|
|
175
524
|
```
|
|
176
|
-
- **Effect**: Inserts after existing children
|
|
177
|
-
- **Common Use**: Adding badges, icons, supplementary content
|
|
178
|
-
- **Note**: HTML is sanitized for safety
|
|
179
525
|
|
|
180
|
-
|
|
181
|
-
|
|
526
|
+
## Compositional Pattern
|
|
527
|
+
|
|
528
|
+
The nav widget supports **per-item conditional visibility** using `showWhen` strategies. This allows different navigation items to appear based on:
|
|
529
|
+
|
|
530
|
+
- User role or permissions
|
|
531
|
+
- Subscription tier
|
|
532
|
+
- Feature flags
|
|
533
|
+
- Any other DecisionStrategy condition
|
|
534
|
+
|
|
535
|
+
Items without `showWhen` are always visible.
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
---
|
|
539
|
+
|
|
540
|
+
# @syntrologie/adapt-navigation
|
|
541
|
+
|
|
542
|
+
Navigation capabilities for scrolling and URL navigation.
|
|
543
|
+
|
|
544
|
+
## Actions
|
|
545
|
+
|
|
546
|
+
### scroll_to
|
|
547
|
+
|
|
548
|
+
Scrolls the viewport to bring an element into view.
|
|
549
|
+
|
|
550
|
+
| Property | Type | Required | Default | Description |
|
|
551
|
+
| ---------- | ------------- | -------- | ----------- | ------------------------------------------- |
|
|
552
|
+
| `kind` | `"scroll_to"` | Yes | | Action type |
|
|
553
|
+
| `anchorId` | string | Yes | | Element selector |
|
|
554
|
+
| `behavior` | string | No | `"smooth"` | `"smooth"`, `"instant"`, `"auto"` |
|
|
555
|
+
| `block` | string | No | `"center"` | `"start"`, `"center"`, `"end"`, `"nearest"` |
|
|
556
|
+
| `inline` | string | No | `"nearest"` | `"start"`, `"center"`, `"end"`, `"nearest"` |
|
|
557
|
+
|
|
558
|
+
```json
|
|
559
|
+
{
|
|
560
|
+
"kind": "scroll_to",
|
|
561
|
+
"anchorId": "#pricing-section",
|
|
562
|
+
"behavior": "smooth",
|
|
563
|
+
"block": "start"
|
|
564
|
+
}
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### navigate
|
|
568
|
+
|
|
569
|
+
Navigates to a URL.
|
|
570
|
+
|
|
571
|
+
| Property | Type | Required | Default | Description |
|
|
572
|
+
| -------- | ------------ | -------- | --------- | ----------------------- |
|
|
573
|
+
| `kind` | `"navigate"` | Yes | | Action type |
|
|
574
|
+
| `url` | string | Yes | | Destination URL |
|
|
575
|
+
| `target` | string | No | `"_self"` | `"_self"` or `"_blank"` |
|
|
576
|
+
|
|
182
577
|
```json
|
|
183
578
|
{
|
|
184
|
-
"kind": "
|
|
185
|
-
"
|
|
579
|
+
"kind": "navigate",
|
|
580
|
+
"url": "/signup?ref=banner",
|
|
581
|
+
"target": "_self"
|
|
186
582
|
}
|
|
187
583
|
```
|
|
188
|
-
- **Effect**: Inserts before existing children
|
|
189
|
-
- **Common Use**: Adding icons, prefixes, notifications
|
|
190
|
-
- **Note**: HTML is sanitized for safety
|
|
191
584
|
|
|
192
|
-
|
|
193
|
-
|
|
585
|
+
**Note:** `javascript:` URLs are blocked for security.
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
---
|
|
589
|
+
|
|
590
|
+
# @syntrologie/adapt-overlays
|
|
591
|
+
|
|
592
|
+
Visual overlay capabilities including highlights, tooltips, badges, and pulse animations.
|
|
593
|
+
|
|
594
|
+
## Actions
|
|
595
|
+
|
|
596
|
+
### highlight
|
|
597
|
+
|
|
598
|
+
Creates a spotlight effect around an element with a scrim overlay.
|
|
599
|
+
|
|
600
|
+
| Property | Type | Required | Default | Description |
|
|
601
|
+
| -------------------- | ------------- | -------- | ----------- | --------------------------------------- |
|
|
602
|
+
| `kind` | `"highlight"` | Yes | | Action type |
|
|
603
|
+
| `anchorId` | string | Yes | | Element selector |
|
|
604
|
+
| `style.color` | string | No | `"#5b8cff"` | Ring color |
|
|
605
|
+
| `style.scrimOpacity` | number | No | `0.55` | Backdrop opacity 0-1 (set to 0 to hide) |
|
|
606
|
+
| `style.paddingPx` | number | No | `12` | Space around element |
|
|
607
|
+
| `style.radiusPx` | number | No | `12` | Ring corner radius |
|
|
608
|
+
|
|
194
609
|
```json
|
|
195
610
|
{
|
|
196
|
-
"kind": "
|
|
197
|
-
"
|
|
198
|
-
"
|
|
611
|
+
"kind": "highlight",
|
|
612
|
+
"anchorId": "#signup-button",
|
|
613
|
+
"style": {
|
|
614
|
+
"color": "#22c55e",
|
|
615
|
+
"scrimOpacity": 0.4
|
|
616
|
+
}
|
|
199
617
|
}
|
|
200
618
|
```
|
|
201
|
-
- **Positions**:
|
|
202
|
-
- `beforebegin`: Before the element itself
|
|
203
|
-
- `afterbegin`: Inside element, before first child
|
|
204
|
-
- `beforeend`: Inside element, after last child
|
|
205
|
-
- `afterend`: After the element itself
|
|
206
|
-
- **Common Use**: Complex insertions, wrapping elements
|
|
207
|
-
- **Note**: More flexible than append/prepend
|
|
208
619
|
|
|
209
|
-
|
|
620
|
+
### tooltip
|
|
621
|
+
|
|
622
|
+
Shows a tooltip near an element with optional title, body, and CTA.
|
|
210
623
|
|
|
211
|
-
|
|
624
|
+
| Property | Type | Required | Default | Description |
|
|
625
|
+
| -------------------- | ----------- | -------- | ------------- | ----------------------------------- |
|
|
626
|
+
| `kind` | `"tooltip"` | Yes | | Action type |
|
|
627
|
+
| `anchorId` | string | Yes | | Element selector |
|
|
628
|
+
| `content.title` | string | No | | Tooltip heading |
|
|
629
|
+
| `content.body` | string | Yes | | Tooltip text |
|
|
630
|
+
| `content.cta.label` | string | No | | CTA button text |
|
|
631
|
+
| `content.cta.action` | Action | No | | Action to execute on CTA click |
|
|
632
|
+
| `trigger` | string | No | `"immediate"` | `"immediate"`, `"hover"`, `"click"` |
|
|
633
|
+
| `placement` | string | No | `"top"` | See placement options below |
|
|
212
634
|
|
|
213
|
-
|
|
214
|
-
Floating information bubbles that appear near target elements.
|
|
635
|
+
**Placement options:** `top`, `top-start`, `top-end`, `bottom`, `bottom-start`, `bottom-end`, `left`, `left-start`, `left-end`, `right`, `right-start`, `right-end`
|
|
215
636
|
|
|
216
637
|
```json
|
|
217
638
|
{
|
|
218
639
|
"kind": "tooltip",
|
|
219
|
-
"
|
|
220
|
-
"anchor": {
|
|
221
|
-
"by": "css",
|
|
222
|
-
"value": ".pricing-card"
|
|
223
|
-
},
|
|
640
|
+
"anchorId": "#pricing-toggle",
|
|
224
641
|
"content": {
|
|
225
|
-
"title": "
|
|
226
|
-
"body": "
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
"ctaButtons": [
|
|
231
|
-
{
|
|
232
|
-
"label": "Learn More",
|
|
233
|
-
"actionId": "learn_more_click"
|
|
642
|
+
"title": "Save 20%",
|
|
643
|
+
"body": "Switch to annual billing to save on your subscription.",
|
|
644
|
+
"cta": {
|
|
645
|
+
"label": "Switch Now",
|
|
646
|
+
"action": { "kind": "navigate", "url": "/billing?annual=true" }
|
|
234
647
|
}
|
|
235
|
-
|
|
236
|
-
"
|
|
237
|
-
|
|
238
|
-
"closeButton": true
|
|
239
|
-
}
|
|
648
|
+
},
|
|
649
|
+
"placement": "bottom",
|
|
650
|
+
"trigger": "immediate"
|
|
240
651
|
}
|
|
241
652
|
```
|
|
242
653
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
- `ctaButtons`: Array of action buttons (optional)
|
|
254
|
-
- `dismiss.onEsc`: Close on Escape key
|
|
255
|
-
- `dismiss.closeButton`: Show X button
|
|
256
|
-
- `dismiss.timeoutMs`: Auto-dismiss after milliseconds
|
|
257
|
-
|
|
258
|
-
### Highlights
|
|
259
|
-
Visual emphasis rings that draw attention to elements.
|
|
654
|
+
### badge
|
|
655
|
+
|
|
656
|
+
Adds a small badge indicator near an element.
|
|
657
|
+
|
|
658
|
+
| Property | Type | Required | Default | Description |
|
|
659
|
+
| ---------- | --------- | -------- | ------------- | -------------------------------------------------------------- |
|
|
660
|
+
| `kind` | `"badge"` | Yes | | Action type |
|
|
661
|
+
| `anchorId` | string | Yes | | Element selector |
|
|
662
|
+
| `text` | string | Yes | | Badge text (e.g., "NEW", "3") |
|
|
663
|
+
| `position` | string | No | `"top-right"` | `"top-left"`, `"top-right"`, `"bottom-left"`, `"bottom-right"` |
|
|
260
664
|
|
|
261
665
|
```json
|
|
262
666
|
{
|
|
263
|
-
"kind": "
|
|
264
|
-
"
|
|
265
|
-
"
|
|
266
|
-
|
|
267
|
-
"value": ".hero-cta button"
|
|
268
|
-
},
|
|
269
|
-
"copy": "Click here to get started",
|
|
270
|
-
"ring": {
|
|
271
|
-
"paddingPx": 8,
|
|
272
|
-
"radiusPx": 4
|
|
273
|
-
},
|
|
274
|
-
"ringColor": "#3b82f6",
|
|
275
|
-
"scrim": {
|
|
276
|
-
"opacity": 0.5
|
|
277
|
-
},
|
|
278
|
-
"blocking": true,
|
|
279
|
-
"dismiss": {
|
|
280
|
-
"onClickOutside": true,
|
|
281
|
-
"onEsc": true
|
|
282
|
-
}
|
|
667
|
+
"kind": "badge",
|
|
668
|
+
"anchorId": "#inbox-icon",
|
|
669
|
+
"text": "5",
|
|
670
|
+
"position": "top-right"
|
|
283
671
|
}
|
|
284
672
|
```
|
|
285
673
|
|
|
286
|
-
|
|
287
|
-
- `kind`: Must be `"highlight"`
|
|
288
|
-
- `id`: Unique identifier for tracking
|
|
289
|
-
- `anchor`: Element selector (same as patches)
|
|
290
|
-
- `copy`: Text to display near the highlight (optional)
|
|
291
|
-
- `ring.paddingPx`: Space between element and ring
|
|
292
|
-
- `ring.radiusPx`: Corner radius of ring
|
|
293
|
-
- `ringColor`: Color of the highlight ring
|
|
294
|
-
- `scrim.opacity`: Opacity of background dimming (0-1)
|
|
295
|
-
- `blocking`: If true, blocks interaction outside highlight
|
|
296
|
-
- `dismiss.onClickOutside`: Close when clicking outside
|
|
297
|
-
- `dismiss.onEsc`: Close on Escape key
|
|
298
|
-
- `dismiss.timeoutMs`: Auto-dismiss after milliseconds
|
|
674
|
+
### pulse
|
|
299
675
|
|
|
300
|
-
|
|
676
|
+
Adds a pulsing animation to draw attention.
|
|
301
677
|
|
|
302
|
-
|
|
678
|
+
| Property | Type | Required | Default | Description |
|
|
679
|
+
| ---------- | --------- | -------- | ------- | ------------------------ |
|
|
680
|
+
| `kind` | `"pulse"` | Yes | | Action type |
|
|
681
|
+
| `anchorId` | string | Yes | | Element selector |
|
|
682
|
+
| `duration` | number | No | `2000` | Animation duration in ms |
|
|
303
683
|
|
|
304
684
|
```json
|
|
305
685
|
{
|
|
306
|
-
"
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
"routes": ["/dashboard", "/home"],
|
|
310
|
-
"steps": [
|
|
311
|
-
{ "kind": "tooltip", ... },
|
|
312
|
-
{ "kind": "highlight", ... }
|
|
313
|
-
]
|
|
314
|
-
}
|
|
686
|
+
"kind": "pulse",
|
|
687
|
+
"anchorId": ".notification-bell",
|
|
688
|
+
"duration": 3000
|
|
315
689
|
}
|
|
316
690
|
```
|
|
317
691
|
|
|
318
|
-
|
|
319
|
-
- `version`: Version number for tracking changes
|
|
320
|
-
- `routes`: URL paths where this recipe applies (optional)
|
|
321
|
-
- `steps`: Array of tooltip and highlight steps
|
|
692
|
+
### modal
|
|
322
693
|
|
|
323
|
-
|
|
694
|
+
Shows a centered modal dialog with optional CTA buttons.
|
|
324
695
|
|
|
325
|
-
|
|
696
|
+
| Property | Type | Required | Default | Description |
|
|
697
|
+
| --------------------- | ------------------ | -------- | ------- | ------------------------------------------------------------- |
|
|
698
|
+
| `kind` | `"overlays:modal"` | Yes | | Action type |
|
|
699
|
+
| `content.title` | string | No | | Modal heading |
|
|
700
|
+
| `content.body` | string | Yes | | Modal text |
|
|
701
|
+
| `size` | string | No | `"md"` | `"sm"`, `"md"`, `"lg"` |
|
|
702
|
+
| `blocking` | boolean | No | `false` | Block page interaction |
|
|
703
|
+
| `scrim.opacity` | number | No | `0.6` | Backdrop opacity 0-1 |
|
|
704
|
+
| `dismiss.onEsc` | boolean | No | `true` | Close on Escape key |
|
|
705
|
+
| `dismiss.closeButton` | boolean | No | `true` | Show close button |
|
|
706
|
+
| `dismiss.timeoutMs` | number | No | | Auto-close after timeout |
|
|
707
|
+
| `ctaButtons` | array | No | | Array of CTA buttons |
|
|
708
|
+
| `waitFor` | string | No | | When to complete: `"dismissed"`, `"cta-click"`, `"timeout:N"` |
|
|
326
709
|
|
|
327
|
-
|
|
710
|
+
**CTA Button properties:**
|
|
328
711
|
|
|
329
|
-
|
|
712
|
+
- `label`: Button text
|
|
713
|
+
- `actionId`: Identifier for the action
|
|
714
|
+
- `primary`: Whether this is a primary button (default: false)
|
|
330
715
|
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
716
|
+
```json
|
|
717
|
+
{
|
|
718
|
+
"kind": "overlays:modal",
|
|
719
|
+
"content": {
|
|
720
|
+
"title": "Welcome!",
|
|
721
|
+
"body": "Thanks for signing up. Let us show you around."
|
|
722
|
+
},
|
|
723
|
+
"size": "md",
|
|
724
|
+
"ctaButtons": [
|
|
725
|
+
{ "label": "Skip", "actionId": "skip" },
|
|
726
|
+
{ "label": "Start Tour", "actionId": "start", "primary": true }
|
|
727
|
+
],
|
|
728
|
+
"waitFor": "cta-click"
|
|
729
|
+
}
|
|
340
730
|
```
|
|
341
731
|
|
|
342
|
-
### Usage
|
|
343
732
|
|
|
344
|
-
|
|
345
|
-
const { canvas, runtime } = await Syntro.init({
|
|
346
|
-
token: "syn_..."
|
|
347
|
-
});
|
|
733
|
+
---
|
|
348
734
|
|
|
349
|
-
// Access runtime providers
|
|
350
|
-
runtime.telemetry?.trackAction(...);
|
|
351
|
-
runtime.context.subscribe((ctx, prev) => { ... });
|
|
352
|
-
runtime.events.subscribe({ names: ['ui.click'] }, (event) => { ... });
|
|
353
|
-
runtime.state.dismissals.mark('my-tile');
|
|
354
|
-
```
|
|
355
735
|
|
|
356
|
-
|
|
736
|
+
---
|
|
357
737
|
|
|
358
|
-
|
|
738
|
+
## Surfaces
|
|
359
739
|
|
|
360
|
-
|
|
361
|
-
const unsubscribe = runtime.context.subscribe((ctx, prev) => {
|
|
362
|
-
if (ctx.page.url !== prev.page.url) {
|
|
363
|
-
// Handle route change
|
|
364
|
-
}
|
|
365
|
-
});
|
|
740
|
+
Surfaces are named slots where widgets can be mounted. Use the `mount_widget` action to render content into a surface slot.
|
|
366
741
|
|
|
367
|
-
|
|
368
|
-
console.log(ctx.page.url, ctx.session.sessionId);
|
|
369
|
-
```
|
|
742
|
+
### Static Slots
|
|
370
743
|
|
|
371
|
-
|
|
372
|
-
| Field | Type | Description |
|
|
373
|
-
|-------|------|-------------|
|
|
374
|
-
| `page.url` | string | Current page URL |
|
|
375
|
-
| `page.routeId` | string? | Matched route pattern |
|
|
376
|
-
| `page.title` | string? | Document title |
|
|
377
|
-
| `session.sessionId` | string | PostHog session ID |
|
|
378
|
-
| `session.startTs` | number | Session start timestamp |
|
|
379
|
-
| `viewport.width` | number | Viewport width in pixels |
|
|
380
|
-
| `viewport.height` | number | Viewport height in pixels |
|
|
381
|
-
| `anchors` | AnchorState[]? | Tracked anchor visibility |
|
|
382
|
-
|
|
383
|
-
### Event Bus
|
|
384
|
-
|
|
385
|
-
Subscribe to normalized events:
|
|
386
|
-
|
|
387
|
-
```typescript
|
|
388
|
-
const unsubscribe = runtime.events.subscribe(
|
|
389
|
-
{ names: ["ui.click", "nav.page_view"] },
|
|
390
|
-
(event) => {
|
|
391
|
-
console.log(event.name, event.props);
|
|
392
|
-
}
|
|
393
|
-
);
|
|
394
|
-
```
|
|
744
|
+
Fixed-position slots for common UI patterns:
|
|
395
745
|
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
746
|
+
| Slot | Position | Use Case |
|
|
747
|
+
|------|----------|----------|
|
|
748
|
+
| `drawer_right` | Right edge, full height | Settings panels, details |
|
|
749
|
+
| `drawer_left` | Left edge, full height | Navigation, filters |
|
|
750
|
+
| `drawer_bottom` | Bottom edge, full width | Action sheets, keyboards |
|
|
751
|
+
| `overlay_center` | Centered modal | Dialogs, confirmations |
|
|
752
|
+
| `overlay_corner_br` | Bottom-right corner | Chat widgets, help |
|
|
753
|
+
| `overlay_corner_bl` | Bottom-left corner | Notifications |
|
|
754
|
+
| `toast_top` | Top center | Success/error messages |
|
|
755
|
+
| `toast_bottom` | Bottom center | Snackbar notifications |
|
|
406
756
|
|
|
407
|
-
|
|
408
|
-
| Event | Source | Description |
|
|
409
|
-
|-------|--------|-------------|
|
|
410
|
-
| `ui.click` | posthog | User clicked element |
|
|
411
|
-
| `ui.scroll` | posthog | User scrolled |
|
|
412
|
-
| `nav.page_view` | posthog | Page navigation |
|
|
413
|
-
| `canvas.opened` | canvas | Smart Canvas opened |
|
|
414
|
-
| `canvas.closed` | canvas | Smart Canvas closed |
|
|
415
|
-
| `tile.viewed` | canvas | Tile became visible |
|
|
416
|
-
| `tile.action` | canvas | User clicked tile action |
|
|
757
|
+
### Dynamic Slots
|
|
417
758
|
|
|
418
|
-
|
|
759
|
+
Slots that position content relative to anchors:
|
|
419
760
|
|
|
420
|
-
|
|
761
|
+
- **Inline Slots**: Render content inside an anchor element. Format: `inline:{anchorId}`
|
|
762
|
+
- **Adjacent Slots**: Render content positioned near an anchor element. Format: `adjacent:{anchorId}`
|
|
421
763
|
|
|
422
|
-
|
|
423
|
-
// Session storage (cleared on close)
|
|
424
|
-
runtime.state.session.set("lastTileViewed", "tile-123");
|
|
425
|
-
const last = runtime.state.session.get<string>("lastTileViewed");
|
|
764
|
+
---
|
|
426
765
|
|
|
427
|
-
|
|
428
|
-
runtime.state.user.set("onboardingComplete", true);
|
|
766
|
+
## Anchor Resolution
|
|
429
767
|
|
|
430
|
-
|
|
431
|
-
const ns = runtime.state.ns("my-adaptive");
|
|
432
|
-
ns.session.set("step", 3);
|
|
433
|
-
```
|
|
768
|
+
The `anchorId` field identifies which DOM element to target. Multiple formats are supported:
|
|
434
769
|
|
|
435
|
-
|
|
436
|
-
```typescript
|
|
437
|
-
// Track dismissals
|
|
438
|
-
runtime.state.dismissals.mark("tooltip-1");
|
|
439
|
-
if (runtime.state.dismissals.isDismissed("tooltip-1")) { ... }
|
|
770
|
+
### CSS Selectors
|
|
440
771
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
772
|
+
| Format | Example | Matches |
|
|
773
|
+
|--------|---------|---------|
|
|
774
|
+
| Class | `".hero-title"` | `<h1 class="hero-title">` |
|
|
775
|
+
| ID | `"#signup-button"` | `<button id="signup-button">` |
|
|
776
|
+
| Attribute | `"[data-testid='cta']"` | `<button data-testid="cta">` |
|
|
777
|
+
| Tag + class | `"h1.page-title"` | `<h1 class="page-title">` |
|
|
778
|
+
| Nested | `".card .title"` | `<div class="title">` inside `.card` |
|
|
444
779
|
|
|
445
|
-
|
|
446
|
-
runtime.state.frequency.increment("upsell-shown");
|
|
447
|
-
if (runtime.state.frequency.count("upsell-shown") >= 3) { ... }
|
|
448
|
-
```
|
|
780
|
+
### Data Attributes (Recommended)
|
|
449
781
|
|
|
450
|
-
|
|
782
|
+
For stability, add `data-syntro-anchor` attributes to target elements:
|
|
451
783
|
|
|
452
|
-
|
|
784
|
+
```html
|
|
785
|
+
<h1 data-syntro-anchor="hero-title">Welcome</h1>
|
|
786
|
+
```
|
|
787
|
+
|
|
788
|
+
Then reference by the anchor name:
|
|
453
789
|
|
|
454
790
|
```json
|
|
455
|
-
{
|
|
456
|
-
"id": "promo-tile",
|
|
457
|
-
"title": "Limited Offer",
|
|
458
|
-
"activation": {
|
|
459
|
-
"routes": { "include": ["/pricing", "/upgrade"] },
|
|
460
|
-
"strategy": {
|
|
461
|
-
"type": "rules",
|
|
462
|
-
"rules": [
|
|
463
|
-
{
|
|
464
|
-
"conditions": [
|
|
465
|
-
{ "type": "viewport", "minWidth": 768 },
|
|
466
|
-
{ "type": "dismissed", "key": "promo-tile", "inverted": true }
|
|
467
|
-
],
|
|
468
|
-
"value": true
|
|
469
|
-
}
|
|
470
|
-
],
|
|
471
|
-
"default": false
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
791
|
+
{ "anchorId": "hero-title" }
|
|
475
792
|
```
|
|
476
793
|
|
|
477
|
-
|
|
478
|
-
| Type | Description |
|
|
479
|
-
|------|-------------|
|
|
480
|
-
| `rules` | Condition-based matching (if/then) |
|
|
481
|
-
| `score` | Threshold on augmented field |
|
|
482
|
-
| `model` | ML model prediction (future) |
|
|
483
|
-
| `external` | Remote decision endpoint (future) |
|
|
484
|
-
|
|
485
|
-
**Condition Types:**
|
|
486
|
-
| Condition | Parameters | Description |
|
|
487
|
-
|-----------|------------|-------------|
|
|
488
|
-
| `page_url` | `url` (pattern) | URL matches pattern |
|
|
489
|
-
| `route` | `routeId` | Route ID matches |
|
|
490
|
-
| `anchor_visible` | `anchorId`, `state` | Anchor visibility state |
|
|
491
|
-
| `event_occurred` | `eventName`, `withinMs?` | Event happened recently |
|
|
492
|
-
| `state_equals` | `key`, `value` | State value matches |
|
|
493
|
-
| `viewport` | `minWidth?`, `maxWidth?` | Viewport size range |
|
|
494
|
-
| `session_metric` | `key`, `operator`, `threshold` | Session metric comparison |
|
|
495
|
-
| `dismissed` | `key`, `inverted?` | Item has been dismissed |
|
|
496
|
-
| `cooldown_active` | `key`, `inverted?` | Cooldown is active |
|
|
497
|
-
| `frequency_limit` | `key`, `limit`, `inverted?` | Frequency cap reached |
|
|
794
|
+
---
|
|
498
795
|
|
|
499
|
-
|
|
796
|
+
## Decision Strategies
|
|
500
797
|
|
|
501
|
-
|
|
798
|
+
Control when adaptives activate using `DecisionStrategy`:
|
|
502
799
|
|
|
503
|
-
|
|
504
|
-
```json
|
|
505
|
-
{
|
|
506
|
-
"experiment": {
|
|
507
|
-
"featureKey": "my-feature",
|
|
508
|
-
"variationId": 1
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
```
|
|
800
|
+
### Rules Strategy
|
|
512
801
|
|
|
513
|
-
**After (v2):**
|
|
514
802
|
```json
|
|
515
803
|
{
|
|
516
|
-
"
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
"
|
|
520
|
-
{
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
],
|
|
524
|
-
"value": true
|
|
525
|
-
}
|
|
804
|
+
"type": "rules",
|
|
805
|
+
"rules": [
|
|
806
|
+
{
|
|
807
|
+
"conditions": [
|
|
808
|
+
{ "type": "page_url", "pattern": "/pricing*" },
|
|
809
|
+
{ "type": "viewport", "minWidth": 768 },
|
|
810
|
+
{ "type": "dismissed", "key": "promo", "inverted": true }
|
|
526
811
|
],
|
|
527
|
-
"
|
|
812
|
+
"value": true
|
|
528
813
|
}
|
|
529
|
-
|
|
814
|
+
],
|
|
815
|
+
"default": false
|
|
530
816
|
}
|
|
531
817
|
```
|
|
532
818
|
|
|
819
|
+
### Condition Types
|
|
820
|
+
|
|
821
|
+
| Type | Parameters | Description |
|
|
822
|
+
|------|------------|-------------|
|
|
823
|
+
| `page_url` | `pattern` | URL matches glob pattern |
|
|
824
|
+
| `route` | `routeId` | Route ID matches |
|
|
825
|
+
| `anchor_visible` | `anchorId`, `state` | Anchor visibility |
|
|
826
|
+
| `event_occurred` | `eventName`, `withinMs?` | Recent event |
|
|
827
|
+
| `state_equals` | `key`, `value` | State matches |
|
|
828
|
+
| `viewport` | `minWidth?`, `maxWidth?`, `minHeight?`, `maxHeight?` | Viewport size |
|
|
829
|
+
| `session_metric` | `key`, `operator`, `threshold` | Metric comparison |
|
|
830
|
+
| `dismissed` | `key`, `inverted?` | Dismissal check |
|
|
831
|
+
| `cooldown_active` | `key`, `inverted?` | Cooldown check |
|
|
832
|
+
| `frequency_limit` | `key`, `limit`, `inverted?` | Frequency cap |
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
533
836
|
## Best Practices
|
|
534
837
|
|
|
535
|
-
### 1.
|
|
536
|
-
- Use the most specific selector that won't break
|
|
537
|
-
- Prefer data attributes over classes for stability
|
|
538
|
-
- Test selectors across different page states
|
|
838
|
+
### 1. Choose the Right Action Type
|
|
539
839
|
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
840
|
+
| Goal | Action |
|
|
841
|
+
|------|--------|
|
|
842
|
+
| Change text | `set_text` |
|
|
843
|
+
| Add visual indicator | `badge`, `pulse` |
|
|
844
|
+
| Show help text | `tooltip` |
|
|
845
|
+
| Draw attention | `highlight` |
|
|
846
|
+
| Add content | `insert_html` |
|
|
847
|
+
| Navigate user | `scroll_to`, `navigate` |
|
|
848
|
+
| Show UI panel | `mount_widget` + Surfaces |
|
|
544
849
|
|
|
545
|
-
###
|
|
546
|
-
- Operations are applied in array order
|
|
547
|
-
- Plan sequences carefully (e.g., addClass before setStyle)
|
|
548
|
-
- Test operation combinations
|
|
850
|
+
### 2. Anchor Selection
|
|
549
851
|
|
|
550
|
-
|
|
551
|
-
-
|
|
552
|
-
- Avoid
|
|
553
|
-
- Use CSS classes instead of inline styles when possible
|
|
852
|
+
- **Prefer stable selectors:** `[data-testid]`, IDs over classes
|
|
853
|
+
- **Test across states:** Element may not exist on all pages
|
|
854
|
+
- **Be specific:** Avoid selectors matching multiple elements
|
|
554
855
|
|
|
555
|
-
###
|
|
556
|
-
- All HTML is sanitized to prevent XSS
|
|
557
|
-
- Classes must be prefixed to avoid conflicts
|
|
558
|
-
- Test across different browsers and devices
|
|
856
|
+
### 3. Reversibility
|
|
559
857
|
|
|
560
|
-
|
|
858
|
+
- Always store handles if you need to revert
|
|
859
|
+
- Use `applyBatch` for related changes (atomic rollback)
|
|
860
|
+
- Clean up on route changes
|
|
561
861
|
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
"by": "css",
|
|
570
|
-
"value": "h1.hero-title"
|
|
571
|
-
},
|
|
572
|
-
"tier": "surgical",
|
|
573
|
-
"operations": [
|
|
574
|
-
{
|
|
575
|
-
"kind": "setText",
|
|
576
|
-
"text": "Start Your Free Trial Today"
|
|
577
|
-
},
|
|
578
|
-
{
|
|
579
|
-
"kind": "addClass",
|
|
580
|
-
"className": "syntro-tested"
|
|
581
|
-
}
|
|
582
|
-
]
|
|
583
|
-
},
|
|
584
|
-
{
|
|
585
|
-
"id": "cta_enhancement",
|
|
586
|
-
"anchor": {
|
|
587
|
-
"by": "data",
|
|
588
|
-
"key": "testid",
|
|
589
|
-
"value": "primary-cta"
|
|
590
|
-
},
|
|
591
|
-
"tier": "additive",
|
|
592
|
-
"operations": [
|
|
593
|
-
{
|
|
594
|
-
"kind": "setStyle",
|
|
595
|
-
"prop": "boxShadow",
|
|
596
|
-
"value": "0 4px 6px rgba(0,0,0,0.1)"
|
|
597
|
-
},
|
|
598
|
-
{
|
|
599
|
-
"kind": "append",
|
|
600
|
-
"html": "<span class='syntro-arrow'>→</span>"
|
|
601
|
-
}
|
|
602
|
-
]
|
|
603
|
-
}
|
|
604
|
-
]
|
|
605
|
-
}
|
|
606
|
-
```
|
|
862
|
+
### 4. Performance
|
|
863
|
+
|
|
864
|
+
- Batch related actions together
|
|
865
|
+
- Use `validate()` to check actions before applying
|
|
866
|
+
- Avoid applying many actions simultaneously
|
|
867
|
+
|
|
868
|
+
### 5. Events
|
|
607
869
|
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
3. Properly tracks both changes with IDs
|
|
870
|
+
- Listen for `action.failed` to handle errors
|
|
871
|
+
- Track `action.applied` for analytics
|
|
872
|
+
- Use EventBus for cross-adaptive coordination
|