@picked/client 0.0.55 → 0.0.56-next.2
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/dist/{api-B1yTKITq.js → api-DHSz_ruC.js} +1 -1
- package/dist/api-DVSjNleu.cjs +1 -0
- package/dist/cjs/form/index.js +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/plugins/create-experience/index.js +1 -1
- package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
- package/dist/docs/actions.md +58 -0
- package/dist/docs/api/index.md +32 -0
- package/dist/docs/api-keys.md +33 -0
- package/dist/docs/conditions.md +52 -0
- package/dist/docs/experiences.md +33 -0
- package/dist/docs/features.md +51 -0
- package/dist/docs/fields.md +70 -0
- package/dist/docs/flow-builder/building-flows.md +61 -0
- package/dist/docs/flow-builder/condition-builder.md +54 -0
- package/dist/docs/flow-builder/keyboard-shortcuts.md +66 -0
- package/dist/docs/flow-builder/nodes.md +43 -0
- package/dist/docs/flow-builder/overview.md +43 -0
- package/dist/docs/index.md +79 -0
- package/dist/docs/pickedql/data-sources.md +39 -0
- package/dist/docs/pickedql/dimensions.md +23 -0
- package/dist/docs/pickedql/examples.md +165 -0
- package/dist/docs/pickedql/filtering.md +31 -0
- package/dist/docs/pickedql/index.md +34 -0
- package/dist/docs/pickedql/schema.md +95 -0
- package/dist/docs/pickedql/virtual-functions.md +84 -0
- package/dist/docs/projects.md +30 -0
- package/dist/docs/reference/index.md +11 -0
- package/dist/docs/reports.md +11 -0
- package/dist/docs/sdk/actions.md +7 -0
- package/dist/docs/sdk/conditions.md +131 -0
- package/dist/docs/sdk/content-security-policy.md +31 -0
- package/dist/docs/sdk/experiences.md +41 -0
- package/dist/docs/sdk/features.md +213 -0
- package/dist/docs/sdk/fields.md +263 -0
- package/dist/docs/sdk/index.md +74 -0
- package/dist/docs/sdk/plugins/create-experience.md +133 -0
- package/dist/docs/sdk/plugins/dynamic-experiences.md +59 -0
- package/dist/docs/sdk/plugins/index.md +9 -0
- package/dist/docs/sdk/plugins/window-object.md +20 -0
- package/dist/docs/sdk/predicates.md +113 -0
- package/dist/docs/sdk/steps.md +411 -0
- package/dist/docs/steps.md +35 -0
- package/dist/docs/team-management.md +40 -0
- package/dist/docs/tooling/chrome-extension.md +29 -0
- package/dist/docs/tooling/gtm-template.md +69 -0
- package/dist/docs/tooling/index.md +19 -0
- package/dist/docs/tooling/mcp.md +120 -0
- package/dist/docs/tooling/vite-plugin.md +82 -0
- package/dist/docs/workspaces.md +35 -0
- package/dist/esm/form/index.js +2 -2
- package/dist/esm/index.js +1 -1
- package/dist/esm/plugins/create-experience/index.js +1 -1
- package/dist/esm/plugins/dynamic-experiences/index.js +11 -2
- package/dist/types/entities/step/step.d.ts +1 -1
- package/dist/types/entities/step/step.d.ts.map +1 -1
- package/dist/types/form/create-field-evaluator.d.ts +5 -5
- package/dist/types/form/create-field-evaluator.d.ts.map +1 -1
- package/dist/types/form/create-form.d.ts +7 -7
- package/dist/types/form/create-form.d.ts.map +1 -1
- package/dist/types/plugins/dynamic-experiences/plugin.d.ts.map +1 -1
- package/dist/types/plugins/dynamic-experiences/types.d.ts +9 -1
- package/dist/types/plugins/dynamic-experiences/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/api-DO5hnUsd.cjs +0 -1
|
@@ -0,0 +1,411 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Steps
|
|
6
|
+
|
|
7
|
+
Steps are the building blocks of an experience. Each step represents a single screen or stage in a multi-step journey.
|
|
8
|
+
|
|
9
|
+
## How Steps Work
|
|
10
|
+
|
|
11
|
+
When an experience starts, its steps are connected in a directed node graph. The SDK traverses this graph to determine which step to display:
|
|
12
|
+
|
|
13
|
+
1. **Initialization**: When the experience opens, the SDK starts at the origin node and traverses the graph to find the first step
|
|
14
|
+
2. **Step Entry**: The active step is set and a `step_enter` event is emitted on the event bus
|
|
15
|
+
3. **Field Evaluation**: The step's fields are evaluated — fields with conditions are shown or hidden based on the current state
|
|
16
|
+
4. **User Input**: The user interacts with the step's fields. Client-side validation runs on blur and on submit
|
|
17
|
+
5. **Step Submission**: When the user submits, a `step_submit` event fires and field responses are committed to the client state
|
|
18
|
+
6. **Navigation**: The SDK follows the edge from the current step node to the next, traversing any conditionals or actions before arriving at the next step
|
|
19
|
+
7. **Completion**: When no further steps exist, the experience flow is complete
|
|
20
|
+
|
|
21
|
+
## Step Routing
|
|
22
|
+
|
|
23
|
+
`StepRouter` listens to the experience's current step state and activates the matching `Step` by its `id`. Each `Step` registers itself on mount and unregisters on unmount, so lazy-rendered tabs or drawers work automatically.
|
|
24
|
+
|
|
25
|
+
:::code-group
|
|
26
|
+
|
|
27
|
+
```svelte [Svelte]
|
|
28
|
+
<script lang="ts">
|
|
29
|
+
import { StepRouter, Step } from '@picked/svelte/router'
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<StepRouter>
|
|
33
|
+
<Step id="welcome">
|
|
34
|
+
<WelcomeScreen />
|
|
35
|
+
</Step>
|
|
36
|
+
|
|
37
|
+
<Step id="contact">
|
|
38
|
+
<ContactForm />
|
|
39
|
+
</Step>
|
|
40
|
+
|
|
41
|
+
<Step id="confirmation">
|
|
42
|
+
<ConfirmationScreen />
|
|
43
|
+
</Step>
|
|
44
|
+
</StepRouter>
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
```tsx [React]
|
|
48
|
+
import { StepRouter, Step } from '@picked/react/router'
|
|
49
|
+
|
|
50
|
+
function MyExperience() {
|
|
51
|
+
return (
|
|
52
|
+
<StepRouter>
|
|
53
|
+
<Step id="welcome">
|
|
54
|
+
<WelcomeScreen />
|
|
55
|
+
</Step>
|
|
56
|
+
|
|
57
|
+
<Step id="contact">
|
|
58
|
+
<ContactForm />
|
|
59
|
+
</Step>
|
|
60
|
+
|
|
61
|
+
<Step id="confirmation">
|
|
62
|
+
<ConfirmationScreen />
|
|
63
|
+
</Step>
|
|
64
|
+
</StepRouter>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
:::
|
|
70
|
+
|
|
71
|
+
:::note
|
|
72
|
+
All Steps must be wrapped in a router, even if it is a single Step
|
|
73
|
+
:::
|
|
74
|
+
|
|
75
|
+
### Lazy-Loaded Steps
|
|
76
|
+
|
|
77
|
+
For large experiences, steps can be lazily loaded using dynamic imports:
|
|
78
|
+
|
|
79
|
+
:::code-group
|
|
80
|
+
|
|
81
|
+
```svelte [Svelte]
|
|
82
|
+
<StepRouter>
|
|
83
|
+
<Step id="welcome" component={import('./WelcomeScreen.svelte')} />
|
|
84
|
+
</StepRouter>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```tsx [React]
|
|
88
|
+
import { lazy } from 'react'
|
|
89
|
+
|
|
90
|
+
const WelcomeScreen = lazy(() => import('./WelcomeScreen'))
|
|
91
|
+
|
|
92
|
+
<StepRouter>
|
|
93
|
+
<Step id="welcome">
|
|
94
|
+
<WelcomeScreen />
|
|
95
|
+
</Step>
|
|
96
|
+
</StepRouter>
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
:::
|
|
100
|
+
|
|
101
|
+
The `component` prop accepts a `Promise<Component>` — the step's content is not loaded until it becomes active.
|
|
102
|
+
|
|
103
|
+
## Accessing Step Context
|
|
104
|
+
|
|
105
|
+
Inside a `Step` component (or any component rendered within one), call `getStep()` / `useStep()` to access the step's reactive context:
|
|
106
|
+
|
|
107
|
+
:::code-group
|
|
108
|
+
|
|
109
|
+
```svelte [Svelte]
|
|
110
|
+
<script lang="ts">
|
|
111
|
+
import { getStep } from '@picked/svelte/hooks'
|
|
112
|
+
|
|
113
|
+
const { step, fields } = getStep()
|
|
114
|
+
</script>
|
|
115
|
+
|
|
116
|
+
<h1>{$step.label}</h1>
|
|
117
|
+
|
|
118
|
+
{#each $fields as field}
|
|
119
|
+
<label>{field.label}</label>
|
|
120
|
+
<input
|
|
121
|
+
name={field.id}
|
|
122
|
+
value={field.value ?? ''}
|
|
123
|
+
onchange={field.onChange}
|
|
124
|
+
onblur={field.onBlur}
|
|
125
|
+
/>
|
|
126
|
+
{#if field.error && field.touched
|
|
127
|
+
<p class="error">{field.error.userMessage}</p>
|
|
128
|
+
{/if}
|
|
129
|
+
{/each}
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
```tsx [React]
|
|
133
|
+
import { useStep } from '@picked/react/hooks'
|
|
134
|
+
import { useUnit } from 'effector-react'
|
|
135
|
+
|
|
136
|
+
function ContactForm() {
|
|
137
|
+
const { step, fields } = useStep()
|
|
138
|
+
const currentStep = useUnit(step)
|
|
139
|
+
const currentFields = useUnit(fields)
|
|
140
|
+
|
|
141
|
+
return (
|
|
142
|
+
<>
|
|
143
|
+
<h1>{currentStep.label}</h1>
|
|
144
|
+
|
|
145
|
+
{currentFields.map((field) => (
|
|
146
|
+
<div key={field.id}>
|
|
147
|
+
<label>{field.label}</label>
|
|
148
|
+
<input
|
|
149
|
+
name={field.id}
|
|
150
|
+
value={field.value ?? ''}
|
|
151
|
+
onChange={field.onChange}
|
|
152
|
+
onBlur={field.onBlur}
|
|
153
|
+
/>
|
|
154
|
+
{field.error && field.touched && <p className="error">{field.error.userMessage}</p>}
|
|
155
|
+
</div>
|
|
156
|
+
))}
|
|
157
|
+
</>
|
|
158
|
+
)
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
:::
|
|
163
|
+
|
|
164
|
+
`getStep()` (Svelte) / `useStep()` (React) returns a `StepContext` with the following properties:
|
|
165
|
+
|
|
166
|
+
| Property | Type | Description |
|
|
167
|
+
| ---------- | --------------------------------------------- | ------------------------------------------------------------------------------ |
|
|
168
|
+
| `step` | `Store<ExperienceStep>` | Reactive store containing the step's `id` and `label` |
|
|
169
|
+
| `fields` | `Store<FormField[]>` | Reactive store of fields with their current values, errors, and event handlers |
|
|
170
|
+
| `isActive` | `Store<boolean>` (Svelte) / `boolean` (React) | Whether this step is currently active in the router |
|
|
171
|
+
| `form` | Object | Form submission handlers (see Forms section) |
|
|
172
|
+
|
|
173
|
+
## Forms
|
|
174
|
+
|
|
175
|
+
When a step has fields, `getStep()` / `useStep()` provides a `form` object for handling submission, validation, and navigation.
|
|
176
|
+
|
|
177
|
+
### Handling Submission
|
|
178
|
+
|
|
179
|
+
Bind `form.props` to your `<form>` element's `onsubmit` handler:
|
|
180
|
+
|
|
181
|
+
:::code-group
|
|
182
|
+
|
|
183
|
+
```svelte [Svelte]
|
|
184
|
+
<script lang="ts">
|
|
185
|
+
import { getStep } from '@picked/svelte/hooks'
|
|
186
|
+
|
|
187
|
+
const { fields, form } = getStep()
|
|
188
|
+
const isSubmitting = form.submitting
|
|
189
|
+
</script>
|
|
190
|
+
|
|
191
|
+
<form {...form.props}>
|
|
192
|
+
{#each $fields as field}
|
|
193
|
+
<input
|
|
194
|
+
name={field.id}
|
|
195
|
+
value={field.value ?? ''}
|
|
196
|
+
onchange={field.onChange}
|
|
197
|
+
onblur={field.onBlur}
|
|
198
|
+
/>
|
|
199
|
+
{#if field.error && field.touched}
|
|
200
|
+
<p class="error">{field.error.userMessage}</p>
|
|
201
|
+
{/if}
|
|
202
|
+
{/each}
|
|
203
|
+
|
|
204
|
+
<button type="submit" disabled={$isSubmitting}>
|
|
205
|
+
{$isSubmitting ? 'Submitting…' : 'Continue'}
|
|
206
|
+
</button>
|
|
207
|
+
</form>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
```tsx [React]
|
|
211
|
+
import { useStep } from '@picked/react/hooks'
|
|
212
|
+
import { useUnit } from 'effector-react'
|
|
213
|
+
|
|
214
|
+
function StepForm() {
|
|
215
|
+
const { fields, form } = useStep()
|
|
216
|
+
const currentFields = useUnit(fields)
|
|
217
|
+
const isSubmitting = useUnit(form.submitting)
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<form {...form.props}>
|
|
221
|
+
{currentFields.map((field) => (
|
|
222
|
+
<div key={field.id}>
|
|
223
|
+
<input
|
|
224
|
+
name={field.id}
|
|
225
|
+
value={field.value ?? ''}
|
|
226
|
+
onChange={field.onChange}
|
|
227
|
+
onBlur={field.onBlur}
|
|
228
|
+
/>
|
|
229
|
+
{field.error && field.touched && <p className="error">{field.error.userMessage}</p>}
|
|
230
|
+
</div>
|
|
231
|
+
))}
|
|
232
|
+
|
|
233
|
+
<button type="submit" disabled={isSubmitting}>
|
|
234
|
+
{isSubmitting ? 'Submitting…' : 'Continue'}
|
|
235
|
+
</button>
|
|
236
|
+
</form>
|
|
237
|
+
)
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
:::
|
|
242
|
+
|
|
243
|
+
Submitting the form:
|
|
244
|
+
|
|
245
|
+
1. Collects field values from the HTML form
|
|
246
|
+
2. Runs `onSubmit` transform callbacks (if any)
|
|
247
|
+
3. Validates all required fields and field validation rules
|
|
248
|
+
4. Commits the responses to the experience state
|
|
249
|
+
5. Fires `form_submit_success` or `form_submit_error` on the event bus
|
|
250
|
+
6. Navigates to the next step (unless `stopNavigation` is called)
|
|
251
|
+
|
|
252
|
+
### Transforming Data Before Submission
|
|
253
|
+
|
|
254
|
+
Use `form.onBeforeSubmit` to intercept and transform field data before it is committed. Callbacks run in series, each receiving the output of the previous:
|
|
255
|
+
|
|
256
|
+
:::code-group
|
|
257
|
+
|
|
258
|
+
```svelte [Svelte]
|
|
259
|
+
<script lang="ts">
|
|
260
|
+
import { getStep } from '@picked/svelte/hooks'
|
|
261
|
+
|
|
262
|
+
const { form } = getStep()
|
|
263
|
+
|
|
264
|
+
form.onBeforeSubmit(async (data) => {
|
|
265
|
+
// Normalize email to lowercase before committing
|
|
266
|
+
return {
|
|
267
|
+
...data,
|
|
268
|
+
'email-address': String(data['email-address']).toLowerCase(),
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
</script>
|
|
272
|
+
|
|
273
|
+
<form {...form.props}>{/* ... */}</form>
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
```tsx [React]
|
|
277
|
+
import { useStep } from '@picked/react/hooks'
|
|
278
|
+
|
|
279
|
+
function ContactStep() {
|
|
280
|
+
const { form } = useStep()
|
|
281
|
+
|
|
282
|
+
form.onBeforeSubmit(async (data) => {
|
|
283
|
+
// Normalize email to lowercase before committing
|
|
284
|
+
return {
|
|
285
|
+
...data,
|
|
286
|
+
'email-address': String(data['email-address']).toLowerCase(),
|
|
287
|
+
}
|
|
288
|
+
})
|
|
289
|
+
|
|
290
|
+
return <form {...form.props}>{/* ... */}</form>
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
:::
|
|
295
|
+
|
|
296
|
+
### Success and Error Callbacks
|
|
297
|
+
|
|
298
|
+
Register callbacks for submission outcomes using `form.onSuccess` and `form.onError`:
|
|
299
|
+
|
|
300
|
+
:::code-group
|
|
301
|
+
|
|
302
|
+
```svelte [Svelte]
|
|
303
|
+
<script lang="ts">
|
|
304
|
+
import { getStep } from '@picked/svelte/hooks'
|
|
305
|
+
|
|
306
|
+
const { form } = getStep()
|
|
307
|
+
|
|
308
|
+
form.onSuccess(async ({ data }) => {
|
|
309
|
+
// Call your backend after responses are committed
|
|
310
|
+
await fetch('/api/submit', {
|
|
311
|
+
method: 'POST',
|
|
312
|
+
body: JSON.stringify(data),
|
|
313
|
+
})
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
form.onError((errors) => {
|
|
317
|
+
console.error('Validation errors:', errors)
|
|
318
|
+
})
|
|
319
|
+
</script>
|
|
320
|
+
|
|
321
|
+
<form {...form.props}>{/* ... */}</form>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
```tsx [React]
|
|
325
|
+
import { useStep } from '@picked/react/hooks'
|
|
326
|
+
|
|
327
|
+
function ContactStep() {
|
|
328
|
+
const { form } = useStep()
|
|
329
|
+
|
|
330
|
+
form.onSuccess(async ({ data }) => {
|
|
331
|
+
// Call your backend after responses are committed
|
|
332
|
+
await fetch('/api/submit', {
|
|
333
|
+
method: 'POST',
|
|
334
|
+
body: JSON.stringify(data),
|
|
335
|
+
})
|
|
336
|
+
})
|
|
337
|
+
|
|
338
|
+
form.onError((errors) => {
|
|
339
|
+
console.error('Validation errors:', errors)
|
|
340
|
+
})
|
|
341
|
+
|
|
342
|
+
return <form {...form.props}>{/* ... */}</form>
|
|
343
|
+
}
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
:::
|
|
347
|
+
|
|
348
|
+
Callbacks registered via `onSuccess` and `onError` are automatically cleaned up when the component unmounts — no manual teardown is needed.
|
|
349
|
+
|
|
350
|
+
### Preventing Navigation on Success
|
|
351
|
+
|
|
352
|
+
By default, the experience advances to the next step after a successful submission. Call `stopNavigation()` inside `onSuccess` to prevent this, for example when you need to handle navigation manually:
|
|
353
|
+
|
|
354
|
+
:::code-group
|
|
355
|
+
|
|
356
|
+
```svelte [Svelte]
|
|
357
|
+
<script lang="ts">
|
|
358
|
+
import { getStep } from '@picked/svelte/hooks'
|
|
359
|
+
import { getExperience } from '@picked/svelte/hooks'
|
|
360
|
+
|
|
361
|
+
const { form } = getStep()
|
|
362
|
+
const experience = getExperience()
|
|
363
|
+
|
|
364
|
+
form.onSuccess(async ({ data, stopNavigation }) => {
|
|
365
|
+
stopNavigation()
|
|
366
|
+
|
|
367
|
+
// Navigate to step based on submitted data
|
|
368
|
+
if (data['plan-type'] === 'enterprise') {
|
|
369
|
+
experience.goToStepById('enterprise-contact')
|
|
370
|
+
} else {
|
|
371
|
+
experience.goToNextStep()
|
|
372
|
+
}
|
|
373
|
+
})
|
|
374
|
+
</script>
|
|
375
|
+
|
|
376
|
+
<form {...form.props}>{/* ... */}</form>
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
```tsx [React]
|
|
380
|
+
import { useStep } from '@picked/react/hooks'
|
|
381
|
+
import { useExperience } from '@picked/react/hooks'
|
|
382
|
+
|
|
383
|
+
function PlanStep() {
|
|
384
|
+
const { form } = useStep()
|
|
385
|
+
const experience = useExperience()
|
|
386
|
+
|
|
387
|
+
form.onSuccess(async ({ data, stopNavigation }) => {
|
|
388
|
+
stopNavigation()
|
|
389
|
+
|
|
390
|
+
// Decide the next step based on submitted data
|
|
391
|
+
if (data['plan-type'] === 'enterprise') {
|
|
392
|
+
experience.goToStepById('enterprise-contact')
|
|
393
|
+
} else {
|
|
394
|
+
experience.goToNextStep()
|
|
395
|
+
}
|
|
396
|
+
})
|
|
397
|
+
|
|
398
|
+
return <form {...form.props}>{/* ... */}</form>
|
|
399
|
+
}
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
:::
|
|
403
|
+
|
|
404
|
+
## Best Practices
|
|
405
|
+
|
|
406
|
+
- **Give steps meaningful labels**: The `label` is used in analytics events and the dashboard — prefer descriptive names like `"Contact Details"` over `"Step 2"`
|
|
407
|
+
- **Keep steps focused**: Each step should collect a small, related set of information. Prefer more steps over longer forms to reduce abandonment
|
|
408
|
+
- **Use conditionals for branching**: Avoid duplicating steps — model branching logic with `nextConditional()` so shared steps can be reused
|
|
409
|
+
- **Use `stopNavigation` sparingly**: Automatic navigation after submit is the expected behavior. Only disable it when you need explicit control over the next destination
|
|
410
|
+
- **Validate eagerly on blur, not on change**: The SDK follows this pattern automatically — fields show errors after the user leaves them, not as they type
|
|
411
|
+
- **Lazy-load large step components**: Use the `component` prop on `<Step>` with a dynamic import for content that is only shown to a subset of users
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Steps
|
|
6
|
+
|
|
7
|
+
A step is a visual screen or card shown to visitors during an experience. Each step holds one or more fields that collect data or display content.
|
|
8
|
+
|
|
9
|
+
## Create a step
|
|
10
|
+
|
|
11
|
+
1. Open your project.
|
|
12
|
+
2. Click **Steps** in the sidebar.
|
|
13
|
+
3. Click **New Step**.
|
|
14
|
+
4. Enter a name and key.
|
|
15
|
+
5. Click **Create**.
|
|
16
|
+
|
|
17
|
+
The key is a unique identifier used in your application. It's set once and can't be changed later.
|
|
18
|
+
|
|
19
|
+
## Configure a step
|
|
20
|
+
|
|
21
|
+
**Name**: The display name shown in the dashboard. Not visible to visitors.
|
|
22
|
+
|
|
23
|
+
**Key**: The programmatic identifier used by your application to reference this step. Not visible to visitors.
|
|
24
|
+
|
|
25
|
+
**Layout Name**: The name of the component layout used to render this step. For example, `card`, `modal`, or `fullscreen`.
|
|
26
|
+
|
|
27
|
+
## Assign fields
|
|
28
|
+
|
|
29
|
+
In the flow builder, drag a field from the entity browser onto a step node. The field appears in the step's **Assigned Fields** list in the inspector.
|
|
30
|
+
|
|
31
|
+
You can also view and manage assigned fields by selecting the step node and expanding the **Assigned Fields** section. Click any field to open its inspector.
|
|
32
|
+
|
|
33
|
+
## Reuse steps
|
|
34
|
+
|
|
35
|
+
Steps are project-level entities. You can drag the same step into multiple experience flows. Changes to a step's configuration apply everywhere it's used.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Team management
|
|
6
|
+
|
|
7
|
+
Manage who has access to your organization and what they can do. Organizations are the top-level container for projects and members.
|
|
8
|
+
|
|
9
|
+
## Organizations
|
|
10
|
+
|
|
11
|
+
An organization groups your projects, members, and settings. You can belong to multiple organizations.
|
|
12
|
+
|
|
13
|
+
Switch between organizations using the organization selector in the top of the sidebar.
|
|
14
|
+
|
|
15
|
+
## Invite members
|
|
16
|
+
|
|
17
|
+
1. Open your organization.
|
|
18
|
+
2. Click **Members**.
|
|
19
|
+
3. Click **Invite**.
|
|
20
|
+
4. Enter an email address.
|
|
21
|
+
5. Select a role.
|
|
22
|
+
6. Click **Send Invite**.
|
|
23
|
+
|
|
24
|
+
The invited user receives an email with a link to join your organization. They need to create a Picked account if they don't have one.
|
|
25
|
+
|
|
26
|
+
## Remove members
|
|
27
|
+
|
|
28
|
+
1. Open your organization.
|
|
29
|
+
2. Click **Members**.
|
|
30
|
+
3. Find the member you want to remove.
|
|
31
|
+
4. Click **Remove** next to their name.
|
|
32
|
+
5. Confirm the removal.
|
|
33
|
+
|
|
34
|
+
The member immediately loses access to all projects in the organization.
|
|
35
|
+
|
|
36
|
+
## Roles and permissions
|
|
37
|
+
|
|
38
|
+
Members are assigned roles that control what they can access. Roles determine whether a member can create projects, edit experiences, manage other members, or view reports.
|
|
39
|
+
|
|
40
|
+
Assign the minimum role needed for each member's responsibilities.
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Chrome Extension
|
|
6
|
+
|
|
7
|
+
The Picked Developer Tools extension adds a Picked panel to Chrome DevTools for inspecting and debugging your Picked integration on any page running the SDK.
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
Install from the [Chrome Web Store](https://chromewebstore.google.com/detail/picked-developer-tools/nimmdamgnhlhdpngnalkpmnleebngidh).
|
|
14
|
+
|
|
15
|
+
## Setup
|
|
16
|
+
|
|
17
|
+
Add the `svelteDevtoolsPlugin` to your Picked client so the extension can connect to the SDK.
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { createPicked } from '@picked/client'
|
|
21
|
+
import { svelteDevtoolsPlugin } from '@picked/svelte/plugins/devtools'
|
|
22
|
+
|
|
23
|
+
const picked = createPicked({
|
|
24
|
+
projectId: 'your-project-id',
|
|
25
|
+
plugins: [
|
|
26
|
+
svelteDevtoolsPlugin(),
|
|
27
|
+
],
|
|
28
|
+
})
|
|
29
|
+
```
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Google Tag Manager template
|
|
6
|
+
|
|
7
|
+
The Picked Ecommerce GTM Tag Template lets you track ecommerce events and send them to Picked directly from Google Tag Manager.
|
|
8
|
+
|
|
9
|
+
## Automatic installation
|
|
10
|
+
|
|
11
|
+
Install the template from the GTM Community Gallery:
|
|
12
|
+
|
|
13
|
+
1. In Tag Manager, click **Templates**.
|
|
14
|
+
2. In the **Tag Templates** section, click **Search Gallery**.
|
|
15
|
+
3. Search for `Picked Ecommerce`.
|
|
16
|
+
4. Click the Picked Ecommerce template to view details.
|
|
17
|
+
5. Click **Add to workspace**.
|
|
18
|
+
6. Review the required permissions and click **Add**.
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
## Manual installation
|
|
23
|
+
|
|
24
|
+
If you prefer to import the template file directly:
|
|
25
|
+
|
|
26
|
+
1. Download the [template file](https://github.com/picked-app/gtm-template/blob/main/template.tpl) from GitHub (use the download icon).
|
|
27
|
+
2. In Google Tag Manager, go to **Templates**.
|
|
28
|
+
3. Click **New**.
|
|
29
|
+
4. Open the three-dot menu and click **Import**.
|
|
30
|
+
5. Select the downloaded template file.
|
|
31
|
+
6. Click **Save**.
|
|
32
|
+
|
|
33
|
+
## Setup
|
|
34
|
+
|
|
35
|
+
### 1. Create a Tag ID variable
|
|
36
|
+
|
|
37
|
+
Sign in to the [Picked Dashboard](https://dashboard.picked.app) and copy your project Tag ID. Save it as a constant variable in GTM (e.g. `Picked Tag ID`).
|
|
38
|
+
|
|
39
|
+

|
|
40
|
+
|
|
41
|
+
### 2. Create an ecommerce data variable
|
|
42
|
+
|
|
43
|
+
Create a **Data Layer Variable** with the variable name set to `ecommerce`. This captures the GA4 Enhanced Ecommerce data layer.
|
|
44
|
+
|
|
45
|
+

|
|
46
|
+
|
|
47
|
+
### 3. Create event triggers
|
|
48
|
+
|
|
49
|
+
Add a trigger for each ecommerce event you want to track (e.g. `add_to_cart`, `purchase`, `view_item`).
|
|
50
|
+
|
|
51
|
+

|
|
52
|
+
|
|
53
|
+
### 4. Create tags
|
|
54
|
+
|
|
55
|
+
Create a new tag for each event, selecting the **Picked Ecommerce** tag template. Assign the matching trigger and configure the options below.
|
|
56
|
+
|
|
57
|
+

|
|
58
|
+
|
|
59
|
+
## Configuration options
|
|
60
|
+
|
|
61
|
+
| Option | Description |
|
|
62
|
+
| --- | --- |
|
|
63
|
+
| **Tag ID** | Your Picked project Tag ID. Find it in the [Picked Dashboard](https://dashboard.picked.app). |
|
|
64
|
+
| **Event** | The ecommerce event to track (e.g. `add_to_cart`, `purchase`). |
|
|
65
|
+
| **Send ecommerce data** | Enable this to send GA4 Enhanced Ecommerce data to Picked. Should be enabled for all ecommerce events. |
|
|
66
|
+
| **GA4 Enhanced Ecommerce Data** | The GTM variable containing GA4 ecommerce data. Use the data layer variable created in step 2. |
|
|
67
|
+
| **Additional data** | Optional GTM variable for sending extra metadata with the event. |
|
|
68
|
+
|
|
69
|
+

|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
---
|
|
2
|
+
layout: docs
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Tooling
|
|
6
|
+
|
|
7
|
+
Build tools and developer utilities for working with Picked.
|
|
8
|
+
|
|
9
|
+
## Vite Plugin
|
|
10
|
+
|
|
11
|
+
The [`@picked/vite-plugin-picked`](/tooling/vite-plugin) package integrates Picked into your Vite-based project. It fetches your project configuration at build time and provides a local launcher for previewing experiences during development.
|
|
12
|
+
|
|
13
|
+
[Get started with the Vite Plugin →](/tooling/vite-plugin)
|
|
14
|
+
|
|
15
|
+
## Chrome Extension
|
|
16
|
+
|
|
17
|
+
The [Picked Developer Tools](/tooling/chrome-extension) extension adds a dedicated panel to Chrome DevTools for inspecting and debugging your Picked integration on any page running the SDK.
|
|
18
|
+
|
|
19
|
+
[Get started with the Chrome Extension →](/tooling/chrome-extension)
|