@picked/client 0.0.1-dev.1776662399138 → 0.0.1-dev.1776837084253
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-C5p0q172.js → api-6oxKA__k.js} +1 -1
- package/dist/{api-CE3ISEsc.cjs → api-CIC-Uysx.cjs} +1 -1
- package/dist/cjs/form/index.js +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/plugins/create-experience/index.js +1 -1
- package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
- package/dist/cjs/plugins/experience-browser-storage/index.js +1 -1
- package/dist/cjs/plugins/single-page-app/index.js +1 -1
- package/dist/cjs/plugins/web-components/index.js +1 -1
- package/dist/cjs/plugins/window-object/index.js +1 -1
- package/dist/cjs/server/index.js +1 -1
- package/dist/docs/pickedql/data-sources.md +61 -2
- package/dist/docs/pickedql/examples.md +84 -0
- package/dist/docs/pickedql/index.md +1 -0
- package/dist/docs/pickedql/schema.md +28 -0
- package/dist/docs/pickedql/virtual-functions.md +40 -3
- package/dist/docs/sdk/actions.md +31 -1
- package/dist/docs/sdk/conditions.md +14 -8
- package/dist/docs/sdk/experiences.md +21 -18
- package/dist/docs/sdk/features.md +8 -8
- package/dist/docs/sdk/fields.md +9 -9
- package/dist/docs/sdk/steps.md +12 -12
- package/dist/esm/form/index.js +1 -1
- package/dist/esm/index.js +158 -284
- package/dist/esm/plugins/create-experience/index.js +1 -1
- package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
- package/dist/esm/plugins/experience-browser-storage/index.js +1 -1
- package/dist/esm/plugins/single-page-app/index.js +28 -14
- package/dist/esm/plugins/web-components/index.js +1 -1
- package/dist/esm/plugins/window-object/index.js +1 -1
- package/dist/esm/server/index.js +1 -1
- package/dist/experience-CNIhapU2.js +136 -0
- package/dist/experience-CTEBY-it.cjs +1 -0
- package/dist/experience-instance-Cu8oGGr9.cjs +1 -0
- package/dist/experience-instance-DIpWYaA6.js +387 -0
- package/dist/nodes-2fst8XKi.js +101 -0
- package/dist/nodes-DBK4N9YY.cjs +1 -0
- package/dist/rules-logic-D7dL30U1.js +263 -0
- package/dist/rules-logic-DJhGFqhC.cjs +1 -0
- package/dist/types/plugins/single-page-app/plugin.d.ts +15 -4
- package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/experience-instance-DG9HFNSE.cjs +0 -1
- package/dist/experience-instance-DffMstSs.js +0 -486
- package/dist/object-C82v79xc.js +0 -25
- package/dist/object-CUJOjanb.cjs +0 -1
- package/dist/rules-logic-B--rEvGw.js +0 -240
- package/dist/rules-logic-D_dZ52-Q.cjs +0 -1
- /package/dist/{id-Bv44ilEo.cjs → id-Cg7fVl1O.cjs} +0 -0
- /package/dist/{id-CRqy981z.js → id-n2yrHvNo.js} +0 -0
- /package/dist/{logger-6z_gb4rA.js → logger-C44jSdYl.js} +0 -0
- /package/dist/{logger-fbvQC40v.cjs → logger-CJUj90QX.cjs} +0 -0
- /package/dist/{supports-0XIfd4-R.js → supports-B_trw6lj.js} +0 -0
- /package/dist/{supports-Dsjg-82e.cjs → supports-CKSVYpQx.cjs} +0 -0
|
@@ -4,13 +4,15 @@ layout: docs
|
|
|
4
4
|
|
|
5
5
|
# Conditions
|
|
6
6
|
|
|
7
|
-
Conditions
|
|
7
|
+
Conditions use JSON Logic to evaluate client state. Use them to gate experience activation, branch step navigation, and control field visibility.
|
|
8
8
|
|
|
9
|
-
## Conditions in
|
|
9
|
+
## Conditions in experiences
|
|
10
10
|
|
|
11
|
-
A common
|
|
11
|
+
A common pattern is using conditions between steps to branch the flow based on form responses:
|
|
12
12
|
|
|
13
13
|
```ts
|
|
14
|
+
import { createExperience } from '@picked/client/plugins/create-experience'
|
|
15
|
+
|
|
14
16
|
const questionaireFunnel = createExperience({
|
|
15
17
|
id: 'mini-funnel',
|
|
16
18
|
// experience config
|
|
@@ -30,7 +32,7 @@ const isSigningUpForNewsletter = funnel.addConditional({
|
|
|
30
32
|
condition: {
|
|
31
33
|
'==': [
|
|
32
34
|
{
|
|
33
|
-
var: 'responses.sign-up-for-newsletter-field',
|
|
35
|
+
var: 'responses.sign-up-for-newsletter-field',
|
|
34
36
|
},
|
|
35
37
|
true,
|
|
36
38
|
],
|
|
@@ -43,11 +45,13 @@ isSigningUpForNewsletter.addTrue(signUserUpToNewsletter)
|
|
|
43
45
|
isSigningUpForNewsletter.addFalse(userDoesNotWantNewsletter)
|
|
44
46
|
```
|
|
45
47
|
|
|
46
|
-
## Conditional
|
|
48
|
+
## Conditional fields
|
|
47
49
|
|
|
48
|
-
Fields can be shown or hidden based on previous responses or predicates using JSON Logic conditions:
|
|
50
|
+
Fields can be shown or hidden based on previous responses or [predicates](./predicates) using JSON Logic conditions:
|
|
49
51
|
|
|
50
52
|
```ts
|
|
53
|
+
import { createField } from '@picked/client/plugins/create-experience'
|
|
54
|
+
|
|
51
55
|
// Show email field only if user selected "email" as a contact method
|
|
52
56
|
export const emailField = createField({
|
|
53
57
|
id: 'email-input',
|
|
@@ -60,7 +64,7 @@ export const emailField = createField({
|
|
|
60
64
|
in: [
|
|
61
65
|
'email',
|
|
62
66
|
{
|
|
63
|
-
var: 'responses.communication-methods',
|
|
67
|
+
var: 'responses.communication-methods',
|
|
64
68
|
},
|
|
65
69
|
],
|
|
66
70
|
},
|
|
@@ -87,11 +91,13 @@ export const mailingAddressField = createField({
|
|
|
87
91
|
})
|
|
88
92
|
```
|
|
89
93
|
|
|
90
|
-
## Field
|
|
94
|
+
## Field options with conditions
|
|
91
95
|
|
|
92
96
|
Individual options within a field can also have conditional visibility:
|
|
93
97
|
|
|
94
98
|
```ts
|
|
99
|
+
import { createField } from '@picked/client/plugins/create-experience'
|
|
100
|
+
|
|
95
101
|
export const contactMethodsField = createField({
|
|
96
102
|
id: 'contact-methods',
|
|
97
103
|
name: 'contact-methods',
|
|
@@ -4,38 +4,41 @@ layout: docs
|
|
|
4
4
|
|
|
5
5
|
# Experiences
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Define experiences in code with `createExperience()`, or load them from the dashboard at runtime with the [Dynamic Experiences Plugin](./plugins/dynamic-experiences).
|
|
8
8
|
|
|
9
|
-
## Creating
|
|
9
|
+
## Creating experiences
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
import { createExperience } from '@picked/client/plugins/create-experience'
|
|
13
|
+
import { adaptSvelteComponent } from '@picked/svelte'
|
|
14
|
+
import appCss from '../app.css?inline'
|
|
13
15
|
|
|
14
16
|
export const productPageExperience = createExperience({
|
|
15
17
|
id: 'product-page-experience',
|
|
16
|
-
name: 'Product Page Experience,
|
|
18
|
+
name: 'Product Page Experience',
|
|
17
19
|
condition: {
|
|
18
20
|
'==': [
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
]
|
|
24
|
-
}
|
|
21
|
+
{ var: 'location.pathname' },
|
|
22
|
+
'/product/',
|
|
23
|
+
],
|
|
24
|
+
},
|
|
25
25
|
targets: [{ selector: 'body', placement: 'after' }],
|
|
26
|
-
component: adaptSvelteComponent(
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
component: adaptSvelteComponent(
|
|
27
|
+
import('../ui/ProductPageExperience.svelte'),
|
|
28
|
+
{ css: [appCss] },
|
|
29
|
+
),
|
|
29
30
|
})
|
|
30
31
|
```
|
|
31
32
|
|
|
32
|
-
|
|
33
|
+
Register experiences using the [Create Experience Plugin](./plugins/create-experience) for code-defined experiences, or the [Dynamic Experiences Plugin](./plugins/dynamic-experiences) to fetch and manage them from the dashboard at runtime.
|
|
34
|
+
|
|
35
|
+
## How experiences work
|
|
33
36
|
|
|
34
37
|
When an experience is registered, the SDK follows this execution flow:
|
|
35
38
|
|
|
36
|
-
1. **Registration**: Experiences are registered to the Picked client using [createExperiencePlugin](./plugins/create-experience
|
|
37
|
-
2. **Condition
|
|
38
|
-
3. **Target
|
|
39
|
+
1. **Registration**: Experiences are registered to the Picked client using [createExperiencePlugin](./plugins/create-experience) for code-defined experiences, or [dynamicExperiencesPlugin](./plugins/dynamic-experiences) for dashboard-managed experiences
|
|
40
|
+
2. **Condition evaluation**: The SDK evaluates the experience's `condition` using the logic engine to determine if it should be shown
|
|
41
|
+
3. **Target resolution**: The SDK searches the DOM for elements matching the `targets` selectors (e.g., `body`, `.product-page`, `#checkout`)
|
|
39
42
|
4. **Initialization**: If the condition evaluates to `true` and at least one target element exists, the experience is initialized
|
|
40
|
-
5. **Component
|
|
41
|
-
6. **Flow
|
|
43
|
+
5. **Component rendering**: The experience's component is rendered and injected into the DOM at the specified target location and placement (before, after, append, prepend, or replace)
|
|
44
|
+
6. **Flow execution**: If the experience contains steps, fields, and conditionals, users can progress through the multi-step flow with validation and branching logic
|
|
@@ -4,9 +4,9 @@ layout: docs
|
|
|
4
4
|
|
|
5
5
|
# Features
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Define feature flags with a `decide` function that resolves to a bucket value, access results through framework hooks, and invalidate cached decisions by bumping the version.
|
|
8
8
|
|
|
9
|
-
## Defining
|
|
9
|
+
## Defining features
|
|
10
10
|
|
|
11
11
|
Define features when creating the Picked client by passing a `features` object. Each feature requires a unique identifier, a versioning key, a human-readable name, and a `decide` function:
|
|
12
12
|
|
|
@@ -51,7 +51,7 @@ features: {
|
|
|
51
51
|
}
|
|
52
52
|
```
|
|
53
53
|
|
|
54
|
-
## How
|
|
54
|
+
## How features work
|
|
55
55
|
|
|
56
56
|
When a feature is registered, the SDK follows this execution order:
|
|
57
57
|
|
|
@@ -61,7 +61,7 @@ When a feature is registered, the SDK follows this execution order:
|
|
|
61
61
|
4. **Storage**: Once resolved, the bucket value is persisted to browser storage for consistency across page loads
|
|
62
62
|
5. **Event Emission**: A `feature_decide` event is fired on the event bus when a feature is resolved for the first time
|
|
63
63
|
|
|
64
|
-
## URL-
|
|
64
|
+
## URL-based overrides
|
|
65
65
|
|
|
66
66
|
You can override feature decisions via URL search parameters for testing purposes:
|
|
67
67
|
|
|
@@ -79,7 +79,7 @@ The format is `?picked-feature=<feature-id>:<bucket-value>`.
|
|
|
79
79
|
|
|
80
80
|
This is useful for QA testing specific feature variants without modifying code. The override is persisted in session storage and will be cleared when the browser tab is closed.
|
|
81
81
|
|
|
82
|
-
## Accessing
|
|
82
|
+
## Accessing features
|
|
83
83
|
|
|
84
84
|
Once features are defined, you can access their resolved bucket values in your application code. The SDK provides framework-specific hooks and a framework-agnostic event bus for subscribing to feature decisions.
|
|
85
85
|
|
|
@@ -132,7 +132,7 @@ function MyComponent() {
|
|
|
132
132
|
|
|
133
133
|
:::
|
|
134
134
|
|
|
135
|
-
## Using
|
|
135
|
+
## Using features in experience conditions
|
|
136
136
|
|
|
137
137
|
Features can be used with experience conditions via JSON logic:
|
|
138
138
|
|
|
@@ -156,7 +156,7 @@ const myExperience = createExperience({
|
|
|
156
156
|
})
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
## Listening to
|
|
159
|
+
## Listening to feature decisions
|
|
160
160
|
|
|
161
161
|
Subscribe to the `feature_decide` event to track when features are resolved:
|
|
162
162
|
|
|
@@ -206,7 +206,7 @@ features: {
|
|
|
206
206
|
|
|
207
207
|
For features managed through the dashboard, versioning is handled automatically — the dashboard appends the version number to the cache key used by the SDK.
|
|
208
208
|
|
|
209
|
-
## Best
|
|
209
|
+
## Best practices
|
|
210
210
|
|
|
211
211
|
- **Use `session` storage for temporary tests**: Set `storage: 'session'` for short-lived experiments that shouldn't persist across browser sessions
|
|
212
212
|
- **Keep `decide` functions fast**: The function blocks experience rendering, so avoid heavy computations or slow network calls
|
package/dist/docs/sdk/fields.md
CHANGED
|
@@ -4,9 +4,9 @@ layout: docs
|
|
|
4
4
|
|
|
5
5
|
# Fields
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Define fields in code with `createField()`, validate input with JSON Logic, and read submitted values through step context.
|
|
8
8
|
|
|
9
|
-
## Defining
|
|
9
|
+
## Defining fields
|
|
10
10
|
|
|
11
11
|
Define fields using `createField()` from the `@picked/client/plugins/create-experience` package. Each field requires a unique identifier, name, type, label, and cardinality:
|
|
12
12
|
|
|
@@ -52,7 +52,7 @@ export const communicationMethods = createField({
|
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
## How
|
|
55
|
+
## How fields work
|
|
56
56
|
|
|
57
57
|
When a field is registered and used in an experience:
|
|
58
58
|
|
|
@@ -63,7 +63,7 @@ When a field is registered and used in an experience:
|
|
|
63
63
|
5. **Storage**: Valid responses are stored in the experience state under `responses[field.name]`
|
|
64
64
|
6. **Reference**: Field values can be referenced in subsequent field conditions, step conditions, or experience logic via `{ var: 'responses.field-name' }`
|
|
65
65
|
|
|
66
|
-
## Field
|
|
66
|
+
## Field types
|
|
67
67
|
|
|
68
68
|
Fields support four primitive types, `text`, `number`, `boolean` and `object`:
|
|
69
69
|
|
|
@@ -129,7 +129,7 @@ const conditionalField = createField({
|
|
|
129
129
|
})
|
|
130
130
|
```
|
|
131
131
|
|
|
132
|
-
## Field
|
|
132
|
+
## Field validation
|
|
133
133
|
|
|
134
134
|
Validate user input using JSON Logic rules. The `$input` variable contains the current field value:
|
|
135
135
|
|
|
@@ -179,7 +179,7 @@ const quantityField = createField({
|
|
|
179
179
|
The `catch`/`throw` pattern in JSON Logic validates that the condition evaluates to `true`. If it doesn't, the `throw` message is displayed to the user.
|
|
180
180
|
:::
|
|
181
181
|
|
|
182
|
-
## Field
|
|
182
|
+
## Field policies
|
|
183
183
|
|
|
184
184
|
Control how field data is tracked and stored using privacy policies:
|
|
185
185
|
|
|
@@ -205,7 +205,7 @@ const sensitiveField = createField({
|
|
|
205
205
|
|
|
206
206
|
Use these policies for sensitive data like SSNs, credit cards, or passwords that should only exist client-side.
|
|
207
207
|
|
|
208
|
-
## Field
|
|
208
|
+
## Field metadata
|
|
209
209
|
|
|
210
210
|
Enhance user experience with additional descriptive text:
|
|
211
211
|
|
|
@@ -229,7 +229,7 @@ const passwordField = createField({
|
|
|
229
229
|
- `description`: Brief explanation shown below the label
|
|
230
230
|
- `helpText`: Additional guidance or requirements displayed near the field
|
|
231
231
|
|
|
232
|
-
## Accessing
|
|
232
|
+
## Accessing field values
|
|
233
233
|
|
|
234
234
|
Field responses are stored in the experience state and can be accessed via the `responses` object:
|
|
235
235
|
|
|
@@ -251,7 +251,7 @@ const sensitiveField = createField({
|
|
|
251
251
|
|
|
252
252
|
:::
|
|
253
253
|
|
|
254
|
-
## Best
|
|
254
|
+
## Best practices
|
|
255
255
|
|
|
256
256
|
- **Use semantic IDs and names**: Name fields descriptively (e.g., `email-address` not `field1`) for easier debugging and analytics
|
|
257
257
|
- **Match type to data**: Use `number` for numeric values, not `text`, to enable proper validation and comparison
|
package/dist/docs/sdk/steps.md
CHANGED
|
@@ -4,9 +4,9 @@ layout: docs
|
|
|
4
4
|
|
|
5
5
|
# Steps
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Render steps with `<StepRouter>` and `<Step>` from `@picked/react` or `@picked/svelte`, and access the active step through `useStep()` / `getStep()`.
|
|
8
8
|
|
|
9
|
-
## How
|
|
9
|
+
## How steps work
|
|
10
10
|
|
|
11
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
12
|
|
|
@@ -18,7 +18,7 @@ When an experience starts, its steps are connected in a directed node graph. The
|
|
|
18
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
19
|
7. **Completion**: When no further steps exist, the experience flow is complete
|
|
20
20
|
|
|
21
|
-
## Step
|
|
21
|
+
## Step routing
|
|
22
22
|
|
|
23
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
24
|
|
|
@@ -72,7 +72,7 @@ function MyExperience() {
|
|
|
72
72
|
All Steps must be wrapped in a router, even if it is a single Step
|
|
73
73
|
:::
|
|
74
74
|
|
|
75
|
-
### Lazy-
|
|
75
|
+
### Lazy-loaded steps
|
|
76
76
|
|
|
77
77
|
For large experiences, steps can be lazily loaded using dynamic imports:
|
|
78
78
|
|
|
@@ -100,7 +100,7 @@ const WelcomeScreen = lazy(() => import('./WelcomeScreen'))
|
|
|
100
100
|
|
|
101
101
|
The `component` prop accepts a `Promise<Component>` — the step's content is not loaded until it becomes active.
|
|
102
102
|
|
|
103
|
-
## Accessing
|
|
103
|
+
## Accessing step context
|
|
104
104
|
|
|
105
105
|
Inside a `Step` component (or any component rendered within one), call `getStep()` / `useStep()` to access the step's reactive context:
|
|
106
106
|
|
|
@@ -123,7 +123,7 @@ Inside a `Step` component (or any component rendered within one), call `getStep(
|
|
|
123
123
|
onchange={field.onChange}
|
|
124
124
|
onblur={field.onBlur}
|
|
125
125
|
/>
|
|
126
|
-
{#if field.error && field.touched
|
|
126
|
+
{#if field.error && field.touched}
|
|
127
127
|
<p class="error">{field.error.userMessage}</p>
|
|
128
128
|
{/if}
|
|
129
129
|
{/each}
|
|
@@ -168,13 +168,13 @@ function ContactForm() {
|
|
|
168
168
|
| `step` | `Store<ExperienceStep>` | Reactive store containing the step's `id` and `label` |
|
|
169
169
|
| `fields` | `Store<FormField[]>` | Reactive store of fields with their current values, errors, and event handlers |
|
|
170
170
|
| `isActive` | `Store<boolean>` (Svelte) / `boolean` (React) | Whether this step is currently active in the router |
|
|
171
|
-
| `form` | Object | Form submission handlers (see Forms
|
|
171
|
+
| `form` | Object | Form submission handlers (see [Forms](#forms)) |
|
|
172
172
|
|
|
173
173
|
## Forms
|
|
174
174
|
|
|
175
175
|
When a step has fields, `getStep()` / `useStep()` provides a `form` object for handling submission, validation, and navigation.
|
|
176
176
|
|
|
177
|
-
### Handling
|
|
177
|
+
### Handling submission
|
|
178
178
|
|
|
179
179
|
Bind `form.props` to your `<form>` element's `onsubmit` handler:
|
|
180
180
|
|
|
@@ -249,7 +249,7 @@ Submitting the form:
|
|
|
249
249
|
5. Fires `form_submit_success` or `form_submit_error` on the event bus
|
|
250
250
|
6. Navigates to the next step (unless `stopNavigation` is called)
|
|
251
251
|
|
|
252
|
-
### Transforming
|
|
252
|
+
### Transforming data before submission
|
|
253
253
|
|
|
254
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
255
|
|
|
@@ -293,7 +293,7 @@ function ContactStep() {
|
|
|
293
293
|
|
|
294
294
|
:::
|
|
295
295
|
|
|
296
|
-
### Success and
|
|
296
|
+
### Success and error callbacks
|
|
297
297
|
|
|
298
298
|
Register callbacks for submission outcomes using `form.onSuccess` and `form.onError`:
|
|
299
299
|
|
|
@@ -347,7 +347,7 @@ function ContactStep() {
|
|
|
347
347
|
|
|
348
348
|
Callbacks registered via `onSuccess` and `onError` are automatically cleaned up when the component unmounts — no manual teardown is needed.
|
|
349
349
|
|
|
350
|
-
### Preventing
|
|
350
|
+
### Preventing navigation on success
|
|
351
351
|
|
|
352
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
353
|
|
|
@@ -401,7 +401,7 @@ function PlanStep() {
|
|
|
401
401
|
|
|
402
402
|
:::
|
|
403
403
|
|
|
404
|
-
## Best
|
|
404
|
+
## Best practices
|
|
405
405
|
|
|
406
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
407
|
- **Keep steps focused**: Each step should collect a small, related set of information. Prefer more steps over longer forms to reduce abandonment
|
package/dist/esm/form/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "../../rules-logic-
|
|
1
|
+
import { t as e } from "../../rules-logic-D7dL30U1.js";
|
|
2
2
|
import { attach as t, combine as n, createEffect as r, createEvent as i, createStore as a, sample as o, split as s } from "effector";
|
|
3
3
|
//#region src/form/build-responses.ts
|
|
4
4
|
function c(e, t, n) {
|