@syntrologie/runtime-sdk 2.8.0-canary.6 → 2.8.0-canary.61

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 (55) hide show
  1. package/CAPABILITIES.md +299 -167
  2. package/README.md +2 -0
  3. package/dist/actions/schema.d.ts +7 -7
  4. package/dist/actions/schema.js +2 -2
  5. package/dist/actions/types.d.ts +1 -1
  6. package/dist/actions/validation-core.d.ts +24 -0
  7. package/dist/actions/validation-rules.d.ts +74 -0
  8. package/dist/actions/validation.d.ts +5 -11
  9. package/dist/bootstrap-init.d.ts +33 -0
  10. package/dist/bootstrap-runtime.d.ts +7 -0
  11. package/dist/bootstrap-types.d.ts +90 -0
  12. package/dist/bootstrap.d.ts +19 -83
  13. package/dist/{chunk-R5DNAIRI.js → chunk-AFMDOOJM.js} +3 -3
  14. package/dist/{chunk-R5DNAIRI.js.map → chunk-AFMDOOJM.js.map} +2 -2
  15. package/dist/{chunk-EXRH5KVA.js → chunk-CF2LQFAZ.js} +1680 -637
  16. package/dist/chunk-CF2LQFAZ.js.map +7 -0
  17. package/dist/{chunk-XDYJ64IN.js → chunk-GSVTS2KH.js} +3 -3
  18. package/dist/chunk-GSVTS2KH.js.map +7 -0
  19. package/dist/components/ShadowCanvasOverlay.d.ts +1 -2
  20. package/dist/components/TileIcon.d.ts +2 -2
  21. package/dist/components/emojiToIcon.d.ts +24 -0
  22. package/dist/config/schema.d.ts +27 -16
  23. package/dist/config/schema.js +1 -1
  24. package/dist/events/EventBus.d.ts +27 -1
  25. package/dist/events/history.d.ts +9 -0
  26. package/dist/events/index.d.ts +3 -0
  27. package/dist/events/normalizers/posthog.d.ts +4 -50
  28. package/dist/events/types.d.ts +30 -23
  29. package/dist/events/validation.d.ts +7 -0
  30. package/dist/index.d.ts +0 -2
  31. package/dist/index.js +1528 -211
  32. package/dist/index.js.map +4 -4
  33. package/dist/overlays/runtime/overlay/overlay-runner.d.ts +4 -0
  34. package/dist/overlays/runtime/overlay/overlay-state.d.ts +21 -0
  35. package/dist/overlays/types.d.ts +3 -1
  36. package/dist/react.js +5 -3
  37. package/dist/react.js.map +2 -2
  38. package/dist/smart-canvas.esm.js +115 -65
  39. package/dist/smart-canvas.esm.js.map +4 -4
  40. package/dist/smart-canvas.js +5796 -3012
  41. package/dist/smart-canvas.js.map +4 -4
  42. package/dist/smart-canvas.min.js +115 -65
  43. package/dist/smart-canvas.min.js.map +4 -4
  44. package/dist/telemetry/InterventionTracker.d.ts +23 -0
  45. package/dist/telemetry/adapters/posthog.d.ts +30 -4
  46. package/dist/telemetry/index.d.ts +1 -0
  47. package/dist/test/setup.d.ts +1 -0
  48. package/dist/token.d.ts +2 -0
  49. package/dist/version.d.ts +1 -1
  50. package/package.json +23 -28
  51. package/schema/canvas-config.schema.json +104 -6
  52. package/scripts/syntroReactPlugin.mjs +3 -0
  53. package/scripts/validate-config.mjs +42 -0
  54. package/dist/chunk-EXRH5KVA.js.map +0 -7
  55. package/dist/chunk-XDYJ64IN.js.map +0 -7
package/CAPABILITIES.md CHANGED
@@ -54,8 +54,8 @@ Change a page header when the element is visible:
54
54
  },
55
55
  "actions": [
56
56
  {
57
- "kind": "set_text",
58
- "anchorId": "h1.hero-title",
57
+ "kind": "content:setText",
58
+ "anchorId": { "selector": "h1.hero-title", "route": "/" },
59
59
  "text": "Welcome to Our New Experience"
60
60
  }
61
61
  ]
@@ -160,62 +160,73 @@ The widget reads auth credentials from the browser:
160
160
 
161
161
  DOM content modification capabilities for text, attributes, styles, HTML, and classes.
162
162
 
163
+ ## When to use
164
+
165
+ | Goal | Action |
166
+ |------|--------|
167
+ | Replace an element's text | `content:setText` |
168
+ | Change an HTML attribute (href, src, data-*) | `content:setAttr` |
169
+ | Modify inline styles (color, size, spacing) | `content:setStyle` |
170
+ | Inject new HTML before/after/inside an element | `content:insertHtml` |
171
+ | Add a CSS class (show/hide, animate) | `content:addClass` |
172
+ | Remove a CSS class | `content:removeClass` |
173
+
163
174
  ## Actions
164
175
 
165
- ### set_text
176
+ ### content:setText
166
177
 
167
178
  Replaces the text content of an element.
168
179
 
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 |
180
+ | Property | Type | Required | Description |
181
+ | ---------- | ------------------- | -------- | ---------------- |
182
+ | `kind` | `"content:setText"` | Yes | Action type |
183
+ | `anchorId` | object | Yes | `{ selector, route }` |
184
+ | `text` | string | Yes | New text content |
174
185
 
175
186
  ```json
176
187
  {
177
- "kind": "set_text",
178
- "anchorId": "h1.hero-title",
188
+ "kind": "content:setText",
189
+ "anchorId": { "selector": "h1.hero-title", "route": "/" },
179
190
  "text": "Start Your Free Trial Today"
180
191
  }
181
192
  ```
182
193
 
183
- ### set_attr
194
+ ### content:setAttr
184
195
 
185
196
  Sets an HTML attribute on an element.
186
197
 
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 |
198
+ | Property | Type | Required | Description |
199
+ | ---------- | ------------------- | -------- | ---------------- |
200
+ | `kind` | `"content:setAttr"` | Yes | Action type |
201
+ | `anchorId` | object | Yes | `{ selector, route }` |
202
+ | `attr` | string | Yes | Attribute name |
203
+ | `value` | string | Yes | Attribute value |
193
204
 
194
205
  **Blocked attributes:** Event handlers (`onclick`, `onerror`, etc.) are not allowed.
195
206
 
196
207
  ```json
197
208
  {
198
- "kind": "set_attr",
199
- "anchorId": "#signup-form",
209
+ "kind": "content:setAttr",
210
+ "anchorId": { "selector": "#signup-form", "route": "/" },
200
211
  "attr": "data-experiment",
201
212
  "value": "signup-v2"
202
213
  }
203
214
  ```
204
215
 
205
- ### set_style
216
+ ### content:setStyle
206
217
 
207
218
  Sets inline CSS styles on an element.
208
219
 
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 |
220
+ | Property | Type | Required | Description |
221
+ | ---------- | -------------------- | -------- | ------------------------ |
222
+ | `kind` | `"content:setStyle"` | Yes | Action type |
223
+ | `anchorId` | object | Yes | `{ selector, route }` |
224
+ | `styles` | object | Yes | CSS property/value pairs |
214
225
 
215
226
  ```json
216
227
  {
217
- "kind": "set_style",
218
- "anchorId": ".hero-section",
228
+ "kind": "content:setStyle",
229
+ "anchorId": { "selector": ".hero-section", "route": "/" },
219
230
  "styles": {
220
231
  "background-color": "#1e40af",
221
232
  "padding": "2rem"
@@ -223,16 +234,17 @@ Sets inline CSS styles on an element.
223
234
  }
224
235
  ```
225
236
 
226
- ### insert_html
237
+ ### content:insertHtml
227
238
 
228
239
  Inserts HTML content relative to an element.
229
240
 
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"` |
241
+ | Property | Type | Required | Description |
242
+ | ---------- | --------------------- | -------- | ----------------------------------------------------------- |
243
+ | `kind` | `"content:insertHtml"` | Yes | Action type |
244
+ | `anchorId` | object | Yes | `{ selector, route }` |
245
+ | `html` | string | Yes | HTML content (sanitized) |
246
+ | `position` | string | Yes | `"before"`, `"after"`, `"prepend"`, `"append"`, `"replace"` |
247
+ | `deepLink` | object | No | Makes the entire inserted element clickable to open the canvas panel and navigate to a specific tile |
236
248
 
237
249
  **Positions:**
238
250
 
@@ -244,45 +256,66 @@ Inserts HTML content relative to an element.
244
256
 
245
257
  ```json
246
258
  {
247
- "kind": "insert_html",
248
- "anchorId": ".cta-button",
259
+ "kind": "content:insertHtml",
260
+ "anchorId": { "selector": ".cta-button", "route": "/" },
249
261
  "html": "<span class=\"badge\">NEW</span>",
250
262
  "position": "append"
251
263
  }
252
264
  ```
253
265
 
254
- ### add_class
266
+ **Deep-linking to canvas tiles:**
267
+
268
+ Use `deepLink` to make inserted content open the canvas panel and navigate to a specific tile when clicked. This is the correct way to connect inserted buttons/links to canvas tiles — do NOT use `onclick` handlers with `window.SynOS`.
269
+
270
+ | Property | Type | Required | Description |
271
+ | ---------------- | ------ | -------- | ---------------------------------- |
272
+ | `deepLink.tileId` | string | Yes | ID of the tile to open |
273
+ | `deepLink.itemId` | string | No | Specific item within the tile |
274
+
275
+ ```json
276
+ {
277
+ "kind": "content:insertHtml",
278
+ "anchorId": { "selector": "[data-id='pricing-heading']", "route": "/" },
279
+ "html": "<button style='background: #4a90e2; color: white; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;'>Help Me Choose</button>",
280
+ "position": "after",
281
+ "deepLink": { "tileId": "plan_selector_faq" }
282
+ }
283
+ ```
284
+
285
+ The SDK automatically handles opening the canvas, setting the cursor to pointer, and publishing a `notification.deep_link` event. The click handler is wired up and cleaned up by the SDK — no JavaScript in the HTML is needed.
286
+
287
+ ### content:addClass
255
288
 
256
289
  Adds a CSS class to an element.
257
290
 
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 |
291
+ | Property | Type | Required | Description |
292
+ | ----------- | -------------------- | -------- | ----------------- |
293
+ | `kind` | `"content:addClass"` | Yes | Action type |
294
+ | `anchorId` | object | Yes | `{ selector, route }` |
295
+ | `className` | string | Yes | Class name to add |
263
296
 
264
297
  ```json
265
298
  {
266
- "kind": "add_class",
267
- "anchorId": ".pricing-card",
299
+ "kind": "content:addClass",
300
+ "anchorId": { "selector": ".pricing-card", "route": "/pricing" },
268
301
  "className": "highlighted"
269
302
  }
270
303
  ```
271
304
 
272
- ### remove_class
305
+ ### content:removeClass
273
306
 
274
307
  Removes a CSS class from an element.
275
308
 
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 |
309
+ | Property | Type | Required | Description |
310
+ | ----------- | ----------------------- | -------- | -------------------- |
311
+ | `kind` | `"content:removeClass"` | Yes | Action type |
312
+ | `anchorId` | object | Yes | `{ selector, route }` |
313
+ | `className` | string | Yes | Class name to remove |
281
314
 
282
315
  ```json
283
316
  {
284
- "kind": "remove_class",
285
- "anchorId": ".pricing-card",
317
+ "kind": "content:removeClass",
318
+ "anchorId": { "selector": ".pricing-card", "route": "/pricing" },
286
319
  "className": "hidden"
287
320
  }
288
321
  ```
@@ -294,24 +327,50 @@ Removes a CSS class from an element.
294
327
 
295
328
  Collapsible Q&A accordion with actions, rich content, feedback, and personalization.
296
329
 
297
- ## Actions
330
+ ## When to use
331
+
332
+ | Goal | Action |
333
+ |------|--------|
334
+ | Add an FAQ accordion widget | Add a **tile** in `tiles[]` with `widget: "adaptive-faq:accordion"` |
335
+ | Scroll to and expand a specific FAQ item | `faq:scroll_to` |
336
+ | Open, close, or toggle a FAQ item | `faq:toggle_item` |
337
+ | Add, remove, reorder, or replace FAQ items | `faq:update` |
338
+
339
+ ## Mounting an FAQ Widget
340
+
341
+ FAQ widgets are mounted via **tiles** (not actions). Add an entry to the `tiles[]` array in the config:
298
342
 
299
- ### mount_faq
343
+ ```json
344
+ {
345
+ "tiles": [
346
+ {
347
+ "id": "my-faq",
348
+ "title": "Frequently Asked Questions",
349
+ "content": {
350
+ "type": "custom",
351
+ "component": "adaptive-faq:accordion",
352
+ "props": {
353
+ "expandBehavior": "single",
354
+ "searchable": true,
355
+ "items": [ ... ]
356
+ }
357
+ }
358
+ }
359
+ ]
360
+ }
361
+ ```
300
362
 
301
- Mounts an FAQ accordion widget to a surface slot.
363
+ ### Tile Props
302
364
 
303
365
  | Property | Type | Required | Description |
304
366
  | ----------------------- | --------------------------------- | -------- | ------------------------------------------------------------------- |
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.expandBehavior` | `"single"` \| `"multiple"` | No | Whether one or many items can be open at once (default: `"single"`) |
309
- | `config.searchable` | boolean | No | Show a search/filter input (default: `false`) |
310
- | `config.theme` | `"light"` \| `"dark"` \| `"auto"` | No | Color theme (default: `"auto"`) |
311
- | `config.items` | array | Yes | FAQ items (see below) |
312
- | `config.feedback` | boolean \| FeedbackConfig | No | Enable per-item feedback widget |
313
- | `config.ordering` | OrderingStrategy | No | Item ordering strategy (default: `"static"`) |
314
- | `config.injections` | InjectionRule[] | No | Dynamic item injection rules |
367
+ | `expandBehavior` | `"single"` \| `"multiple"` | No | Whether one or many items can be open at once (default: `"single"`) |
368
+ | `searchable` | boolean | No | Show a search/filter input (default: `false`) |
369
+ | `theme` | `"light"` \| `"dark"` \| `"auto"` | No | Color theme (default: `"auto"`) |
370
+ | `items` | array | Yes | FAQ items (see below) |
371
+ | `feedback` | boolean \| FeedbackConfig | No | Enable per-item feedback widget |
372
+ | `ordering` | OrderingStrategy | No | Item ordering strategy (default: `"static"`) |
373
+ | `injections` | InjectionRule[] | No | Dynamic item injection rules |
315
374
 
316
375
  ### FAQ Item Schema
317
376
 
@@ -326,65 +385,63 @@ Each item in the `items` array:
326
385
  | `config.category` | string | No | Category for grouping items |
327
386
  | `config.priority` | number | No | Priority weight for ordering |
328
387
  | `config.answerStrategy` | AnswerStrategy | No | AI-generated answer configuration |
329
- | `showWhen` | DecisionStrategy \| null | No | Conditional visibility strategy |
388
+ | `triggerWhen` | DecisionStrategy \| null | No | Conditional visibility strategy |
389
+
390
+ **Full tile example with FAQ items:**
330
391
 
331
392
  ```json
332
393
  {
333
- "kind": "mount_faq",
334
- "slot": "drawer_right",
335
- "config": {
336
- "title": "Frequently Asked Questions",
337
- "expandBehavior": "single",
338
- "searchable": true,
339
- "theme": "auto",
340
- "feedback": {
341
- "style": "thumbs",
342
- "prompt": "Was this helpful?"
343
- },
344
- "ordering": "priority",
345
- "items": [
346
- {
347
- "kind": "faq:question",
348
- "config": {
349
- "id": "getting-started",
350
- "question": "How do I get started?",
351
- "answer": "Sign up for a free account and follow our quickstart guide.",
352
- "category": "General",
353
- "priority": 10
354
- }
355
- },
356
- {
357
- "kind": "faq:question",
358
- "config": {
359
- "id": "payment-methods",
360
- "question": "What payment methods do you accept?",
361
- "answer": "We accept all major credit cards and PayPal.",
362
- "category": "Billing",
363
- "priority": 5
364
- },
365
- "showWhen": {
366
- "type": "rules",
367
- "rules": [
394
+ "tiles": [
395
+ {
396
+ "id": "help-faq",
397
+ "title": "Frequently Asked Questions",
398
+ "content": {
399
+ "type": "custom",
400
+ "component": "adaptive-faq:accordion",
401
+ "props": {
402
+ "expandBehavior": "single",
403
+ "searchable": true,
404
+ "feedback": {
405
+ "style": "thumbs",
406
+ "prompt": "Was this helpful?"
407
+ },
408
+ "ordering": "priority",
409
+ "items": [
368
410
  {
369
- "conditions": [{ "type": "page_url", "pattern": "/pricing*" }],
370
- "value": true
411
+ "kind": "faq:question",
412
+ "config": {
413
+ "id": "getting-started",
414
+ "question": "How do I get started?",
415
+ "answer": "Sign up for a free account and follow our quickstart guide.",
416
+ "category": "General",
417
+ "priority": 10
418
+ }
419
+ },
420
+ {
421
+ "kind": "faq:question",
422
+ "config": {
423
+ "id": "payment-methods",
424
+ "question": "What payment methods do you accept?",
425
+ "answer": "We accept all major credit cards and PayPal.",
426
+ "category": "Billing",
427
+ "priority": 5
428
+ }
371
429
  }
372
- ],
373
- "default": false
430
+ ]
374
431
  }
375
432
  }
376
- ]
377
- }
433
+ }
434
+ ]
378
435
  }
379
436
  ```
380
437
 
381
- ### scroll_to_faq
438
+ ### faq:scroll_to
382
439
 
383
440
  Scrolls the viewport to a specific FAQ item and optionally expands it.
384
441
 
385
442
  | Property | Type | Required | Default | Description |
386
443
  | -------------- | ----------------- | -------- | ---------- | ------------------------------------------ |
387
- | `kind` | `"scroll_to_faq"` | Yes | | Action type |
444
+ | `kind` | `"faq:scroll_to"` | Yes | | Action type |
388
445
  | `itemId` | string | No\* | | Target item ID |
389
446
  | `itemQuestion` | string | No\* | | Target item question text (fuzzy match) |
390
447
  | `expand` | boolean | No | `true` | Whether to expand the item after scrolling |
@@ -394,20 +451,20 @@ Scrolls the viewport to a specific FAQ item and optionally expands it.
394
451
 
395
452
  ```json
396
453
  {
397
- "kind": "scroll_to_faq",
454
+ "kind": "faq:scroll_to",
398
455
  "itemId": "payment-methods",
399
456
  "expand": true,
400
457
  "behavior": "smooth"
401
458
  }
402
459
  ```
403
460
 
404
- ### toggle_faq_item
461
+ ### faq:toggle_item
405
462
 
406
463
  Opens, closes, or toggles a FAQ item's expanded state.
407
464
 
408
465
  | Property | Type | Required | Default | Description |
409
466
  | -------------- | ------------------- | -------- | ---------- | --------------------------------------- |
410
- | `kind` | `"toggle_faq_item"` | Yes | | Action type |
467
+ | `kind` | `"faq:toggle_item"` | Yes | | Action type |
411
468
  | `itemId` | string | No\* | | Target item ID |
412
469
  | `itemQuestion` | string | No\* | | Target item question text (fuzzy match) |
413
470
  | `state` | string | No | `"toggle"` | `"open"`, `"closed"`, `"toggle"` |
@@ -416,19 +473,19 @@ Opens, closes, or toggles a FAQ item's expanded state.
416
473
 
417
474
  ```json
418
475
  {
419
- "kind": "toggle_faq_item",
476
+ "kind": "faq:toggle_item",
420
477
  "itemId": "getting-started",
421
478
  "state": "open"
422
479
  }
423
480
  ```
424
481
 
425
- ### update_faq
482
+ ### faq:update
426
483
 
427
484
  Dynamically adds, removes, reorders, or replaces FAQ items at runtime.
428
485
 
429
486
  | Property | Type | Required | Description |
430
487
  | ----------- | ------------------- | -------- | ------------------------------------------------------- |
431
- | `kind` | `"update_faq"` | Yes | Action type |
488
+ | `kind` | `"faq:update"` | Yes | Action type |
432
489
  | `operation` | string | Yes | `"add"`, `"remove"`, `"reorder"`, `"replace"` |
433
490
  | `items` | FAQQuestionAction[] | No | Items to add or replace with (required for add/replace) |
434
491
  | `itemId` | string | No | Item to remove (required for remove) |
@@ -440,7 +497,7 @@ Dynamically adds, removes, reorders, or replaces FAQ items at runtime.
440
497
 
441
498
  ```json
442
499
  {
443
- "kind": "update_faq",
500
+ "kind": "faq:update",
444
501
  "operation": "add",
445
502
  "position": "append",
446
503
  "items": [
@@ -460,7 +517,7 @@ Dynamically adds, removes, reorders, or replaces FAQ items at runtime.
460
517
 
461
518
  ```json
462
519
  {
463
- "kind": "update_faq",
520
+ "kind": "faq:update",
464
521
  "operation": "remove",
465
522
  "itemId": "outdated-question"
466
523
  }
@@ -470,7 +527,7 @@ Dynamically adds, removes, reorders, or replaces FAQ items at runtime.
470
527
 
471
528
  ```json
472
529
  {
473
- "kind": "update_faq",
530
+ "kind": "faq:update",
474
531
  "operation": "reorder",
475
532
  "order": ["getting-started", "new-feature", "payment-methods"]
476
533
  }
@@ -480,7 +537,7 @@ Dynamically adds, removes, reorders, or replaces FAQ items at runtime.
480
537
 
481
538
  ```json
482
539
  {
483
- "kind": "update_faq",
540
+ "kind": "faq:update",
484
541
  "operation": "replace",
485
542
  "items": [
486
543
  {
@@ -499,12 +556,12 @@ Dynamically adds, removes, reorders, or replaces FAQ items at runtime.
499
556
 
500
557
  The FAQ widget uses a **compositional action pattern** where `faq:question` actions serve as configuration data rendered by the widget, rather than being executed by the runtime. This allows:
501
558
 
502
- - **Per-item conditional visibility** via `showWhen` strategies -- items can appear or hide based on page URL, user segment, viewport, or any DecisionStrategy condition
559
+ - **Per-item conditional visibility** via `triggerWhen` strategies -- items can appear or hide based on page URL, user segment, viewport, or any DecisionStrategy condition
503
560
  - **Category grouping** -- items with a `category` field are grouped under collapsible section headers
504
561
  - **Dynamic injection** -- `injections` rules can add items when trigger conditions are met, supporting contextual FAQ content
505
562
  - **Ordering control** -- the `ordering` strategy determines how items are sorted within categories
506
563
 
507
- Items without `showWhen` are always visible. Items without `category` appear in an ungrouped section.
564
+ Items without `triggerWhen` are always visible. Items without `category` appear in an ungrouped section.
508
565
 
509
566
  ## Rich Answer Content
510
567
 
@@ -650,17 +707,67 @@ Injection rules add contextual FAQ items when conditions are met:
650
707
 
651
708
  Gamification capabilities including badges, points, and leaderboards.
652
709
 
710
+ ## When to use
711
+
712
+ | Goal | Action |
713
+ |------|--------|
714
+ | Award a badge to a user | `gamification:awardBadge` |
715
+ | Add points to a user's score | `gamification:addPoints` |
716
+ | Mount a gamification widget (leaderboard, progress) | Add a **tile** with `component: "adaptive-gamification:leaderboard"` |
717
+
653
718
  ## Actions
654
719
 
655
- ### mount_gamification
720
+ ### gamification:awardBadge
721
+
722
+ Awards a badge to the current user.
723
+
724
+ | Property | Type | Required | Description |
725
+ | -------- | -------------------------- | -------- | ---------------- |
726
+ | `kind` | `"gamification:awardBadge"` | Yes | Action type |
727
+ | `badgeId` | string | Yes | Badge identifier |
728
+
729
+ ```json
730
+ {
731
+ "kind": "gamification:awardBadge",
732
+ "badgeId": "first-purchase"
733
+ }
734
+ ```
735
+
736
+ ### gamification:addPoints
737
+
738
+ Adds points to the current user's score.
739
+
740
+ | Property | Type | Required | Description |
741
+ | -------- | -------------------------- | -------- | ---------------- |
742
+ | `kind` | `"gamification:addPoints"` | Yes | Action type |
743
+ | `points` | number | Yes | Points to add |
744
+
745
+ ```json
746
+ {
747
+ "kind": "gamification:addPoints",
748
+ "points": 50
749
+ }
750
+ ```
751
+
752
+ ### Gamification Widget (via Tile)
656
753
 
657
- Mounts gamification UI elements.
754
+ Mount gamification UI elements (leaderboard, badge display, progress tracker) via a **tile**:
658
755
 
659
- | Property | Type | Required | Description |
660
- | -------- | ---------------------- | -------- | -------------------------- |
661
- | `kind` | `"mount_gamification"` | Yes | Action type |
662
- | `slot` | string | Yes | Target slot |
663
- | `config` | object | Yes | Gamification configuration |
756
+ ```json
757
+ {
758
+ "tiles": [
759
+ {
760
+ "id": "gamification",
761
+ "title": "Your Progress",
762
+ "content": {
763
+ "type": "custom",
764
+ "component": "adaptive-gamification:leaderboard",
765
+ "props": { ... }
766
+ }
767
+ }
768
+ ]
769
+ }
770
+ ```
664
771
 
665
772
  ### Configuration Schema
666
773
 
@@ -685,9 +792,13 @@ Mounts gamification UI elements.
685
792
 
686
793
  ```json
687
794
  {
688
- "kind": "mount_gamification",
689
- "slot": "overlay_corner_br",
690
- "config": {
795
+ "tiles": [{
796
+ "id": "gamification-widget",
797
+ "title": "Achievements",
798
+ "content": {
799
+ "type": "custom",
800
+ "component": "adaptive-gamification:leaderboard",
801
+ "props": {
691
802
  "badges": [
692
803
  {
693
804
  "id": "first-purchase",
@@ -697,18 +808,6 @@ Mounts gamification UI elements.
697
808
  "trigger": {
698
809
  "event": "purchase_completed"
699
810
  }
700
- },
701
- {
702
- "id": "explorer",
703
- "name": "Explorer",
704
- "icon": "compass",
705
- "description": "Visited 10 different pages",
706
- "trigger": {
707
- "event": "page_view",
708
- "conditions": [
709
- { "type": "session_metric", "key": "unique_pages", "operator": ">=", "threshold": 10 }
710
- ]
711
- }
712
811
  }
713
812
  ],
714
813
  "points": {
@@ -737,6 +836,14 @@ Mounts gamification UI elements.
737
836
 
738
837
  Navigation tips accordion widget with conditional item visibility and toast notifications.
739
838
 
839
+ ## When to use
840
+
841
+ | Goal | Action |
842
+ |------|--------|
843
+ | Scroll to an element on the page | `navigation:scrollTo` |
844
+ | Navigate to a different URL | `navigation:navigate` |
845
+ | Show contextual navigation tips widget | Add a **tile** with `component: "adaptive-nav:tips"` |
846
+
740
847
  ## Widget: `adaptive-nav:tips`
741
848
 
742
849
  Accordion of contextual navigation tips. Each tip has a collapsible header and expanded body with optional CTA link.
@@ -857,15 +964,26 @@ Navigates to a URL.
857
964
 
858
965
  Visual overlay capabilities including highlights, tooltips, badges, pulse animations, and celebrations.
859
966
 
967
+ ## When to use
968
+
969
+ | Goal | Action |
970
+ |------|--------|
971
+ | Draw attention to an element (spotlight) | `overlays:highlight` |
972
+ | Show contextual help or guidance near an element | `overlays:tooltip` |
973
+ | Add a notification indicator (count, "NEW") | `overlays:badge` |
974
+ | Subtle attention-grab animation | `overlays:pulse` |
975
+ | Show a blocking or non-blocking dialog | `overlays:modal` |
976
+ | Celebrate a user achievement | `overlays:celebrate` |
977
+
860
978
  ## Actions
861
979
 
862
- ### highlight
980
+ ### overlays:highlight
863
981
 
864
982
  Creates a spotlight effect around an element with a scrim overlay.
865
983
 
866
984
  | Property | Type | Required | Default | Description |
867
985
  | -------------------- | ------------- | -------- | ----------- | --------------------------------------- |
868
- | `kind` | `"highlight"` | Yes | | Action type |
986
+ | `kind` | `"overlays:highlight"` | Yes | | Action type |
869
987
  | `anchorId` | string | Yes | | Element selector |
870
988
  | `style.color` | string | No | `"#5b8cff"` | Ring color |
871
989
  | `style.scrimOpacity` | number | No | `0.55` | Backdrop opacity 0-1 (set to 0 to hide) |
@@ -874,7 +992,7 @@ Creates a spotlight effect around an element with a scrim overlay.
874
992
 
875
993
  ```json
876
994
  {
877
- "kind": "highlight",
995
+ "kind": "overlays:highlight",
878
996
  "anchorId": "#signup-button",
879
997
  "style": {
880
998
  "color": "#22c55e",
@@ -883,13 +1001,13 @@ Creates a spotlight effect around an element with a scrim overlay.
883
1001
  }
884
1002
  ```
885
1003
 
886
- ### tooltip
1004
+ ### overlays:tooltip
887
1005
 
888
1006
  Shows a tooltip near an element with optional title, body, and CTA.
889
1007
 
890
1008
  | Property | Type | Required | Default | Description |
891
1009
  | -------------------- | ----------- | -------- | ------------- | -------------------------------------- |
892
- | `kind` | `"tooltip"` | Yes | | Action type |
1010
+ | `kind` | `"overlays:tooltip"` | Yes | | Action type |
893
1011
  | `anchorId` | string | Yes | | Element selector |
894
1012
  | `content.title` | string | No | | Tooltip heading |
895
1013
  | `content.body` | string | Yes | | Tooltip text |
@@ -905,14 +1023,14 @@ Shows a tooltip near an element with optional title, body, and CTA.
905
1023
 
906
1024
  ```json
907
1025
  {
908
- "kind": "tooltip",
1026
+ "kind": "overlays:tooltip",
909
1027
  "anchorId": "#pricing-toggle",
910
1028
  "content": {
911
1029
  "title": "Save 20%",
912
1030
  "body": "Switch to annual billing to save on your subscription.",
913
1031
  "cta": {
914
1032
  "label": "Switch Now",
915
- "action": { "kind": "navigate", "url": "/billing?annual=true" }
1033
+ "action": { "kind": "navigation:navigate", "url": "/billing?annual=true" }
916
1034
  }
917
1035
  },
918
1036
  "placement": "bottom",
@@ -951,45 +1069,45 @@ Use `ctaButtons` for tooltips with multiple actions. Each button has:
951
1069
  - `"faq:open:<questionId>"` — Convention for companion FAQ tooltips (see adaptive-faq CAPABILITIES for details). Publishes `action.tooltip_cta_clicked` which the FAQ widget listens for.
952
1070
  - Any other value — Publishes `action.tooltip_cta_clicked` with the `actionId` in event props for custom handling
953
1071
 
954
- ### badge
1072
+ ### overlays:badge
955
1073
 
956
1074
  Adds a small badge indicator near an element.
957
1075
 
958
1076
  | Property | Type | Required | Default | Description |
959
1077
  | ---------- | --------- | -------- | ------------- | -------------------------------------------------------------- |
960
- | `kind` | `"badge"` | Yes | | Action type |
1078
+ | `kind` | `"overlays:badge"` | Yes | | Action type |
961
1079
  | `anchorId` | string | Yes | | Element selector |
962
1080
  | `text` | string | Yes | | Badge text (e.g., "NEW", "3") |
963
1081
  | `position` | string | No | `"top-right"` | `"top-left"`, `"top-right"`, `"bottom-left"`, `"bottom-right"` |
964
1082
 
965
1083
  ```json
966
1084
  {
967
- "kind": "badge",
1085
+ "kind": "overlays:badge",
968
1086
  "anchorId": "#inbox-icon",
969
1087
  "text": "5",
970
1088
  "position": "top-right"
971
1089
  }
972
1090
  ```
973
1091
 
974
- ### pulse
1092
+ ### overlays:pulse
975
1093
 
976
1094
  Adds a pulsing animation to draw attention.
977
1095
 
978
1096
  | Property | Type | Required | Default | Description |
979
1097
  | ---------- | --------- | -------- | ------- | ------------------------ |
980
- | `kind` | `"pulse"` | Yes | | Action type |
1098
+ | `kind` | `"overlays:pulse"` | Yes | | Action type |
981
1099
  | `anchorId` | string | Yes | | Element selector |
982
1100
  | `duration` | number | No | `2000` | Animation duration in ms |
983
1101
 
984
1102
  ```json
985
1103
  {
986
- "kind": "pulse",
1104
+ "kind": "overlays:pulse",
987
1105
  "anchorId": ".notification-bell",
988
1106
  "duration": 3000
989
1107
  }
990
1108
  ```
991
1109
 
992
- ### modal
1110
+ ### overlays:modal
993
1111
 
994
1112
  Shows a centered modal dialog with optional CTA buttons.
995
1113
 
@@ -1029,7 +1147,7 @@ Shows a centered modal dialog with optional CTA buttons.
1029
1147
  }
1030
1148
  ```
1031
1149
 
1032
- ### celebrate
1150
+ ### overlays:celebrate
1033
1151
 
1034
1152
  Renders a fullscreen Canvas 2D celebration effect. One action kind with a pluggable `effect` parameter supporting multiple visual presets.
1035
1153
 
@@ -1251,15 +1369,7 @@ Control when adaptives activate using `DecisionStrategy`:
1251
1369
 
1252
1370
  ### 1. Choose the Right Action Type
1253
1371
 
1254
- | Goal | Action |
1255
- |------|--------|
1256
- | Change text | `set_text` |
1257
- | Add visual indicator | `badge`, `pulse` |
1258
- | Show help text | `tooltip` |
1259
- | Draw attention | `highlight` |
1260
- | Add content | `insert_html` |
1261
- | Navigate user | `scroll_to`, `navigate` |
1262
- | Show UI panel | `mount_widget` + Surfaces |
1372
+ Each adaptive package has a "When to use" guide at the top of its capabilities section above. Refer to those for action selection guidance.
1263
1373
 
1264
1374
  ### 2. Anchor Selection
1265
1375
 
@@ -1284,3 +1394,25 @@ Control when adaptives activate using `DecisionStrategy`:
1284
1394
  - Listen for `action.failed` to handle errors
1285
1395
  - Track `action.applied` for analytics
1286
1396
  - Use EventBus for cross-adaptive coordination
1397
+
1398
+ ### 6. Opening the Canvas from Inserted Content
1399
+
1400
+ When `content:insertHtml` needs to open the canvas panel (e.g., a "Help Me Choose" button that opens an FAQ tile), use the `deepLink` property — **never write `onclick` handlers or reference `window.SynOS` in HTML**.
1401
+
1402
+ ```json
1403
+ {
1404
+ "kind": "content:insertHtml",
1405
+ "anchorId": { "selector": "[data-id='pricing-heading']", "route": "/" },
1406
+ "html": "<button style='background: #4a90e2; color: white; border: none; padding: 8px 16px; border-radius: 20px; cursor: pointer;'>Help Me Choose</button>",
1407
+ "position": "after",
1408
+ "deepLink": { "tileId": "plan_selector_faq" }
1409
+ }
1410
+ ```
1411
+
1412
+ The `deepLink` object:
1413
+ - `tileId` (required) — ID of the canvas tile to navigate to
1414
+ - `itemId` (optional) — specific item within the tile (e.g., a FAQ question ID)
1415
+
1416
+ The SDK automatically opens the canvas, navigates to the tile, sets cursor to pointer, and wires up click/cleanup handlers.
1417
+
1418
+ **NEVER use `onclick`, `window.SynOS`, or any JavaScript in `content:insertHtml` HTML strings.** The HTML is sanitized and event handlers are stripped. Use `deepLink` instead.