@picked/client 0.0.70 → 0.0.71-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/.tsbuildinfo +1 -0
- package/dist/api-B0ydpQBE.js +38 -0
- package/dist/api-CObostrU.cjs +1 -0
- package/dist/cjs/form/index.js +1 -1
- package/dist/cjs/index.js +2 -2
- package/dist/cjs/plugins/dom-observer/index.js +1 -1
- package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
- package/dist/cjs/server/index.js +1 -1
- package/dist/docs/explanation/conditions-and-the-logic-engine.md +94 -0
- package/dist/docs/explanation/feature-flag-allocation.md +176 -0
- package/dist/docs/explanation/how-picked-works.md +102 -0
- package/dist/docs/explanation/how-pickedql-works.md +76 -0
- package/dist/docs/explanation/pages-and-flows.md +64 -0
- package/dist/docs/explanation/the-content-model.md +77 -0
- package/dist/docs/explanation/the-two-apis.md +68 -0
- package/dist/docs/explanation/why-server-side-rendering.md +76 -0
- package/dist/docs/explanation/workspaces-and-versions.md +71 -0
- package/dist/docs/how-to/add-a-step-field-or-action.md +43 -0
- package/dist/docs/{pickedql/examples.md → how-to/analytics/index.md} +19 -6
- package/dist/docs/how-to/archive-or-delete-a-workspace.md +46 -0
- package/dist/docs/how-to/authenticate-with-a-magic-link.md +40 -0
- package/dist/docs/how-to/authenticate-with-a-password.md +51 -0
- package/dist/docs/how-to/authenticate-with-an-api-key.md +51 -0
- package/dist/docs/how-to/authenticate-with-oauth.md +40 -0
- package/dist/docs/{flow-builder/building-flows.md → how-to/build-a-flow.md} +13 -9
- package/dist/docs/how-to/connect-the-mcp-server.md +38 -0
- package/dist/docs/how-to/create-a-project.md +29 -0
- package/dist/docs/how-to/create-an-experience.md +42 -0
- package/dist/docs/how-to/create-and-revoke-an-api-key.md +37 -0
- package/dist/docs/how-to/debug-with-the-chrome-extension.md +57 -0
- package/dist/docs/how-to/define-a-page-layout.md +39 -0
- package/dist/docs/how-to/fill-and-publish-a-page.md +50 -0
- package/dist/docs/{gtm-template.md → how-to/install-the-gtm-template.md} +9 -3
- package/dist/docs/how-to/install-the-sdk.md +68 -0
- package/dist/docs/how-to/install-the-vite-plugin.md +56 -0
- package/dist/docs/how-to/invite-and-remove-members.md +34 -0
- package/dist/docs/how-to/preview-a-workspace.md +28 -0
- package/dist/docs/how-to/publish-a-workspace.md +30 -0
- package/dist/docs/how-to/read-a-feature-flag.md +101 -0
- package/dist/docs/how-to/register-a-component.md +55 -0
- package/dist/docs/how-to/register-an-action-handler.md +67 -0
- package/dist/docs/how-to/render-a-step-form.md +132 -0
- package/dist/docs/how-to/render-an-unpublished-preview.md +41 -0
- package/dist/docs/how-to/reuse-a-section.md +37 -0
- package/dist/docs/how-to/reuse-a-step-field-or-action.md +28 -0
- package/dist/docs/how-to/roll-back-a-published-version.md +26 -0
- package/dist/docs/how-to/run-an-ab-test.md +49 -0
- package/dist/docs/how-to/run-code-on-a-form-submission.md +125 -0
- package/dist/docs/how-to/server-render-a-page.md +81 -0
- package/dist/docs/how-to/set-a-content-security-policy.md +32 -0
- package/dist/docs/how-to/set-up-mfa.md +69 -0
- package/dist/docs/how-to/upload-and-use-an-asset.mdx +73 -0
- package/dist/docs/how-to/validate-a-field.md +52 -0
- package/dist/docs/how-to/write-a-condition.md +45 -0
- package/dist/docs/how-to/write-a-predicate.md +60 -0
- package/dist/docs/index.md +41 -70
- package/dist/docs/reference/dashboard/actions.mdx +53 -0
- package/dist/docs/{api-keys.mdx → reference/dashboard/api-keys.mdx} +7 -15
- package/dist/docs/reference/dashboard/conditions.mdx +42 -0
- package/dist/docs/reference/dashboard/content/asset-library.mdx +63 -0
- package/dist/docs/{content → reference/dashboard/content}/content-entries.mdx +11 -3
- package/dist/docs/{content → reference/dashboard/content}/layouts.mdx +11 -35
- package/dist/docs/reference/dashboard/content/pages.mdx +35 -0
- package/dist/docs/reference/dashboard/content/sections.mdx +28 -0
- package/dist/docs/{experiences.mdx → reference/dashboard/experiences.mdx} +9 -16
- package/dist/docs/{features.mdx → reference/dashboard/features.mdx} +26 -41
- package/dist/docs/{fields.mdx → reference/dashboard/fields.mdx} +26 -20
- package/dist/docs/{flow-builder/overview.mdx → reference/dashboard/flow-builder/canvas.mdx} +8 -13
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/condition-builder.md +5 -13
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/keyboard-shortcuts.md +7 -1
- package/dist/docs/{flow-builder → reference/dashboard/flow-builder}/nodes.md +10 -3
- package/dist/docs/reference/dashboard/projects.mdx +44 -0
- package/dist/docs/reference/dashboard/reports.mdx +43 -0
- package/dist/docs/reference/dashboard/steps.mdx +37 -0
- package/dist/docs/{team-management.md → reference/dashboard/team-management.md} +5 -22
- package/dist/docs/{workspace-versioning.mdx → reference/dashboard/workspace-versioning.mdx} +6 -10
- package/dist/docs/reference/dashboard/workspaces.mdx +76 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/experience-content.md +11 -4
- package/dist/docs/reference/delivery-api/index.md +45 -0
- package/dist/docs/{delivery-api → reference/delivery-api}/preview-caching-crawling.md +12 -5
- package/dist/docs/{delivery-api → reference/delivery-api}/project-config.md +11 -4
- package/dist/docs/reference/glossary.md +173 -0
- package/dist/docs/reference/management-api/authentication.md +74 -0
- package/dist/docs/{api → reference/management-api}/authorization-and-scopes.md +10 -3
- package/dist/docs/{api → reference/management-api}/error-handling.md +9 -3
- package/dist/docs/{api → reference/management-api}/pagination.md +6 -0
- package/dist/docs/{pickedql → reference/pickedql}/data-sources.md +16 -9
- package/dist/docs/{pickedql → reference/pickedql}/dimensions.md +7 -0
- package/dist/docs/{pickedql → reference/pickedql}/filtering.md +7 -0
- package/dist/docs/reference/pickedql/index.md +18 -0
- package/dist/docs/{pickedql → reference/pickedql}/schema.md +13 -6
- package/dist/docs/{pickedql → reference/pickedql}/virtual-functions.md +7 -0
- package/dist/docs/reference/sdk/actions.md +30 -0
- package/dist/docs/{sdk → reference/sdk}/conditions.md +8 -1
- package/dist/docs/reference/sdk/content-security-policy.md +21 -0
- package/dist/docs/reference/sdk/experiences.md +51 -0
- package/dist/docs/{sdk → reference/sdk}/features.md +30 -117
- package/dist/docs/{sdk → reference/sdk}/fields.md +10 -88
- package/dist/docs/reference/sdk/index.md +68 -0
- package/dist/docs/{sdk → reference/sdk}/plugins/create-experience.md +10 -22
- package/dist/docs/reference/sdk/plugins/dynamic-experiences.md +26 -0
- package/dist/docs/reference/sdk/plugins/index.md +29 -0
- package/dist/docs/{sdk → reference/sdk}/plugins/window-object.md +6 -0
- package/dist/docs/reference/sdk/predicates.md +43 -0
- package/dist/docs/reference/sdk/ssr/index.md +33 -0
- package/dist/docs/{sdk → reference/sdk}/ssr/rendering-and-hydration.md +4 -63
- package/dist/docs/{sdk → reference/sdk}/ssr/serialize.md +6 -33
- package/dist/docs/{sdk → reference/sdk}/ssr/slots-and-placements.md +7 -1
- package/dist/docs/reference/sdk/steps.md +87 -0
- package/dist/docs/reference/tools/chrome-extension.md +16 -0
- package/dist/docs/{image-optimisation-service.md → reference/tools/image-optimisation-service.md} +8 -0
- package/dist/docs/{mcp.md → reference/tools/mcp.md} +5 -45
- package/dist/docs/{vite-plugin.md → reference/tools/vite-plugin.md} +8 -38
- package/dist/docs/{api/index.md → tutorials/first-api-call.md} +27 -15
- package/dist/docs/tutorials/first-experience-in-the-dashboard.mdx +143 -0
- package/dist/docs/tutorials/first-experience.mdx +255 -0
- package/dist/docs/tutorials/first-server-rendered-page.mdx +186 -0
- package/dist/{dom-BwmTHeT7.js → dom-BqcToNL0.js} +1 -3
- package/dist/{dom-CDrHc_j9.cjs → dom-DlLH3FxV.cjs} +1 -1
- package/dist/esm/form/index.js +2 -4
- package/dist/esm/index.js +306 -298
- package/dist/esm/plugins/dom-observer/index.js +1 -1
- package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
- package/dist/esm/preview/index.js +1 -1
- package/dist/esm/server/index.js +12 -10
- package/dist/{experience-instance-DOJShRk5.js → experience-instance-DGk11d8a.js} +3 -3
- package/dist/experience-instance-Dej3P1sE.cjs +1 -0
- package/dist/plugin-CNna0UjB.cjs +1 -0
- package/dist/{plugin-ChPkTj__.js → plugin-DUOJpHaq.js} +2 -2
- package/dist/{preview-channel-DW9J8t4B.js → preview-channel-CSr96XAo.js} +1 -1
- package/dist/{protocol-DSqOlW2r.js → protocol-C5KkkiZc.js} +1 -1
- package/dist/types/client.d.ts +7 -6
- package/dist/types/entities/action/action.d.ts +5 -4
- package/dist/types/entities/action/action.d.ts.map +1 -1
- package/dist/types/entities/component/component.d.ts +6 -5
- package/dist/types/entities/component/component.d.ts.map +1 -1
- package/dist/types/entities/condition/condition.d.ts +5 -5
- package/dist/types/entities/content/content.d.ts +4 -3
- package/dist/types/entities/experience/experience.d.ts +11 -10
- package/dist/types/entities/experience/experience.d.ts.map +1 -1
- package/dist/types/entities/experience-instance/experience-instance.d.ts +10 -9
- package/dist/types/entities/feature/feature.d.ts +19 -2
- package/dist/types/entities/feature/feature.d.ts.map +1 -1
- package/dist/types/entities/field/field.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts +7 -6
- package/dist/types/entities/framework/framework.d.ts.map +1 -1
- package/dist/types/entities/history/history.d.ts +6 -6
- package/dist/types/entities/plugin/plugin.d.ts +3 -2
- package/dist/types/entities/plugin/plugin.d.ts.map +1 -1
- package/dist/types/entities/predicate/predicate.d.ts +4 -3
- package/dist/types/entities/predicate/predicate.d.ts.map +1 -1
- package/dist/types/entities/response/response-validation.d.ts +3 -2
- package/dist/types/entities/response/response.d.ts +12 -11
- package/dist/types/entities/session/session.d.ts +2 -1
- package/dist/types/entities/step/step.d.ts +6 -5
- package/dist/types/exports.d.ts +2 -1
- package/dist/types/exports.d.ts.map +1 -1
- package/dist/types/form/build-responses.d.ts +2 -1
- package/dist/types/form/create-field-evaluator.d.ts +4 -3
- package/dist/types/form/create-field-validation.d.ts +5 -4
- package/dist/types/form/create-form.d.ts +7 -6
- package/dist/types/form/create-submit-pipeline.d.ts +7 -6
- package/dist/types/form/get-step-fields.d.ts +3 -2
- package/dist/types/lifecycle/condition-selection.d.ts +14 -4
- package/dist/types/lifecycle/lifecycle.d.ts +4 -3
- package/dist/types/lifecycle/rules-logic.d.ts +4 -3
- package/dist/types/lifecycle/state-snapshot.d.ts +4 -3
- package/dist/types/picked.d.ts +64 -62
- package/dist/types/picked.d.ts.map +1 -1
- package/dist/types/ping.d.ts +1 -1
- package/dist/types/ping.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/create-experience.d.ts +9 -8
- package/dist/types/plugins/create-experience/create-experience.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/plugin.d.ts +3 -2
- package/dist/types/plugins/create-experience/plugin.d.ts.map +1 -1
- package/dist/types/plugins/create-experience/serialization.d.ts.map +1 -1
- package/dist/types/plugins/dom-observer/plugin.d.ts +1 -1
- package/dist/types/plugins/dynamic-experiences/plugin.d.ts +3 -3
- package/dist/types/plugins/dynamic-experiences/types.d.ts +8 -5
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/experience-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/history-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts +1 -1
- package/dist/types/plugins/responses-browser-storage/plugin.d.ts.map +1 -1
- package/dist/types/plugins/responses-indexeddb/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts +1 -1
- package/dist/types/plugins/single-page-app/plugin.d.ts.map +1 -1
- package/dist/types/plugins/web-components/plugin.d.ts +2 -1
- package/dist/types/plugins/window-object/plugin.d.ts +2 -2
- package/dist/types/preview-channel.d.ts +5 -1
- package/dist/types/preview-receiver/index.d.ts +18 -1
- package/dist/types/preview-receiver/protocol.d.ts +10 -1
- package/dist/types/server/index.d.ts +3 -3
- package/dist/types/server/serialize.d.ts +2 -2
- package/dist/types/utils/dom.d.ts +2 -1
- package/dist/types/utils/events.d.ts +6 -6
- package/dist/types/utils/events.d.ts.map +1 -1
- package/dist/types/utils/global-obj.d.ts +1 -1
- package/dist/types/utils/global-obj.d.ts.map +1 -1
- package/dist/types/utils/id.d.ts.map +1 -1
- package/dist/types/utils/logger.d.ts +2 -1
- package/dist/types/utils/logger.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-next-node-from-action.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node-from-condition.d.ts +2 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-next-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts +1 -1
- package/dist/types/utils/node-tree/get-origin-node.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-leaf.d.ts.map +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts +1 -1
- package/dist/types/utils/node-tree/min-max-steps-to-origin.d.ts.map +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts +1 -1
- package/dist/types/utils/node-tree/next-reachable-step-nodes.d.ts.map +1 -1
- package/dist/types/utils/nodes.d.ts +1 -1
- package/dist/types/utils/picked-config.d.ts +2 -1
- package/dist/types/utils/rules-logic.d.ts +6 -2
- package/dist/types/utils/storage.d.ts +1 -1
- package/dist/types/utils/storage.d.ts.map +1 -1
- package/package.json +22 -23
- package/dist/api-CPy9G49C.js +0 -40
- package/dist/api-Ce6xYI--.cjs +0 -1
- package/dist/docs/actions.mdx +0 -98
- package/dist/docs/api/authentication.md +0 -403
- package/dist/docs/chrome-extension.md +0 -68
- package/dist/docs/conditions.mdx +0 -72
- package/dist/docs/content/asset-library.mdx +0 -124
- package/dist/docs/content/pages.mdx +0 -82
- package/dist/docs/content/sections.mdx +0 -44
- package/dist/docs/delivery-api/index.md +0 -53
- package/dist/docs/guides/build-a-personalized-page.mdx +0 -161
- package/dist/docs/pickedql/index.md +0 -54
- package/dist/docs/projects.mdx +0 -44
- package/dist/docs/reports.mdx +0 -20
- package/dist/docs/sdk/actions.md +0 -82
- package/dist/docs/sdk/content-security-policy.md +0 -33
- package/dist/docs/sdk/experiences.md +0 -64
- package/dist/docs/sdk/feature-allocation.md +0 -161
- package/dist/docs/sdk/index.md +0 -98
- package/dist/docs/sdk/plugins/dynamic-experiences.md +0 -84
- package/dist/docs/sdk/plugins/index.md +0 -9
- package/dist/docs/sdk/predicates.md +0 -128
- package/dist/docs/sdk/ssr/index.md +0 -79
- package/dist/docs/sdk/steps.md +0 -479
- package/dist/docs/steps.mdx +0 -53
- package/dist/docs/workspaces.mdx +0 -133
- package/dist/experience-instance-DurC3pE-.cjs +0 -1
- package/dist/plugin-DHn11gn6.cjs +0 -1
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to define a page layout
|
|
7
|
+
|
|
8
|
+
This guide shows you how to define the shape of a page. A layout sets which fields a page
|
|
9
|
+
can hold, and it holds no data itself.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Open your workspace.
|
|
14
|
+
2. Click **Pages** in the sidebar, then **Page Layouts**.
|
|
15
|
+
3. Click **New model**.
|
|
16
|
+
4. Set **Category** to **Page layout**.
|
|
17
|
+
5. Enter a **Name** and a **Key**. The key is stable, and your SDK code and your API
|
|
18
|
+
calls both use it.
|
|
19
|
+
6. Add your fields. Choose a type for each one.
|
|
20
|
+
7. Click **Create model**.
|
|
21
|
+
|
|
22
|
+
The category is fixed when you create the layout. You cannot change it later.
|
|
23
|
+
|
|
24
|
+
## Make a field repeatable
|
|
25
|
+
|
|
26
|
+
Turn on **repeatable** on any field. It then renders as a sortable list of values. Use it
|
|
27
|
+
for a gallery, or for a list of features.
|
|
28
|
+
|
|
29
|
+
## Group related fields
|
|
30
|
+
|
|
31
|
+
Add a **Group** field to hold a set of fields under one key. Make the group repeatable to
|
|
32
|
+
describe a list of objects, such as a list of feature cards.
|
|
33
|
+
|
|
34
|
+
## Related
|
|
35
|
+
|
|
36
|
+
- [About the content model](/explanation/the-content-model) — why the schema and the data
|
|
37
|
+
are separate.
|
|
38
|
+
- [Page and step layouts](/reference/dashboard/content/layouts) — every field type.
|
|
39
|
+
- [How to reuse a section](/how-to/reuse-a-section).
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to fill and publish a page
|
|
7
|
+
|
|
8
|
+
This guide shows you how to make a server-rendered Page and put content in it. You need a
|
|
9
|
+
page layout first. See [How to define a page layout](/how-to/define-a-page-layout).
|
|
10
|
+
|
|
11
|
+
## 1. Create the page
|
|
12
|
+
|
|
13
|
+
1. Open your project.
|
|
14
|
+
2. Choose a workspace.
|
|
15
|
+
3. Click **Pages** in the sidebar.
|
|
16
|
+
4. Click **New experience**.
|
|
17
|
+
5. Choose the **Page** type.
|
|
18
|
+
6. Choose a page layout.
|
|
19
|
+
7. Click **Create page**.
|
|
20
|
+
|
|
21
|
+
Picked makes a content entry and links it to the page on the first save.
|
|
22
|
+
|
|
23
|
+
## 2. Fill in the content
|
|
24
|
+
|
|
25
|
+
1. Open the **Properties** tab.
|
|
26
|
+
2. Fill in each field. The inspector on the right edits the field that you choose.
|
|
27
|
+
3. Watch the preview panel as the page fills in.
|
|
28
|
+
|
|
29
|
+
## 3. Correct every error
|
|
30
|
+
|
|
31
|
+
An invalid field shows an error next to it while you edit. Correct each one before you
|
|
32
|
+
publish. Picked serves valid content only.
|
|
33
|
+
|
|
34
|
+
## 4. Publish
|
|
35
|
+
|
|
36
|
+
Publish the workspace to make the page live. See
|
|
37
|
+
[How to publish a workspace](/how-to/publish-a-workspace).
|
|
38
|
+
|
|
39
|
+
## Change the layout later
|
|
40
|
+
|
|
41
|
+
Use the change-layout control on the **Settings** tab. When you unlink a layout, Picked
|
|
42
|
+
separates the content entry from the page. It deletes no entry, but the page then has no
|
|
43
|
+
content to render.
|
|
44
|
+
|
|
45
|
+
## Related
|
|
46
|
+
|
|
47
|
+
- [About pages and flows](/explanation/pages-and-flows) — when to choose a Page.
|
|
48
|
+
- [Your first server-rendered page](/tutorials/first-server-rendered-page) — the whole
|
|
49
|
+
path, with the SDK.
|
|
50
|
+
- [Pages](/reference/dashboard/content/pages) — the editor reference.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
---
|
|
2
|
+
type: how-to
|
|
2
3
|
layout: docs
|
|
3
4
|
---
|
|
4
5
|
|
|
5
|
-
#
|
|
6
|
+
# How to install the GTM template
|
|
6
7
|
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
This guide shows you how to track an ecommerce event in Google Tag Manager and send it to
|
|
9
|
+
Picked. You need a GTM container and your Picked Tag ID.
|
|
9
10
|
|
|
10
11
|
## Automatic installation
|
|
11
12
|
|
|
@@ -76,3 +77,8 @@ the trigger that matches. Then set the options below.
|
|
|
76
77
|
| **Additional data** | An optional GTM variable, for more metadata with the event. |
|
|
77
78
|
|
|
78
79
|

|
|
80
|
+
|
|
81
|
+
## Related
|
|
82
|
+
|
|
83
|
+
- [About how Picked works](/explanation/how-picked-works) — what Picked does with the
|
|
84
|
+
event.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to install the SDK
|
|
7
|
+
|
|
8
|
+
This guide shows you how to add the Picked client to a web application. You need a project
|
|
9
|
+
ID from the dashboard.
|
|
10
|
+
|
|
11
|
+
## 1. Install the packages
|
|
12
|
+
|
|
13
|
+
:::code-group
|
|
14
|
+
|
|
15
|
+
```bash [React]
|
|
16
|
+
npm install @picked/client @picked/react effector effector-react
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```bash [Svelte]
|
|
20
|
+
npm install @picked/client @picked/svelte effector
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
:::
|
|
24
|
+
|
|
25
|
+
## 2. Create and start the client
|
|
26
|
+
|
|
27
|
+
:::code-group
|
|
28
|
+
|
|
29
|
+
```tsx [React]
|
|
30
|
+
import { createClient } from '@picked/client'
|
|
31
|
+
import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
|
|
32
|
+
import { reactFrameworkPlugin } from '@picked/react/plugins/framework'
|
|
33
|
+
|
|
34
|
+
export const picked = createClient({
|
|
35
|
+
projectId: 'your-project-id',
|
|
36
|
+
plugins: [reactFrameworkPlugin({ components: {} }), dynamicExperiencesPlugin()],
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
picked.start()
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
```ts [Svelte]
|
|
43
|
+
import { createClient } from '@picked/client'
|
|
44
|
+
import { dynamicExperiencesPlugin } from '@picked/client/plugins/dynamic-experiences'
|
|
45
|
+
import { svelteFrameworkPlugin } from '@picked/svelte/plugins/framework'
|
|
46
|
+
|
|
47
|
+
export const picked = createClient({
|
|
48
|
+
projectId: 'your-project-id',
|
|
49
|
+
plugins: [svelteFrameworkPlugin({ components: {} }), dynamicExperiencesPlugin()],
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
picked.start()
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
:::
|
|
56
|
+
|
|
57
|
+
`start()` is idempotent. A second call changes nothing on a client that started already.
|
|
58
|
+
|
|
59
|
+
## 3. Add the optional plugins
|
|
60
|
+
|
|
61
|
+
- `windowObjectPlugin()` puts the client on `window.Picked`, which helps when you debug.
|
|
62
|
+
- `singlePageAppPlugin()` starts the client again on a history event.
|
|
63
|
+
|
|
64
|
+
## Related
|
|
65
|
+
|
|
66
|
+
- [Add Picked to your application](/tutorials/first-experience) — the whole path.
|
|
67
|
+
- [SDK installation](/reference/sdk) — every client option.
|
|
68
|
+
- [How to register a component](/how-to/register-a-component).
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to install the Vite plugin
|
|
7
|
+
|
|
8
|
+
This guide shows you how to embed your project configuration at build time, so the SDK makes no
|
|
9
|
+
API request at runtime.
|
|
10
|
+
|
|
11
|
+
## 1. Install
|
|
12
|
+
|
|
13
|
+
:::code-group
|
|
14
|
+
|
|
15
|
+
```bash [npm]
|
|
16
|
+
npm install @picked/vite-plugin-picked
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```bash [pnpm]
|
|
20
|
+
pnpm add @picked/vite-plugin-picked
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
```bash [yarn]
|
|
24
|
+
yarn add @picked/vite-plugin-picked
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
:::
|
|
28
|
+
|
|
29
|
+
## 2. Add it to your config
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { defineConfig } from 'vite'
|
|
33
|
+
import { picked } from '@picked/vite-plugin-picked'
|
|
34
|
+
|
|
35
|
+
export default defineConfig({
|
|
36
|
+
plugins: [
|
|
37
|
+
picked({
|
|
38
|
+
projectId: 'your-project-id',
|
|
39
|
+
}),
|
|
40
|
+
],
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
When Vite starts, the plugin reads your project configuration and embeds them in your bundle.
|
|
45
|
+
The SDK then reads the embedded configuration and makes no network request.
|
|
46
|
+
|
|
47
|
+
:::note
|
|
48
|
+
When a preview token is there at runtime, the SDK ignores the embedded configuration and reads
|
|
49
|
+
fresh data from the API.
|
|
50
|
+
:::
|
|
51
|
+
|
|
52
|
+
## Related
|
|
53
|
+
|
|
54
|
+
- [Vite plugin](/reference/tools/vite-plugin) — every option.
|
|
55
|
+
- [About how Picked works](/explanation/how-picked-works) — where build-time configuration sit
|
|
56
|
+
in the startup order.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to invite and remove members
|
|
7
|
+
|
|
8
|
+
This guide shows you how to control who reaches your organization.
|
|
9
|
+
|
|
10
|
+
## Invite a member
|
|
11
|
+
|
|
12
|
+
1. Open your organization.
|
|
13
|
+
2. Click **Members**.
|
|
14
|
+
3. Click **Invite member**.
|
|
15
|
+
4. Enter an email address.
|
|
16
|
+
5. Choose a role. Give the smallest role that the work needs.
|
|
17
|
+
6. Click **Send invitation**.
|
|
18
|
+
|
|
19
|
+
The person receives an email with a link to join. A person with no Picked account must
|
|
20
|
+
create one first.
|
|
21
|
+
|
|
22
|
+
## Remove a member
|
|
23
|
+
|
|
24
|
+
1. Open your organization.
|
|
25
|
+
2. Click **Members**.
|
|
26
|
+
3. Find the member.
|
|
27
|
+
4. Click **Remove** next to the name.
|
|
28
|
+
5. Confirm.
|
|
29
|
+
|
|
30
|
+
The member loses access to every project in the organization immediately.
|
|
31
|
+
|
|
32
|
+
## Related
|
|
33
|
+
|
|
34
|
+
- [Team management](/reference/dashboard/team-management) — the roles.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to see a preview of a workspace
|
|
7
|
+
|
|
8
|
+
This guide shows you how to see an unpublished change on your own site before your
|
|
9
|
+
visitors get it. You need a draft workspace with at least one change in it.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Click **Preview** in the workspace toolbar.
|
|
14
|
+
2. Enter the URL of your site.
|
|
15
|
+
3. Set each feature flag to the **Default** value, to **On**, or to **Off**. This step
|
|
16
|
+
is optional.
|
|
17
|
+
4. Click **Open preview**.
|
|
18
|
+
|
|
19
|
+
Your site opens in a new tab with the unpublished workspace applied.
|
|
20
|
+
|
|
21
|
+
The preview sends the workspace state to the SDK in the query parameters. The visitors on
|
|
22
|
+
your live site therefore see no change.
|
|
23
|
+
|
|
24
|
+
## Related
|
|
25
|
+
|
|
26
|
+
- [About workspaces and versions](/explanation/workspaces-and-versions) — why a preview
|
|
27
|
+
cannot reach production.
|
|
28
|
+
- [Workspaces](/reference/dashboard/workspaces) — the workspace states.
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to publish a workspace
|
|
7
|
+
|
|
8
|
+
This guide shows you how to make the changes in a workspace live. You need a draft
|
|
9
|
+
workspace with at least one unpublished change.
|
|
10
|
+
|
|
11
|
+
The **Publish** button is active only when the workspace holds an unpublished change. A
|
|
12
|
+
badge in the toolbar shows the current state.
|
|
13
|
+
|
|
14
|
+
## Steps
|
|
15
|
+
|
|
16
|
+
1. Click **Publish** in the workspace toolbar.
|
|
17
|
+
2. Read the change preview in the publish modal.
|
|
18
|
+
3. Expand any modified row to see which properties changed.
|
|
19
|
+
4. Read the banner above the diff, if one is there. It reports a change that breaks
|
|
20
|
+
another record.
|
|
21
|
+
5. Click **Publish** to confirm.
|
|
22
|
+
|
|
23
|
+
Picked makes an immutable snapshot of your workspace, and the SDK serves it to your
|
|
24
|
+
visitors.
|
|
25
|
+
|
|
26
|
+
## Related
|
|
27
|
+
|
|
28
|
+
- [About workspaces and versions](/explanation/workspaces-and-versions) — why the modal
|
|
29
|
+
shows a diff.
|
|
30
|
+
- [How to roll back a published version](/how-to/roll-back-a-published-version).
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to read a feature flag
|
|
7
|
+
|
|
8
|
+
This guide shows you how to read the resolved bucket of a feature flag in your
|
|
9
|
+
application. You need a feature flag in your project first, either from the dashboard or
|
|
10
|
+
[defined in SDK code](/reference/sdk/features#define-a-feature-flag-in-sdk-code).
|
|
11
|
+
|
|
12
|
+
Which accessor you pick decides *when* the visitor enters the test, so read
|
|
13
|
+
[About feature flag allocation](/explanation/feature-flag-allocation) before you choose.
|
|
14
|
+
|
|
15
|
+
## 1. Choose an accessor
|
|
16
|
+
|
|
17
|
+
Each accessor returns a different value, and they differ in whether a read resolves the
|
|
18
|
+
feature flag. A read that resolves the feature flag commits the visitor to a bucket and reports the
|
|
19
|
+
decision.
|
|
20
|
+
|
|
21
|
+
| API | Returns | Does a read resolve the feature flag? |
|
|
22
|
+
| --- | --- | --- |
|
|
23
|
+
| `useFeature` / `getFeature` | `() => Promise<bucket>` | Only when you call the function that it returns |
|
|
24
|
+
| `useFeatureResult` / `getFeatureResult` | `{ id, bucket }`, and `undefined` until it resolves | Yes, as soon as the component renders |
|
|
25
|
+
| `useFeatureEnabled` / `getFeatureEnabled` | `boolean \| undefined`, the dashboard **Enabled** feature flag | No |
|
|
26
|
+
| `client.features.listStore` | Every registered feature flag, each with an `isResolved` feature flag | No |
|
|
27
|
+
| `client.features.getById(id)` | A store that holds one feature flag | No |
|
|
28
|
+
|
|
29
|
+
Some decisions must wait for data that you do not have yet, such as a cart, a quote, or
|
|
30
|
+
the profile of a signed-in user. For those, use `useFeature` or `getFeature`. Call the
|
|
31
|
+
function they return after the data arrives.
|
|
32
|
+
|
|
33
|
+
## 2. Read the bucket
|
|
34
|
+
|
|
35
|
+
:::code-group
|
|
36
|
+
|
|
37
|
+
```tsx [React]
|
|
38
|
+
import { useFeatureResult } from '@picked/react/hooks'
|
|
39
|
+
|
|
40
|
+
function MyComponent() {
|
|
41
|
+
// { id, bucket }, or undefined until the feature flag resolves.
|
|
42
|
+
const result = useFeatureResult('my-feature')
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div>
|
|
46
|
+
{result?.bucket === 'control' && <p>Control</p>}
|
|
47
|
+
{result?.bucket === 'variant-a' && <p>Variant A</p>}
|
|
48
|
+
</div>
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
```svelte [Svelte]
|
|
54
|
+
<script lang="ts">
|
|
55
|
+
import { getFeatureResult } from '@picked/svelte/hooks'
|
|
56
|
+
|
|
57
|
+
// A store that holds { id, bucket }, or undefined until the feature flag resolves.
|
|
58
|
+
const result = getFeatureResult('my-feature')
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
{#if $result?.bucket === 'control'}
|
|
62
|
+
<p>Control</p>
|
|
63
|
+
{:else if $result?.bucket === 'variant-a'}
|
|
64
|
+
<p>Variant A</p>
|
|
65
|
+
{/if}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
:::
|
|
69
|
+
|
|
70
|
+
:::warning
|
|
71
|
+
`useFeatureResult` and `getFeatureResult` resolve the feature flag as soon as the component
|
|
72
|
+
renders, and they commit the visitor to a bucket at that moment.
|
|
73
|
+
:::
|
|
74
|
+
|
|
75
|
+
## 3. Read it without a framework
|
|
76
|
+
|
|
77
|
+
The event bus works with any framework, and with none:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import { createClient } from '@picked/client'
|
|
81
|
+
|
|
82
|
+
const client = createClient({
|
|
83
|
+
/* Put your client options here. */
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
client.eventBus.watch((event) => {
|
|
87
|
+
if (event.type === 'feature_decide' && event.feature.id === 'my-feature') {
|
|
88
|
+
console.log(event.feature) // { id: 'my-feature', key: 'v1', bucket: 'control' }
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
`feature_decide` fires only when the SDK makes a new decision. A visitor who returns
|
|
94
|
+
restores the decision from storage and fires nothing, so watch
|
|
95
|
+
`client.features.listStore` when you need the current state instead.
|
|
96
|
+
|
|
97
|
+
## Related
|
|
98
|
+
|
|
99
|
+
- [About feature flag allocation](/explanation/feature-flag-allocation) — when the
|
|
100
|
+
visitor enters the test.
|
|
101
|
+
- [SDK feature flags](/reference/sdk/features) — the definition shape and the overrides.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to register a component
|
|
7
|
+
|
|
8
|
+
This guide shows you how to connect a component in your application to an experience in
|
|
9
|
+
the dashboard.
|
|
10
|
+
|
|
11
|
+
## Steps
|
|
12
|
+
|
|
13
|
+
1. Wrap your component with the adapter for your framework.
|
|
14
|
+
2. Pass it in the `components` object of `createClient()`.
|
|
15
|
+
3. Use the same key as the component name of the experience.
|
|
16
|
+
|
|
17
|
+
:::code-group
|
|
18
|
+
|
|
19
|
+
```tsx [React]
|
|
20
|
+
import { createClient } from '@picked/client'
|
|
21
|
+
import { adaptReactComponent } from '@picked/react'
|
|
22
|
+
import { MyWidget } from './MyWidget'
|
|
23
|
+
|
|
24
|
+
const picked = createClient({
|
|
25
|
+
projectId: 'your-project-id',
|
|
26
|
+
components: {
|
|
27
|
+
MyWidget: adaptReactComponent(MyWidget),
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
```ts [Svelte]
|
|
33
|
+
import { createClient } from '@picked/client'
|
|
34
|
+
import { adaptSvelteComponent } from '@picked/svelte'
|
|
35
|
+
import MyWidget from './MyWidget.svelte'
|
|
36
|
+
|
|
37
|
+
const picked = createClient({
|
|
38
|
+
projectId: 'your-project-id',
|
|
39
|
+
components: {
|
|
40
|
+
MyWidget: adaptSvelteComponent(MyWidget),
|
|
41
|
+
},
|
|
42
|
+
})
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
:::
|
|
46
|
+
|
|
47
|
+
:::warning
|
|
48
|
+
`components` takes an adapted component. A plain React or Svelte component does not work
|
|
49
|
+
without `adaptReactComponent` or `adaptSvelteComponent`.
|
|
50
|
+
:::
|
|
51
|
+
|
|
52
|
+
## Related
|
|
53
|
+
|
|
54
|
+
- [SDK experiences](/reference/sdk/experiences) — the experience shape.
|
|
55
|
+
- [How to install the SDK](/how-to/install-the-sdk).
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to register an action handler
|
|
7
|
+
|
|
8
|
+
This guide shows you how to connect an action node in a flow to a function in your
|
|
9
|
+
application. You need an action in your project first, with a key. See
|
|
10
|
+
[Actions](/reference/dashboard/actions).
|
|
11
|
+
|
|
12
|
+
## 1. Register the handler
|
|
13
|
+
|
|
14
|
+
Pass an `actions` object to `createClient()`. Each key must match an action key from the
|
|
15
|
+
dashboard:
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createClient } from '@picked/client'
|
|
19
|
+
|
|
20
|
+
const picked = createClient({
|
|
21
|
+
projectId: 'your-project-id',
|
|
22
|
+
actions: {
|
|
23
|
+
'track-signup': () => {
|
|
24
|
+
analytics.track('signup_completed')
|
|
25
|
+
},
|
|
26
|
+
notify: (params) => {
|
|
27
|
+
sendNotification(params)
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The SDK calls the function that matches when the flow reaches the action node.
|
|
34
|
+
|
|
35
|
+
## 2. Throw only for a true error
|
|
36
|
+
|
|
37
|
+
The flow takes the failure branch when your handler throws or its promise rejects. Throw
|
|
38
|
+
when the request itself did not complete:
|
|
39
|
+
|
|
40
|
+
```ts
|
|
41
|
+
'check-eligibility': async () => {
|
|
42
|
+
const response = await fetch('/api/eligibility')
|
|
43
|
+
// Throw only when the request itself fails. That takes the failure branch.
|
|
44
|
+
if (!response.ok) throw new Error('Eligibility request failed')
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## 3. Record a negative answer as a response
|
|
49
|
+
|
|
50
|
+
A valid negative result is not a failure. An endpoint can answer `200` with a "no". Store
|
|
51
|
+
that value as a response and branch on it with a condition instead:
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
'check-serviced-area': async ({ client, responses }) => {
|
|
55
|
+
const postcode = responses.find((r) => r.fieldKey === 'postcode')?.value
|
|
56
|
+
const { serviced } = await fetch(`/api/serviced?postcode=${postcode}`).then((r) => r.json())
|
|
57
|
+
// Store the outcome as a response. A later condition then takes the branch.
|
|
58
|
+
client.responses.register('is-serviced', serviced)
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Related
|
|
63
|
+
|
|
64
|
+
- [About how Picked works](/explanation/how-picked-works#how-an-action-decides-which-way-to-go)
|
|
65
|
+
— why a returned `false` is a success.
|
|
66
|
+
- [SDK actions](/reference/sdk/actions) — what the handler receives and returns.
|
|
67
|
+
- [Actions](/reference/dashboard/actions) — the dashboard options.
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: how-to
|
|
3
|
+
layout: docs
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# How to render a step form
|
|
7
|
+
|
|
8
|
+
This guide shows you how to render the fields of the active step and let a visitor submit
|
|
9
|
+
them.
|
|
10
|
+
|
|
11
|
+
## 1. Put the steps in a router
|
|
12
|
+
|
|
13
|
+
`StepRouter` watches the step state and activates the `Step` whose `id` matches.
|
|
14
|
+
|
|
15
|
+
:::code-group
|
|
16
|
+
|
|
17
|
+
```tsx [React]
|
|
18
|
+
import { StepRouter, Step } from '@picked/react/router'
|
|
19
|
+
|
|
20
|
+
function MyExperience() {
|
|
21
|
+
return (
|
|
22
|
+
<StepRouter>
|
|
23
|
+
<Step id="welcome">
|
|
24
|
+
<WelcomeScreen />
|
|
25
|
+
</Step>
|
|
26
|
+
<Step id="contact">
|
|
27
|
+
<ContactForm />
|
|
28
|
+
</Step>
|
|
29
|
+
</StepRouter>
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
```svelte [Svelte]
|
|
35
|
+
<script lang="ts">
|
|
36
|
+
import { StepRouter, Step } from '@picked/svelte/router'
|
|
37
|
+
</script>
|
|
38
|
+
|
|
39
|
+
<StepRouter>
|
|
40
|
+
<Step id="welcome">
|
|
41
|
+
<WelcomeScreen />
|
|
42
|
+
</Step>
|
|
43
|
+
<Step id="contact">
|
|
44
|
+
<ContactForm />
|
|
45
|
+
</Step>
|
|
46
|
+
</StepRouter>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
:::
|
|
50
|
+
|
|
51
|
+
:::note
|
|
52
|
+
A router must hold every Step, even when there is only one Step.
|
|
53
|
+
:::
|
|
54
|
+
|
|
55
|
+
## 2. Render the fields
|
|
56
|
+
|
|
57
|
+
Bind `form.props` to your `<form>` element and map over the fields.
|
|
58
|
+
|
|
59
|
+
:::code-group
|
|
60
|
+
|
|
61
|
+
```tsx [React]
|
|
62
|
+
import { useStep } from '@picked/react/hooks'
|
|
63
|
+
import { useUnit } from 'effector-react'
|
|
64
|
+
|
|
65
|
+
function StepForm() {
|
|
66
|
+
const { fields, form } = useStep()
|
|
67
|
+
const currentFields = useUnit(fields)
|
|
68
|
+
const isSubmitting = useUnit(form.submitting)
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<form {...form.props}>
|
|
72
|
+
{currentFields.map((field) => (
|
|
73
|
+
<div key={field.id}>
|
|
74
|
+
<label htmlFor={field.id}>{field.label}</label>
|
|
75
|
+
<input
|
|
76
|
+
id={field.id}
|
|
77
|
+
name={field.id}
|
|
78
|
+
value={field.value ?? ''}
|
|
79
|
+
onChange={field.onChange}
|
|
80
|
+
onBlur={field.onBlur}
|
|
81
|
+
/>
|
|
82
|
+
{field.error && field.touched && <p className="error">{field.error.userMessage}</p>}
|
|
83
|
+
</div>
|
|
84
|
+
))}
|
|
85
|
+
<button type="submit" disabled={isSubmitting}>Continue</button>
|
|
86
|
+
</form>
|
|
87
|
+
)
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
```svelte [Svelte]
|
|
92
|
+
<script lang="ts">
|
|
93
|
+
import { getStep } from '@picked/svelte/hooks'
|
|
94
|
+
|
|
95
|
+
const { fields, form } = getStep()
|
|
96
|
+
const isSubmitting = form.submitting
|
|
97
|
+
</script>
|
|
98
|
+
|
|
99
|
+
<form {...form.props}>
|
|
100
|
+
{#each $fields as field}
|
|
101
|
+
<div>
|
|
102
|
+
<label for={field.id}>{field.label}</label>
|
|
103
|
+
<input
|
|
104
|
+
id={field.id}
|
|
105
|
+
name={field.id}
|
|
106
|
+
value={field.value ?? ''}
|
|
107
|
+
onchange={field.onChange}
|
|
108
|
+
onblur={field.onBlur}
|
|
109
|
+
/>
|
|
110
|
+
{#if field.error && field.touched}
|
|
111
|
+
<p class="error">{field.error.userMessage}</p>
|
|
112
|
+
{/if}
|
|
113
|
+
</div>
|
|
114
|
+
{/each}
|
|
115
|
+
<button type="submit" disabled={$isSubmitting}>Continue</button>
|
|
116
|
+
</form>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
:::
|
|
120
|
+
|
|
121
|
+
The SDK checks a field on blur, and not while the visitor types.
|
|
122
|
+
|
|
123
|
+
## 3. Load a large step lazily
|
|
124
|
+
|
|
125
|
+
Pass a dynamic import to the `component` prop of `<Step>`. The SDK does not load the
|
|
126
|
+
content until that step becomes active.
|
|
127
|
+
|
|
128
|
+
## Related
|
|
129
|
+
|
|
130
|
+
- [How to run code on a form submission](/how-to/run-code-on-a-form-submission) — the
|
|
131
|
+
callbacks.
|
|
132
|
+
- [SDK steps](/reference/sdk/steps) — the `StepContext` shape.
|