@syntrologie/adapt-nav 2.13.0 → 2.15.0

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 (104) hide show
  1. package/dist/NavWidgetLit.d.ts +56 -0
  2. package/dist/NavWidgetLit.d.ts.map +1 -0
  3. package/dist/NavWidgetLit.js +495 -0
  4. package/dist/NavWidgetLit.test.d.ts +8 -0
  5. package/dist/NavWidgetLit.test.d.ts.map +1 -0
  6. package/dist/NavWidgetLit.test.js +199 -0
  7. package/dist/editor-lit.d.ts +49 -0
  8. package/dist/editor-lit.d.ts.map +1 -0
  9. package/dist/editor-lit.js +319 -0
  10. package/dist/editor.d.ts.map +1 -1
  11. package/dist/editor.js +3 -3
  12. package/dist/runtime-lit.d.ts +108 -0
  13. package/dist/runtime-lit.d.ts.map +1 -0
  14. package/dist/runtime-lit.js +241 -0
  15. package/dist/runtime.d.ts +15 -3
  16. package/dist/runtime.d.ts.map +1 -1
  17. package/dist/runtime.js +29 -0
  18. package/dist/schema.d.ts +216 -216
  19. package/dist/schema.d.ts.map +1 -1
  20. package/node_modules/@syntro/design-system/dist/tokens/index.d.ts +2 -0
  21. package/node_modules/@syntro/design-system/dist/tokens/index.d.ts.map +1 -1
  22. package/node_modules/@syntro/design-system/dist/tokens/index.js +2 -0
  23. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.d.ts +93 -0
  24. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.d.ts.map +1 -0
  25. package/node_modules/@syntro/design-system/dist/tokens/panel-shell.js +72 -0
  26. package/node_modules/@syntrologie/sdk-contracts/dist/index.d.ts +1 -1
  27. package/node_modules/@syntrologie/sdk-contracts/dist/index.js +5 -3
  28. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.d.ts +150 -79
  29. package/node_modules/@syntrologie/sdk-contracts/dist/schemas.js +266 -67
  30. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.d.ts.map +1 -1
  31. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPicker.js +6 -3
  32. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.d.ts +84 -0
  33. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.d.ts.map +1 -0
  34. package/node_modules/@syntrologie/shared-editor-ui/dist/components/AnchorPickerLit.js +323 -0
  35. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.d.ts +25 -0
  36. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.d.ts.map +1 -0
  37. package/node_modules/@syntrologie/shared-editor-ui/dist/components/BeforeAfterToggleLit.js +55 -0
  38. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.d.ts +33 -0
  39. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.d.ts.map +1 -0
  40. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ConditionStatusLineLit.js +118 -0
  41. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.d.ts +32 -0
  42. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.d.ts.map +1 -0
  43. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DetectionBadgeLit.js +68 -0
  44. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.d.ts +34 -0
  45. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.d.ts.map +1 -0
  46. package/node_modules/@syntrologie/shared-editor-ui/dist/components/DismissedSectionLit.js +57 -0
  47. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.d.ts +13 -0
  48. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.d.ts.map +1 -0
  49. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditBackButtonLit.js +31 -0
  50. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.d.ts +7 -0
  51. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.d.ts.map +1 -0
  52. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorBodyLit.js +15 -0
  53. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.d.ts +36 -0
  54. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.d.ts.map +1 -0
  55. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorCardLit.js +102 -0
  56. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.d.ts +20 -0
  57. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.d.ts.map +1 -0
  58. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorFooterLit.js +48 -0
  59. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.d.ts +16 -0
  60. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.d.ts.map +1 -0
  61. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorHeaderLit.js +25 -0
  62. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.d.ts +66 -0
  63. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.d.ts.map +1 -0
  64. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorInputLit.js +87 -0
  65. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.d.ts +7 -0
  66. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.d.ts.map +1 -0
  67. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorLayoutLit.js +15 -0
  68. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.d.ts.map +1 -1
  69. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShell.js +28 -17
  70. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.d.ts +66 -0
  71. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.d.ts.map +1 -0
  72. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorPanelShellLit.js +528 -0
  73. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.d.ts +41 -0
  74. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.d.ts.map +1 -0
  75. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorSelectLit.js +63 -0
  76. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.d.ts +55 -0
  77. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.d.ts.map +1 -0
  78. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EditorTextareaLit.js +92 -0
  79. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.d.ts +90 -0
  80. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.d.ts.map +1 -0
  81. package/node_modules/@syntrologie/shared-editor-ui/dist/components/ElementHighlightLit.js +242 -0
  82. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.d.ts +12 -0
  83. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.d.ts.map +1 -0
  84. package/node_modules/@syntrologie/shared-editor-ui/dist/components/EmptyStateLit.js +21 -0
  85. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.d.ts +21 -0
  86. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.d.ts.map +1 -0
  87. package/node_modules/@syntrologie/shared-editor-ui/dist/components/GroupHeaderLit.js +33 -0
  88. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.d.ts +28 -0
  89. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.d.ts.map +1 -0
  90. package/node_modules/@syntrologie/shared-editor-ui/dist/components/TriggerJourneyLit.js +121 -0
  91. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.d.ts +110 -0
  92. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.d.ts.map +1 -0
  93. package/node_modules/@syntrologie/shared-editor-ui/dist/controllers/PanelShellController.js +476 -0
  94. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts +2 -0
  95. package/node_modules/@syntrologie/shared-editor-ui/dist/index.d.ts.map +1 -1
  96. package/node_modules/@syntrologie/shared-editor-ui/dist/index.js +1 -0
  97. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.d.ts +15 -0
  98. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.d.ts.map +1 -0
  99. package/node_modules/@syntrologie/shared-editor-ui/dist/lit-elements.js +14 -0
  100. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts +0 -4
  101. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.d.ts.map +1 -1
  102. package/node_modules/@syntrologie/shared-editor-ui/dist/utils/elementChainRecommender.js +17 -1
  103. package/node_modules/@syntrologie/shared-editor-ui/package.json +9 -1
  104. package/package.json +12 -1
@@ -15,76 +15,168 @@ export const AnchorIdZ = z
15
15
  })
16
16
  .strict();
17
17
  // =============================================================================
18
+ // TRIGGER VOCABULARY — canonical lists of valid event names, metric keys, etc.
19
+ // These flow through to the JSON schema as enums and are used by the LLM prompt.
20
+ // =============================================================================
21
+ /** Events that can be counted in event_count conditions. */
22
+ export const COUNTABLE_EVENTS = [
23
+ // User interactions (from PostHog autocapture normalization)
24
+ 'ui.click',
25
+ 'ui.scroll',
26
+ 'ui.input',
27
+ 'ui.change',
28
+ 'ui.submit',
29
+ // Behavioral detectors (from event-processor)
30
+ 'ui.hover',
31
+ 'ui.idle',
32
+ 'ui.scroll_thrash',
33
+ 'ui.focus_bounce',
34
+ // Navigation
35
+ 'nav.page_view',
36
+ 'nav.page_leave',
37
+ // Derived behavioral signals
38
+ 'behavior.rage_click',
39
+ 'behavior.hesitation',
40
+ 'behavior.confusion',
41
+ ];
42
+ export const CountableEventZ = z
43
+ .enum(COUNTABLE_EVENTS)
44
+ .describe('Event name to count. ui.* = user interactions and behavioral detectors, nav.* = page navigation, behavior.* = derived behavioral signals.');
45
+ /** Valid session metric keys. */
46
+ export const SESSION_METRIC_KEYS = ['time_on_page', 'page_views', 'scroll_depth'];
47
+ export const SessionMetricKeyZ = z
48
+ .enum(SESSION_METRIC_KEYS)
49
+ .describe('Session metric key. time_on_page = seconds on current page, page_views = pages visited this session, scroll_depth = 0-100 percentage.');
50
+ /** Element chain match field prefixes for counter filters. */
51
+ export const ELEMENT_MATCH_FIELDS = ['tag_name', '$el_text'];
52
+ // Note: attr__* is a dynamic prefix (attr__data-id, attr__class, attr__href, etc.)
53
+ // and cannot be enumerated. The match key is either one of ELEMENT_MATCH_FIELDS
54
+ // or starts with "attr__".
55
+ // =============================================================================
18
56
  // CONDITION SCHEMAS
19
57
  // =============================================================================
20
- export const PageUrlConditionZ = z.object({
58
+ export const PageUrlConditionZ = z
59
+ .object({
21
60
  type: z.literal('page_url'),
22
- url: z.string(),
23
- });
24
- export const RouteConditionZ = z.object({
61
+ url: z.string().describe('URL path to match (e.g. "/pricing", "/dashboard")'),
62
+ })
63
+ .describe('Fires when the current page URL matches. Use for page-specific actions. ' +
64
+ 'Example: {"type": "page_url", "url": "/pricing"}');
65
+ export const RouteConditionZ = z
66
+ .object({
25
67
  type: z.literal('route'),
26
- routeId: z.string(),
27
- });
28
- export const AnchorVisibleConditionZ = z.object({
68
+ routeId: z.string().describe('Named route ID from the route filter'),
69
+ })
70
+ .describe('Fires when the current route matches a named route ID.');
71
+ export const AnchorVisibleConditionZ = z
72
+ .object({
29
73
  type: z.literal('anchor_visible'),
30
- anchorId: z.string(),
31
- state: z.enum(['visible', 'present', 'absent']),
32
- });
33
- export const EventOccurredConditionZ = z.object({
74
+ anchorId: z.string().describe('CSS selector of the anchor element'),
75
+ state: z
76
+ .enum(['visible', 'present', 'absent'])
77
+ .describe('"visible" = in viewport, "present" = in DOM, "absent" = not in DOM'),
78
+ })
79
+ .describe("Fires based on a DOM element's visibility state. " +
80
+ 'Example: {"type": "anchor_visible", "anchorId": "#cta-button", "state": "visible"}');
81
+ export const EventOccurredConditionZ = z
82
+ .object({
34
83
  type: z.literal('event_occurred'),
35
- eventName: z.string(),
36
- withinMs: z.number().optional(),
37
- });
38
- export const StateEqualsConditionZ = z.object({
84
+ eventName: z.string().describe('Event name (e.g. "ui.click", "$pageview")'),
85
+ withinMs: z.number().optional().describe('Time window in ms. Omit = any time this session.'),
86
+ })
87
+ .describe('Fires when a specific event has occurred during this session. ' +
88
+ 'Example: {"type": "event_occurred", "eventName": "ui.click", "withinMs": 5000}');
89
+ export const StateEqualsConditionZ = z
90
+ .object({
39
91
  type: z.literal('state_equals'),
40
- key: z.string(),
41
- value: z.unknown(),
42
- });
43
- export const ViewportConditionZ = z.object({
92
+ key: z
93
+ .string()
94
+ .describe('Key in the SDK persistent state store (localStorage). Only valid for keys the host app explicitly sets via syntro.state.set().'),
95
+ value: z.unknown().describe('Expected value to match against'),
96
+ })
97
+ .describe('Checks the SDK persistent state store (localStorage). ONLY for host-app state set via syntro.state.set() — ' +
98
+ 'NOT for user attributes like region, device, or UTM params (those are handled by segment targeting). ' +
99
+ 'Do NOT use this for targeting. If you do not know the valid state keys, do not use this condition type.');
100
+ export const ViewportConditionZ = z
101
+ .object({
44
102
  type: z.literal('viewport'),
45
- minWidth: z.number().optional(),
46
- maxWidth: z.number().optional(),
47
- minHeight: z.number().optional(),
48
- maxHeight: z.number().optional(),
49
- });
50
- export const SessionMetricConditionZ = z.object({
103
+ minWidth: z.number().optional().describe('Minimum viewport width in pixels'),
104
+ maxWidth: z.number().optional().describe('Maximum viewport width in pixels'),
105
+ minHeight: z.number().optional().describe('Minimum viewport height in pixels'),
106
+ maxHeight: z.number().optional().describe('Maximum viewport height in pixels'),
107
+ })
108
+ .describe('Fires based on viewport (screen) size. Use for responsive behavior. ' +
109
+ 'Example: {"type": "viewport", "minWidth": 768} — fires on tablet and larger.');
110
+ export const SessionMetricConditionZ = z
111
+ .object({
51
112
  type: z.literal('session_metric'),
52
- key: z.string(),
113
+ key: SessionMetricKeyZ,
53
114
  operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),
54
- threshold: z.number(),
55
- });
56
- export const DismissedConditionZ = z.object({
115
+ threshold: z.number().describe('Numeric threshold to compare against'),
116
+ })
117
+ .describe('Fires when a session metric crosses a threshold. Valid keys: "time_on_page" (seconds), ' +
118
+ '"page_views" (count), "scroll_depth" (0-100). ' +
119
+ 'Example: {"type": "session_metric", "key": "time_on_page", "operator": "gte", "threshold": 30}');
120
+ export const DismissedConditionZ = z
121
+ .object({
57
122
  type: z.literal('dismissed'),
58
- key: z.string(),
59
- inverted: z.boolean().optional(),
60
- });
61
- export const CooldownActiveConditionZ = z.object({
123
+ key: z.string().describe('Dismissal key (usually a tile or action ID)'),
124
+ inverted: z
125
+ .boolean()
126
+ .optional()
127
+ .describe('When true, fires if NOT dismissed (default behavior)'),
128
+ })
129
+ .describe('Checks if an item has been dismissed by the user. Use with inverted: true to show only if not dismissed.');
130
+ export const CooldownActiveConditionZ = z
131
+ .object({
62
132
  type: z.literal('cooldown_active'),
63
- key: z.string(),
64
- inverted: z.boolean().optional(),
65
- });
66
- export const FrequencyLimitConditionZ = z.object({
133
+ key: z.string().describe('Cooldown key'),
134
+ inverted: z.boolean().optional().describe('When true, fires if cooldown is NOT active'),
135
+ })
136
+ .describe('Checks if a cooldown timer is currently active. Use to prevent showing the same intervention too frequently.');
137
+ export const FrequencyLimitConditionZ = z
138
+ .object({
67
139
  type: z.literal('frequency_limit'),
68
- key: z.string(),
69
- limit: z.number(),
70
- inverted: z.boolean().optional(),
71
- });
72
- export const MatchOpZ = z.object({
140
+ key: z.string().describe('Frequency counter key'),
141
+ limit: z.number().describe('Maximum allowed count'),
142
+ inverted: z.boolean().optional().describe('When true, fires if limit NOT reached'),
143
+ })
144
+ .describe('Checks if a frequency limit has been reached. Use to cap how many times an action fires per session.');
145
+ export const MatchOpZ = z
146
+ .object({
73
147
  equals: z.union([z.string(), z.number(), z.boolean()]).optional(),
74
148
  contains: z.string().optional(),
75
- });
76
- export const CounterDefZ = z.object({
77
- events: z.array(z.string()).min(1),
78
- match: z.record(z.string(), MatchOpZ).optional(),
79
- });
80
- export const EventCountConditionZ = z.object({
149
+ })
150
+ .describe('Match operator for counter filters. Exactly one of equals or contains must be specified.');
151
+ export const CounterDefZ = z
152
+ .object({
153
+ events: z
154
+ .array(CountableEventZ)
155
+ .min(1)
156
+ .describe('Event names to count. Use values from the countable events enum.'),
157
+ match: z
158
+ .record(z.string(), MatchOpZ)
159
+ .optional()
160
+ .describe('Property filters. Keys are event prop names or element-chain fields ' +
161
+ '(tag_name, $el_text, attr__*). All entries AND together.'),
162
+ })
163
+ .describe('Defines what events to count. Registered as an accumulator predicate at config-load time.');
164
+ export const EventCountConditionZ = z
165
+ .object({
81
166
  type: z.literal('event_count'),
82
- key: z.string(),
167
+ key: z.string().describe('Unique key for this counter (used for accumulator registration)'),
83
168
  operator: z.enum(['gte', 'lte', 'eq', 'gt', 'lt']),
84
- count: z.number().int().min(0),
85
- withinMs: z.number().positive().optional(),
86
- counter: CounterDefZ.optional(),
87
- });
169
+ count: z.number().int().min(0).describe('Target count threshold'),
170
+ withinMs: z
171
+ .number()
172
+ .positive()
173
+ .optional()
174
+ .describe('Time window in ms. Omit = count across entire session.'),
175
+ counter: CounterDefZ.optional().describe('Inline counter definition. Defines what events to count.'),
176
+ })
177
+ .describe('Fires when accumulated event count crosses a threshold. Most powerful trigger type. ' +
178
+ 'Example: {"type": "event_count", "key": "pricing-clicks", "operator": "gte", "count": 3, ' +
179
+ '"counter": {"events": ["ui.click"], "match": {"attr__data-cta": {"contains": "pricing"}}}}');
88
180
  export const ConditionZ = z.discriminatedUnion('type', [
89
181
  PageUrlConditionZ,
90
182
  RouteConditionZ,
@@ -101,36 +193,57 @@ export const ConditionZ = z.discriminatedUnion('type', [
101
193
  // =============================================================================
102
194
  // STRATEGY SCHEMAS
103
195
  // =============================================================================
104
- export const RuleZ = z.object({
105
- conditions: z.array(ConditionZ),
106
- value: z.unknown(),
107
- });
108
- export const RuleStrategyZ = z.object({
196
+ export const RuleZ = z
197
+ .object({
198
+ conditions: z
199
+ .array(ConditionZ)
200
+ .describe('Array of conditions ALL must match (AND logic) for this rule to fire.'),
201
+ value: z
202
+ .unknown()
203
+ .describe('Value returned when all conditions match. For triggerWhen: true = fire the action.'),
204
+ })
205
+ .describe('A single rule. ALL conditions must match (AND logic). Rules in a strategy are evaluated ' +
206
+ 'top-to-bottom — first rule where all conditions match wins and returns its value.');
207
+ export const RuleStrategyZ = z
208
+ .object({
109
209
  type: z.literal('rules'),
110
- rules: z.array(RuleZ),
111
- default: z.unknown(),
112
- });
113
- export const ScoreStrategyZ = z.object({
210
+ rules: z
211
+ .array(RuleZ)
212
+ .describe('Ordered list of rules. Evaluated top-to-bottom — first match wins.'),
213
+ default: z
214
+ .unknown()
215
+ .describe('Fallback value when no rule matches. For triggerWhen: false = do not fire by default.'),
216
+ })
217
+ .describe('Rule-based strategy. Evaluates rules top-to-bottom. First rule where ALL conditions match ' +
218
+ 'returns its value. If no rule matches, returns default. ' +
219
+ 'For triggerWhen: set value=true on matching rules, default=false.');
220
+ export const ScoreStrategyZ = z
221
+ .object({
114
222
  type: z.literal('score'),
115
223
  field: z.string(),
116
224
  threshold: z.number(),
117
225
  above: z.unknown(),
118
226
  below: z.unknown(),
119
- });
120
- export const ModelStrategyZ = z.object({
227
+ })
228
+ .describe('Score-based strategy. Compares a field value against a threshold.');
229
+ export const ModelStrategyZ = z
230
+ .object({
121
231
  type: z.literal('model'),
122
232
  modelId: z.string(),
123
233
  inputs: z.array(z.string()),
124
234
  outputMapping: z.record(z.string(), z.unknown()),
125
235
  default: z.unknown(),
126
- });
127
- export const ExternalStrategyZ = z.object({
236
+ })
237
+ .describe('ML model strategy. Sends inputs to a model and maps outputs.');
238
+ export const ExternalStrategyZ = z
239
+ .object({
128
240
  type: z.literal('external'),
129
241
  endpoint: z.string(),
130
242
  method: z.enum(['GET', 'POST']).optional(),
131
243
  default: z.unknown(),
132
244
  timeoutMs: z.number().optional(),
133
- });
245
+ })
246
+ .describe('External API strategy. Calls an endpoint to determine the value.');
134
247
  export const DecisionStrategyZ = z.discriminatedUnion('type', [
135
248
  RuleStrategyZ,
136
249
  ScoreStrategyZ,
@@ -140,6 +253,92 @@ export const DecisionStrategyZ = z.discriminatedUnion('type', [
140
253
  /** Canonical Zod schema for the optional triggerWhen field on actions and adaptive items. */
141
254
  export const TriggerWhenZ = DecisionStrategyZ.nullable().optional();
142
255
  // =============================================================================
256
+ // TRIGGER DOCUMENTATION — examples and match field docs
257
+ // Exported as constants so the schema generator can inject them into the
258
+ // JSON schema. The Python prompt builder reads them from the schema.
259
+ // =============================================================================
260
+ /** Complete triggerWhen examples showing the full rules wrapper structure. */
261
+ export const TRIGGER_EXAMPLES = [
262
+ {
263
+ name: 'Click count on a specific element',
264
+ description: 'Fire when user clicks an element with data-id="hero-cta" 2+ times',
265
+ triggerWhen: {
266
+ type: 'rules',
267
+ rules: [
268
+ {
269
+ conditions: [
270
+ {
271
+ type: 'event_count',
272
+ key: 'cta-clicks',
273
+ operator: 'gte',
274
+ count: 2,
275
+ counter: {
276
+ events: ['ui.click'],
277
+ match: { 'attr__data-id': { equals: 'hero-cta' } },
278
+ },
279
+ },
280
+ ],
281
+ value: true,
282
+ },
283
+ ],
284
+ default: false,
285
+ },
286
+ },
287
+ {
288
+ name: 'Time on page threshold',
289
+ description: 'Fire after user spends 30+ seconds on the page',
290
+ triggerWhen: {
291
+ type: 'rules',
292
+ rules: [
293
+ {
294
+ conditions: [
295
+ {
296
+ type: 'session_metric',
297
+ key: 'time_on_page',
298
+ operator: 'gte',
299
+ threshold: 30,
300
+ },
301
+ ],
302
+ value: true,
303
+ },
304
+ ],
305
+ default: false,
306
+ },
307
+ },
308
+ {
309
+ name: 'Element visible in viewport',
310
+ description: 'Fire when a DOM element becomes visible',
311
+ triggerWhen: {
312
+ type: 'rules',
313
+ rules: [
314
+ {
315
+ conditions: [
316
+ {
317
+ type: 'anchor_visible',
318
+ anchorId: '#pricing-section',
319
+ state: 'visible',
320
+ },
321
+ ],
322
+ value: true,
323
+ },
324
+ ],
325
+ default: false,
326
+ },
327
+ },
328
+ {
329
+ name: 'No trigger (fire immediately)',
330
+ description: 'Action fires as soon as the segment matches — no in-session condition needed',
331
+ triggerWhen: null,
332
+ },
333
+ ];
334
+ /** Documentation for counter.match field keys. */
335
+ export const MATCH_FIELD_DOCS = {
336
+ tag_name: 'HTML tag name (e.g. "button", "a", "input")',
337
+ $el_text: 'Visible text content of the element',
338
+ 'attr__*': 'HTML attribute prefixed with attr__. Example: attr__data-id matches the data-id attribute, ' +
339
+ 'attr__class matches the class attribute, attr__href matches the href attribute.',
340
+ };
341
+ // =============================================================================
143
342
  // EVENT SCOPE SCHEMA
144
343
  // =============================================================================
145
344
  /** Scopes a widget to specific events/URLs. */
@@ -1 +1 @@
1
- {"version":3,"file":"AnchorPicker.d.ts","sourceRoot":"","sources":["../../src/components/AnchorPicker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB;;8DAE0D;IAC1D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAKD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,iBAAyB,EACzB,eAAuJ,GACxJ,EAAE,iBAAiB,sCAwMnB"}
1
+ {"version":3,"file":"AnchorPicker.d.ts","sourceRoot":"","sources":["../../src/components/AnchorPicker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAWH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,IAAI,CAAC;IACxC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB;;8DAE0D;IAC1D,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAKD,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,MAAM,EACN,QAAQ,EACR,iBAAyB,EACzB,eAAuJ,GACxJ,EAAE,iBAAiB,sCA2MnB"}
@@ -27,11 +27,14 @@ export function AnchorPicker({ isActive, onPick, onCancel, passthroughClicks = f
27
27
  const overlayRef = useRef(null);
28
28
  const handleMouseMove = useCallback((e) => {
29
29
  const overlay = overlayRef.current;
30
- if (overlay) {
30
+ // In passthrough mode the overlay is already pointerEvents:'none',
31
+ // so elementFromPoint can see through it — no toggle needed.
32
+ // In non-passthrough mode, temporarily disable to detect elements underneath.
33
+ if (overlay && !passthroughClicks) {
31
34
  overlay.style.pointerEvents = 'none';
32
35
  }
33
36
  const elementAtPoint = document.elementFromPoint(e.clientX, e.clientY);
34
- if (overlay) {
37
+ if (overlay && !passthroughClicks) {
35
38
  overlay.style.pointerEvents = 'auto';
36
39
  }
37
40
  if (!elementAtPoint) {
@@ -52,7 +55,7 @@ export function AnchorPicker({ isActive, onPick, onCancel, passthroughClicks = f
52
55
  setHoveredElement(elementAtPoint);
53
56
  const selector = generateSelector(elementAtPoint);
54
57
  setHoveredSelector(selector);
55
- }, [excludeSelector]);
58
+ }, [excludeSelector, passthroughClicks]);
56
59
  const handleClick = useCallback((e) => {
57
60
  if (passthroughClicks)
58
61
  return; // Let click propagate to PostHog
@@ -0,0 +1,84 @@
1
+ /**
2
+ * AnchorPickerLit — Shared Element Picker Overlay (Lit web component).
3
+ *
4
+ * Full-page overlay that lets the user hover and click to select a DOM element.
5
+ * Returns the element, its CSS selector, and a human-readable description
6
+ * via custom events.
7
+ *
8
+ * The overlay is rendered into a portal div appended to document.body, NOT
9
+ * into the component's own render root. This is necessary because the editor
10
+ * panel applies `backdrop-filter: blur(...)` which, in Chrome, creates a new
11
+ * containing block for `position: fixed` descendants. Without the portal, the
12
+ * highlight box coordinates (from getBoundingClientRect, which are viewport-
13
+ * relative) would be interpreted relative to the panel, causing the highlight
14
+ * to appear far off from the actual hovered element.
15
+ *
16
+ * Lit port of AnchorPicker.tsx — preserves all behavior including:
17
+ * - Mouse tracking with elementFromPoint detection
18
+ * - Passthrough click mode for PostHog integration
19
+ * - Element highlight with info tooltip
20
+ * - Escape key cancellation
21
+ * - Exclude selector filtering
22
+ */
23
+ import { LitElement } from 'lit';
24
+ export interface PickedElement {
25
+ element: Element;
26
+ selector: string;
27
+ description: string;
28
+ }
29
+ export declare class AnchorPickerLit extends LitElement {
30
+ static properties: {
31
+ isActive: {
32
+ type: BooleanConstructor;
33
+ attribute: string;
34
+ };
35
+ passthroughClicks: {
36
+ type: BooleanConstructor;
37
+ attribute: string;
38
+ };
39
+ excludeSelector: {
40
+ type: StringConstructor;
41
+ attribute: string;
42
+ };
43
+ _hoveredElement: {
44
+ state: boolean;
45
+ };
46
+ _hoveredSelector: {
47
+ state: boolean;
48
+ };
49
+ };
50
+ isActive: boolean;
51
+ passthroughClicks: boolean;
52
+ excludeSelector: string;
53
+ private _hoveredElement;
54
+ private _hoveredSelector;
55
+ private _overlayEl;
56
+ private _portalDiv;
57
+ createRenderRoot(): this;
58
+ connectedCallback(): void;
59
+ disconnectedCallback(): void;
60
+ updated(changed: Map<string, unknown>): void;
61
+ /**
62
+ * Create or update the body-level portal div.
63
+ * Rendering into document.body ensures position:fixed coordinates are
64
+ * relative to the viewport, not an ancestor with backdrop-filter.
65
+ */
66
+ private _syncPortal;
67
+ private _destroyPortal;
68
+ private _attachDocumentListeners;
69
+ private _detachDocumentListeners;
70
+ /**
71
+ * Resolve the shadow host this picker lives inside, if any. When the picker
72
+ * is mounted inside a shadow root (e.g. the editor SDK mounts inside
73
+ * `<smart-canvas>`'s shadow), `document.elementFromPoint` returns the shadow
74
+ * *host*, not the host page element beneath. Temporarily disabling pointer
75
+ * events on the host lets hit-testing fall through to the host page.
76
+ */
77
+ private _getShadowHost;
78
+ private _handleMouseMove;
79
+ private _handleClick;
80
+ private _handleKeyDown;
81
+ render(): symbol;
82
+ private _overlayTemplate;
83
+ }
84
+ //# sourceMappingURL=AnchorPickerLit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AnchorPickerLit.d.ts","sourceRoot":"","sources":["../../src/components/AnchorPickerLit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAGH,OAAO,EAAQ,UAAU,EAAgC,MAAM,KAAK,CAAC;AAarE,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;CACrB;AAiBD,qBAAa,eAAgB,SAAQ,UAAU;IAC7C,OAAgB,UAAU;;;;;;;;;;;;;;;;;;;MAOxB;IAEF,QAAQ,UAAS;IACjB,iBAAiB,UAAS;IAC1B,eAAe,EAAE,MAAM,CAA4B;IAGnD,OAAO,CAAC,eAAe,CAAwB;IAC/C,OAAO,CAAC,gBAAgB,CAAM;IAG9B,OAAO,CAAC,UAAU,CAA+B;IAGjD,OAAO,CAAC,UAAU,CAA+B;IAIxC,gBAAgB;IAIhB,iBAAiB,IAAI,IAAI;IAOzB,oBAAoB,IAAI,IAAI;IAM5B,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAiBrD;;;;OAIG;IACH,OAAO,CAAC,WAAW;IAgBnB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,wBAAwB;IAQhC,OAAO,CAAC,wBAAwB;IAQhC;;;;;;OAMG;IACH,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,gBAAgB,CA+CtB;IAEF,OAAO,CAAC,YAAY,CAwBlB;IAEF,OAAO,CAAC,cAAc,CAUpB;IAMO,MAAM;IAIf,OAAO,CAAC,gBAAgB;CA0GzB"}