@picked/client 0.0.70-next.5 → 0.0.70

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 (78) hide show
  1. package/dist/{api-DQ1DqG_F.js → api-CPy9G49C.js} +1 -1
  2. package/dist/api-Ce6xYI--.cjs +1 -0
  3. package/dist/cjs/index.js +2 -2
  4. package/dist/cjs/plugins/dynamic-experiences/index.js +1 -1
  5. package/dist/cjs/server/index.js +1 -1
  6. package/dist/docs/actions.mdx +38 -18
  7. package/dist/docs/api/authentication.md +75 -48
  8. package/dist/docs/api/authorization-and-scopes.md +63 -47
  9. package/dist/docs/api/error-handling.md +70 -54
  10. package/dist/docs/api/index.md +41 -22
  11. package/dist/docs/api/pagination.md +30 -20
  12. package/dist/docs/api-keys.mdx +11 -6
  13. package/dist/docs/chrome-extension.md +22 -5
  14. package/dist/docs/conditions.mdx +32 -19
  15. package/dist/docs/content/asset-library.mdx +65 -34
  16. package/dist/docs/content/content-entries.mdx +8 -2
  17. package/dist/docs/content/layouts.mdx +45 -29
  18. package/dist/docs/content/pages.mdx +29 -14
  19. package/dist/docs/content/sections.mdx +19 -8
  20. package/dist/docs/delivery-api/experience-content.md +10 -5
  21. package/dist/docs/delivery-api/index.md +19 -12
  22. package/dist/docs/delivery-api/preview-caching-crawling.md +27 -14
  23. package/dist/docs/delivery-api/project-config.md +6 -4
  24. package/dist/docs/experiences.mdx +26 -10
  25. package/dist/docs/features.mdx +75 -20
  26. package/dist/docs/fields.mdx +42 -27
  27. package/dist/docs/flow-builder/building-flows.md +38 -20
  28. package/dist/docs/flow-builder/condition-builder.md +32 -21
  29. package/dist/docs/flow-builder/keyboard-shortcuts.md +18 -18
  30. package/dist/docs/flow-builder/nodes.md +26 -13
  31. package/dist/docs/flow-builder/overview.mdx +28 -15
  32. package/dist/docs/gtm-template.md +35 -26
  33. package/dist/docs/guides/build-a-personalized-page.mdx +36 -18
  34. package/dist/docs/image-optimisation-service.md +33 -17
  35. package/dist/docs/index.md +28 -17
  36. package/dist/docs/mcp.md +46 -38
  37. package/dist/docs/pickedql/data-sources.md +65 -43
  38. package/dist/docs/pickedql/dimensions.md +27 -12
  39. package/dist/docs/pickedql/examples.md +38 -26
  40. package/dist/docs/pickedql/filtering.md +10 -6
  41. package/dist/docs/pickedql/index.md +32 -14
  42. package/dist/docs/pickedql/schema.md +85 -76
  43. package/dist/docs/pickedql/virtual-functions.md +62 -36
  44. package/dist/docs/projects.mdx +14 -7
  45. package/dist/docs/reports.mdx +5 -3
  46. package/dist/docs/sdk/actions.md +33 -17
  47. package/dist/docs/sdk/conditions.md +8 -5
  48. package/dist/docs/sdk/content-security-policy.md +5 -4
  49. package/dist/docs/sdk/experiences.md +29 -11
  50. package/dist/docs/sdk/feature-allocation.md +79 -47
  51. package/dist/docs/sdk/features.md +130 -76
  52. package/dist/docs/sdk/fields.md +66 -42
  53. package/dist/docs/sdk/index.md +22 -13
  54. package/dist/docs/sdk/plugins/create-experience.md +18 -15
  55. package/dist/docs/sdk/plugins/dynamic-experiences.md +42 -16
  56. package/dist/docs/sdk/predicates.md +53 -37
  57. package/dist/docs/sdk/ssr/index.md +25 -8
  58. package/dist/docs/sdk/ssr/rendering-and-hydration.md +37 -16
  59. package/dist/docs/sdk/ssr/serialize.md +38 -20
  60. package/dist/docs/sdk/ssr/slots-and-placements.md +28 -10
  61. package/dist/docs/sdk/steps.md +100 -55
  62. package/dist/docs/steps.mdx +20 -11
  63. package/dist/docs/team-management.md +17 -11
  64. package/dist/docs/vite-plugin.md +26 -19
  65. package/dist/docs/workspace-versioning.mdx +14 -8
  66. package/dist/docs/workspaces.mdx +55 -24
  67. package/dist/esm/index.js +257 -238
  68. package/dist/esm/plugins/dynamic-experiences/index.js +2 -2
  69. package/dist/esm/server/index.js +1 -1
  70. package/dist/{plugin-EPx6sE_l.js → plugin-ChPkTj__.js} +58 -53
  71. package/dist/plugin-DHn11gn6.cjs +1 -0
  72. package/dist/types/entities/feature/feature.d.ts.map +1 -1
  73. package/dist/types/plugins/dynamic-experiences/hash.d.ts +40 -5
  74. package/dist/types/plugins/dynamic-experiences/hash.d.ts.map +1 -1
  75. package/dist/types/plugins/dynamic-experiences/plugin.d.ts.map +1 -1
  76. package/package.json +1 -1
  77. package/dist/api-B9koex39.cjs +0 -1
  78. package/dist/plugin-YbSSGrM7.cjs +0 -1
@@ -4,11 +4,13 @@ layout: docs
4
4
 
5
5
  # Pagination
6
6
 
7
- The Picked API uses Relay-style cursor-based pagination for all list fields that may return large result sets. This guide explains the connection pattern and demonstrates how to paginate through results.
7
+ The Picked API paginates every list field that can return a large result. It uses a
8
+ cursor, in the Relay-style pattern. This guide covers the connection pattern and
9
+ shows how to move through a result.
8
10
 
9
11
  ## Connection pattern
10
12
 
11
- Paginated fields return a **connection** object with the following shape:
13
+ A paginated field returns a **connection** object with this shape:
12
14
 
13
15
  ```graphql
14
16
  type ExampleConnection {
@@ -32,20 +34,21 @@ type PageInfo {
32
34
 
33
35
  | Field | Description |
34
36
  |-------|-------------|
35
- | `edges` | An ordered list of edges, each containing a `cursor` and a `node` (the actual data object) |
36
- | `pageInfo.hasNextPage` | `true` if more results exist after the last edge |
37
- | `pageInfo.hasPreviousPage` | `true` if results exist before the first edge |
38
- | `pageInfo.startCursor` | Cursor of the first edge in the current page |
39
- | `pageInfo.endCursor` | Cursor of the last edge in the current page |
40
- | `totalCount` | Total number of items across all pages |
37
+ | `edges` | An ordered list of edges. Each edge holds a `cursor` and a `node`, and the `node` holds the data. |
38
+ | `pageInfo.hasNextPage` | `true` when more results come after the last edge |
39
+ | `pageInfo.hasPreviousPage` | `true` when results come before the first edge |
40
+ | `pageInfo.startCursor` | The cursor of the first edge on the current page |
41
+ | `pageInfo.endCursor` | The cursor of the last edge on the current page |
42
+ | `totalCount` | The number of items on every page together |
41
43
 
42
44
  ## Forward pagination with `first` and `after`
43
45
 
44
- To paginate forward through results, use the `first` argument to specify the page size and the `after` argument to specify the cursor to start after.
46
+ To move forward through the results, use two arguments. The `first` argument gives
47
+ the page size. The `after` argument gives the cursor to start after.
45
48
 
46
49
  ### First page
47
50
 
48
- Omit the `after` argument to fetch the first page:
51
+ Leave the `after` argument out to read the first page:
49
52
 
50
53
  ```graphql
51
54
  query {
@@ -89,16 +92,17 @@ query {
89
92
  }
90
93
  ```
91
94
 
92
- ## Checking for more pages
95
+ ## Check for more pages
93
96
 
94
- Before requesting the next page, check the `hasNextPage` field:
97
+ Read the `hasNextPage` field before you ask for the next page:
95
98
 
96
- - `hasNextPage: true` — more results are available; pass `endCursor` to the next request's `after` argument
97
- - `hasNextPage: false` — all results have been fetched; stop paginating
99
+ - `hasNextPage: true` — more results are available. Pass `endCursor` as the `after`
100
+ argument of the next request.
101
+ - `hasNextPage: false` — you read every result. Stop here.
98
102
 
99
103
  ## Full paginated query example
100
104
 
101
- The following example fetches all members of an organization, page by page:
105
+ This example reads every member of an organization, one page at a time:
102
106
 
103
107
  ```graphql
104
108
  # Page 1
@@ -154,7 +158,8 @@ Continue until `hasNextPage` returns `false`.
154
158
 
155
159
  ## Paginated fields
156
160
 
157
- The following fields in the schema return connection types and support `first`/`after` pagination:
161
+ These fields in the schema return a connection type. They all take the `first` and
162
+ `after` arguments:
158
163
 
159
164
  | Parent Type | Field | Connection Type |
160
165
  |------------|-------|----------------|
@@ -170,7 +175,12 @@ All of these fields accept the same `first` and `after` arguments and return the
170
175
 
171
176
  ## Tips
172
177
 
173
- - **Default page size** — if `first` is omitted, the API applies a default limit. Explicitly setting `first` ensures predictable page sizes.
174
- - **Cursors are opaque** — cursor strings should be treated as opaque tokens. Do not parse, construct, or modify them. Pass them exactly as received from the API.
175
- - **Stable ordering** — results within a connection are returned in a stable order. The same cursor always refers to the same position in the result set.
176
- - **Combine with other fields** — pagination arguments can be used alongside other query fields. For example, fetching an organization and its first page of members in a single request is common and efficient.
178
+ - **The default page size** — the API applies a default limit when you leave `first`
179
+ out. Set `first` yourself to make sure that each page has the size you expect.
180
+ - **A cursor is opaque** — treat a cursor string as an opaque token. Do not parse it,
181
+ build it, or change it. Pass it back exactly as the API gave it.
182
+ - **The order is stable** — a connection returns its results in a stable order. The
183
+ same cursor always points at the same position in the result.
184
+ - **Use them with other fields** — you can use the pagination arguments together with
185
+ other query fields. One request that reads an organization and the first page of
186
+ its members is common, and it is efficient.
@@ -6,7 +6,8 @@ import { Screenshot } from '../../components/Screenshot'
6
6
 
7
7
  # API keys
8
8
 
9
- API keys let you access Picked's API programmatically. Use them for server-side integrations or CI/CD workflows.
9
+ An API key lets your code reach the Picked API. Use one for a server-side integration
10
+ or for a CI/CD workflow.
10
11
 
11
12
  <Screenshot
12
13
  route="/{orgSlug}/api-keys"
@@ -21,11 +22,12 @@ API keys let you access Picked's API programmatically. Use them for server-side
21
22
  4. Enter a description.
22
23
  5. Click **Create**.
23
24
 
24
- Copy the key immediately — it won't be shown again.
25
+ Copy the key immediately. The dashboard does not show it again.
25
26
 
26
- ## Using an API key
27
+ ## Use an API key
27
28
 
28
- Include your API key in the `Authorization` header when making requests to the [Picked API](/api).
29
+ Put your API key in the `Authorization` header of each request to the
30
+ [Picked API](/api).
29
31
 
30
32
  ```
31
33
  Authorization: Bearer your-api-key
@@ -33,8 +35,11 @@ Authorization: Bearer your-api-key
33
35
 
34
36
  ## Scopes
35
37
 
36
- API keys can be scoped to limit what they can access. When creating a key, select the scopes that match your integration's needs. A key can only perform actions allowed by its assigned scopes.
38
+ An API key carries scopes, and the scopes limit what the key can reach. Choose the
39
+ scopes that your integration needs when you create the key. A key can do only the
40
+ operations that its scopes permit.
37
41
 
38
42
  ## Revoke a key
39
43
 
40
- Revoke a key at any time from the API keys list. Click the revoke button next to the key you want to disable. Revoked keys stop working immediately.
44
+ You can revoke a key at any time from the API keys list. Click the revoke button next
45
+ to the key. A revoked key stops work immediately.
@@ -4,17 +4,21 @@ layout: docs
4
4
 
5
5
  # Chrome Extension
6
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.
7
+ The extension for the Picked Developer Tools adds a Picked panel to Chrome DevTools.
8
+ Use the panel to check and debug your Picked integration on any page that runs the
9
+ SDK.
8
10
 
9
11
  ![Picked Developer Tools](/chrome-extension-screenshot.jpg)
10
12
 
11
13
  ## Installation
12
14
 
13
- Install from the [Chrome Web Store](https://chromewebstore.google.com/detail/picked-developer-tools/nimmdamgnhlhdpngnalkpmnleebngidh).
15
+ Install the extension from the
16
+ [Chrome Web Store](https://chromewebstore.google.com/detail/picked-developer-tools/nimmdamgnhlhdpngnalkpmnleebngidh).
14
17
 
15
18
  ## Setup
16
19
 
17
- Add the `svelteDevtoolsPlugin` to your Picked client so the extension can connect to the SDK.
20
+ Add the `svelteDevtoolsPlugin` to your Picked client. The extension then connects to
21
+ the SDK.
18
22
 
19
23
  ```typescript
20
24
  import { createPicked } from '@picked/client'
@@ -30,7 +34,16 @@ const picked = createPicked({
30
34
 
31
35
  ## Custom Tools
32
36
 
33
- You can extend the Developer Tools with your own project-specific tools, surfaced under a **Custom Tools** tab. Each tool is a framework-adapted component — authored with the same `adaptReactComponent` / `adaptSvelteComponent` helpers you already use — so you can build it in your app's framework and it receives the live Picked client exactly like an experience component does (React: `usePicked()`; Svelte: `getPicked()`). Tools can both read client state and call client methods.
37
+ You can extend the Developer Tools with your own tools for one project. They appear
38
+ under a **Custom Tools** tab.
39
+
40
+ Each tool is a framework-adapted component. Write it with the same
41
+ `adaptReactComponent` or `adaptSvelteComponent` helper that you already use. You can
42
+ therefore build the tool in the framework of your application.
43
+
44
+ The tool receives the live Picked client, exactly as an experience component does. In
45
+ React, use `usePicked()`. In Svelte, use `getPicked()`. A tool can read client state
46
+ and call client methods.
34
47
 
35
48
  ```typescript
36
49
  import { createPicked } from '@picked/client'
@@ -48,4 +61,8 @@ const picked = createPicked({
48
61
  })
49
62
  ```
50
63
 
51
- The Developer Tools shell is rendered with Svelte, so a tool's framework must also be registered on the client. A React app needs `reactFrameworkPlugin` (for the tool) alongside the Svelte framework and `svelteDevtoolsPlugin` (for the shell). If a tool's framework isn't registered, its tab shows a warning instead of rendering.
64
+ Svelte renders the Developer Tools shell, so you must also register the framework of
65
+ your tool on the client. A React application needs `reactFrameworkPlugin` for the
66
+ tool, together with the Svelte framework and `svelteDevtoolsPlugin` for the shell.
67
+ When the framework of a tool is not registered, the tab of that tool shows a warning
68
+ and no content.
@@ -6,7 +6,8 @@ import { Screenshot } from '../../components/Screenshot'
6
6
 
7
7
  # Conditions
8
8
 
9
- A condition evaluates logic and branches the flow into two paths — one for when the condition is true, another for when it's false.
9
+ A condition evaluates a rule and splits the flow into two paths. One path is for a
10
+ true result, the other for a false result.
10
11
 
11
12
  <Screenshot
12
13
  route="/{orgSlug}/{projectId}/workspaces/{workspaceId}/conditions"
@@ -18,42 +19,54 @@ A condition evaluates logic and branches the flow into two paths — one for whe
18
19
  1. Open your project.
19
20
  2. Click **Conditions** in the sidebar.
20
21
  3. Click **New Condition**.
21
- 4. Enter a name and key.
22
+ 4. Enter a name and a key.
22
23
  5. Click **Create**.
23
24
 
24
- ## Configure a condition
25
+ ## Set up a condition
25
26
 
26
- **Name**: The display name shown in the dashboard. Not visible to visitors.
27
+ **Name**: The name that the dashboard shows. Your visitors do not see it.
27
28
 
28
- **Key**: The programmatic identifier. Set once, can't change. Not visible to visitors.
29
+ **Key**: The identifier for your application. You set it once and you cannot change
30
+ it. Your visitors do not see it.
29
31
 
30
- ## Define logic
32
+ ## Define the rule
31
33
 
32
- Select a condition node in the flow builder to open its inspector. The **Logic** section contains a visual [condition builder](/flow-builder/condition-builder).
34
+ Choose a condition node in the flow builder to open its inspector. The **Logic**
35
+ section holds a visual [condition builder](/flow-builder/condition-builder).
33
36
 
34
- The condition builder lets you create rules using AND/OR groups. Each rule compares a data source against an operator and a target value.
37
+ The condition builder lets you write a rule with AND groups and OR groups. Each rule
38
+ compares a data source against an operator and a value.
35
39
 
36
- ### Available data sources
40
+ ### Data sources
37
41
 
38
- **Responses** — values visitors have submitted through form fields. For example, check if a visitor entered a specific email domain or selected a particular option.
42
+ **Responses** — the values that your visitors send through form fields. An example is
43
+ a check of whether a visitor entered one email domain, or chose one option.
39
44
 
40
- **Actions** — references to actions that have been triggered during the flow.
45
+ **Actions** — the actions that ran during the flow.
41
46
 
42
- **Feature flags** — the state of feature flags in your project. Branch on whether a visitor is allocated to a flag.
47
+ **Feature flags** — the state of each feature flag in your project. Branch on whether
48
+ Picked allocates a visitor to a flag.
43
49
 
44
- **Location** — properties of the visitor's current page URL, including pathname, search parameters, hostname, and hash. For example, show different content based on which page the visitor is on.
50
+ **Location** — the parts of the current page URL of the visitor. These are the
51
+ pathname, the search parameters, the hostname, and the hash. An example is content
52
+ that changes with the page that the visitor is on.
45
53
 
46
54
  ### Example
47
55
 
48
- To branch based on a visitor's country selection:
56
+ To take a branch on the country that a visitor chooses:
49
57
 
50
58
  1. Add a rule: **Responses → country** equals `US`.
51
- 2. The green (true) path handles US visitors. The red (false) path handles everyone else.
59
+ 2. The green path, for a true result, handles a visitor in the US. The red path, for
60
+ a false result, handles every other visitor.
52
61
 
53
- To combine multiple conditions, create an AND or OR group and add rules within it.
62
+ To join more than one rule, create an AND group or an OR group and add the rules
63
+ inside it.
54
64
 
55
- ## Branching
65
+ ## Branches
56
66
 
57
- In the flow builder, condition nodes have two output handles. The green handle (true) leads to the path taken when the condition matches. The red handle (false) leads to the alternative path.
67
+ In the flow builder, a condition node has two output handles. The green handle, for a
68
+ true result, leads to the path for a match. The red handle, for a false result, leads
69
+ to the other path.
58
70
 
59
- You can chain conditions. Connect the output of one condition to the input of another to create complex decision trees.
71
+ You can chain conditions. Connect the output of one condition to the input of another
72
+ to build a decision tree.
@@ -6,88 +6,119 @@ import { Screenshot } from '../../../components/Screenshot'
6
6
 
7
7
  # Asset Library
8
8
 
9
- The Asset Library stores the files your content references: images, video, documents, and HTML.
9
+ The Asset Library holds the files that your content points at. These are images,
10
+ video, documents, and HTML.
10
11
 
11
12
  <Screenshot
12
13
  route="/{orgSlug}/{projectId}/assets"
13
14
  alt="The asset library on the Picked dashboard"
14
15
  />
15
16
 
16
- ## Upload and manage assets
17
+ ## Upload and control your assets
17
18
 
18
- The Asset Library is a project-level store. Upload a file, then reference it from any Content Entry in the project.
19
+ The Asset Library is a project-level store. Upload a file, then point at it from any
20
+ Content Entry in the project.
19
21
 
20
- - **Size limit:** 50 MB per file.
21
- - **Allowed types:** images (PNG, JPEG, WebP, AVIF, GIF, SVG), video (MP4, WebM), common document formats, and HTML (`text/html`).
22
+ - **Size limit:** 50 MB for each file.
23
+ - **Allowed types:** an image in PNG, JPEG, WebP, AVIF, GIF, or SVG. A video in MP4
24
+ or WebM. A common document format. HTML, as `text/html`.
22
25
 
23
- Uploads outside the allowed types or over the size limit are rejected at upload time.
26
+ Picked rejects a file of another type. It also rejects a file above the size limit.
24
27
 
25
28
  ## Reference an asset from a field
26
29
 
27
- Two field types point at library items:
30
+ Two field types point at an item in the library:
28
31
 
29
- - An **Asset** field references an image, video, or document.
30
- - An **HTML asset** field references an uploaded `.html` file.
32
+ - An **Asset** field points at an image, a video, or a document.
33
+ - An **HTML asset** field takes a `.html` file from your library.
31
34
 
32
- Add the field to a [layout](/content/layouts), then pick a library item when filling in the [Content Entry](/content/content-entries).
35
+ Add the field to a [layout](/content/layouts). Then choose an item from the library
36
+ when you fill in the [Content Entry](/content/content-entries).
33
37
 
34
38
  ## Pick an asset
35
39
 
36
- Every Asset field opens the same picker: click **Choose file** (or **Replace** on a field that already has a value) to open a modal with two tabs, **Library** (browse existing assets) and **Upload** (add a new file).
40
+ Every Asset field opens the same picker. Click **Choose file** to open it. On a field
41
+ with a value already, click **Replace**. The modal has two tabs: **Library**, where
42
+ you browse the assets that are there, and **Upload**, where you add a new file.
37
43
 
38
44
  <Screenshot
39
45
  route="/{orgSlug}/{projectId}/design-systems/new"
40
46
  wait='button:has-text("Upload file")'
41
47
  click='button:has-text("Upload file")'
42
48
  selector="[role=dialog]"
43
- alt="The asset picker modal on the Picked dashboard, showing the Library tab with its search box, type filter, and Sort by menu"
49
+ alt="The asset picker modal on the Picked dashboard, with the Library tab, its search box, its type filter, and its Sort by menu"
44
50
  renderWidth={1072}
45
51
  renderHeight={790}
46
52
  />
47
53
 
48
54
  ### Search, filter, and sort
49
55
 
50
- The Library tab has three controls for narrowing a large asset list, all applied on the server across the whole library, not just the assets already loaded:
56
+ The Library tab has three controls that make a large asset list smaller. The server
57
+ applies each one across the whole library, and not only across the assets that it
58
+ loaded already:
51
59
 
52
- - **Search:** filters by file name as you type.
53
- - **Type filter:** narrows to a media-type bucket (All types, Images, Video, Audio, Documents, or Archives).
54
- - **Sort by:** orders by Name or Date uploaded, each ascending or descending.
60
+ - **Search:** narrows the list by file name while you type.
61
+ - **Type filter:** narrows the list to one media type. The choices are All types,
62
+ Images, Video, Audio, Documents, and Archive files.
63
+ - **Sort by:** orders the list by the Name or by the Date uploaded, each one
64
+ ascending or descending.
55
65
 
56
66
  :::note
57
- Results are paginated. Use **Load more** at the bottom of the list to fetch the next page.
67
+ The results come one page at a time. Click **Load more** at the bottom of the list to
68
+ read the next page.
58
69
  :::
59
70
 
60
- ### Select one or several assets
71
+ ### Choose one asset or several
61
72
 
62
- The picker adapts to how many assets the field accepts:
73
+ The picker changes with the number of assets that the field takes:
63
74
 
64
- - A field that holds a single asset (a layout's Asset field, or a design system's guidance file) shows a **radio** indicator next to each row. Picking a new asset replaces the current one.
65
- - A surface that accepts several assets at once (for example, a workbench's Files tab) shows a **checkbox** indicator and a running selection count in the detail panel.
75
+ - A field that holds one asset shows a **radio** indicator next to each row. The
76
+ Asset field of a layout and the guidance file of a design system both do this. A
77
+ new choice replaces the current asset.
78
+ - A place that takes several assets at once shows a **checkbox** indicator. The
79
+ detail panel then also shows a count of what you chose. The Files tab of a
80
+ workbench does this.
66
81
 
67
- The detail panel on the right shows the selected asset's kind, dimensions, size, and upload date.
82
+ The detail panel on the right shows the kind, the dimensions, the size, and the
83
+ upload date of the asset that you chose.
68
84
 
69
85
  ### Open an asset in a new tab
70
86
 
71
- Each row, and the detail panel for the currently selected asset, has an **Open in new tab** control. It links to the asset's full detail page without losing your current selection in the picker.
87
+ Each row has an **Open in new tab** control, and so does the detail panel of the
88
+ asset that you chose. It links to the full detail page of the asset, and your choice
89
+ in the picker stays as it is.
72
90
 
73
91
  :::tip
74
- Use this to double-check an asset (its full-size preview, every uploaded version) before committing to it.
92
+ Use this to check an asset again before you choose it. You can see the full-size
93
+ preview and every version that somebody uploaded.
75
94
  :::
76
95
 
77
96
  ## HTML assets
78
97
 
79
- Upload a `.html` file and reference it from an **HTML asset** field. On upload, Picked runs an advisory scan that guides you but never blocks the upload. It surfaces performance, SEO, and accessibility findings so you can improve the file before publishing:
98
+ Upload a `.html` file and point at it from an **HTML asset** field. Picked then scans
99
+ the file. The scan is advisory: it helps you, and it never stops you. It
100
+ reports findings about speed, about search rank, and about accessibility, so that you
101
+ can improve the file before you publish it:
80
102
 
81
- - **File size:** a warning at 100 KB and a stronger one at 250 KB.
82
- - **Inline images:** a note when inline base64 image data adds roughly 50 KB or more.
83
- - **Image dimensions:** images missing an explicit width or height, which risk layout shift.
84
- - **Lazy loading:** images without `loading="lazy"`.
85
- - **Link safety:** external links with `target="_blank"` but no `rel="noopener"`.
86
- - **Link SEO:** external links without `rel="nofollow"`.
87
- - **Accessibility:** an axe-core pass covering alt text, heading order, contrast, and more.
103
+ - **File size:** a warning at 100 KB, and a stronger one at 250 KB.
104
+ - **Inline images:** a note when inline `base64` image data adds about 50 KB or more.
105
+ - **Image dimensions:** an image with no width and no height. Such an image can move
106
+ the content around it while the page loads.
107
+ - **Lazy load:** an image with no `loading="lazy"` attribute.
108
+ - **Link safety:** an external link with `target="_blank"` and no `rel="noopener"`.
109
+ - **Link search rank:** an external link with no `rel="nofollow"`.
110
+ - **Accessibility:** a pass by `axe-core`. It covers alt text, heading order,
111
+ contrast, and more.
88
112
 
89
- Every finding is advisory. You can always upload the file as is.
113
+ Every finding is advisory. You can always upload the file as it is.
90
114
 
91
115
  ## How assets are served
92
116
 
93
- Assets are served from a sandboxed storage origin, separate from your app's trusted origin. Serving HTML from its own origin means an uploaded document executes in isolation and cannot reach the page that embeds it. When an [Experience Content](/delivery-api/experience-content) response includes an HTML asset, its content is inlined into the response, so the SDK renders it without a second storage fetch.
117
+ Picked serves each asset from a sandboxed storage origin. That origin is separate
118
+ from the trusted origin of your application. HTML therefore comes from its own
119
+ origin, so a document that you upload runs in isolation and cannot reach the page
120
+ that holds it.
121
+
122
+ An [Experience Content](/delivery-api/experience-content) response can hold an HTML
123
+ asset. The response then carries the content of that asset, and the SDK renders it
124
+ with no second request to storage.
@@ -23,8 +23,14 @@ A [Page](/content/pages) has a single Step, and that Step links to its entry thr
23
23
 
24
24
  ## Edit entry data
25
25
 
26
- The entry editor renders a form driven by the layout schema: one input per field, in the order the schema defines. Repeatable fields appear as sortable lists you can add to and reorder. Group fields nest their inputs under a single heading.
26
+ The entry editor renders a form from the layout schema. There is one input for each
27
+ field, in the order that the schema sets. A repeatable field appears as a sortable
28
+ list. You can add to that list and put it into a new order. A group field holds its
29
+ inputs under one heading.
27
30
 
28
31
  ## Validation
29
32
 
30
- Invalid data surfaces as per-field errors using a JSON-path style that points at the exact location in the entry, for example `sections[0].data.title`. Fix every error before publishing: the published surface only serves valid content.
33
+ Invalid data appears as an error on each field. The error carries a path in the JSON
34
+ style, and it points at the exact place in the entry, for example
35
+ `sections[0].data.title`. Fix every error before you publish, because Picked serves
36
+ valid content only.
@@ -15,23 +15,31 @@ Layouts are reusable JSON schemas. Page Layouts back standalone Pages; Step Layo
15
15
 
16
16
  ## What a layout is
17
17
 
18
- A layout is a reusable schema that defines the fields a piece of content can hold. It holds no data itself: a [Content Entry](/content/content-entries) instantiates the layout and fills it in. The dashboard groups both kinds of layout under **Models**.
18
+ A layout is a reusable schema. It defines the fields that a piece of content can
19
+ hold. A layout holds no data itself. A [Content Entry](/content/content-entries)
20
+ creates one copy of a layout and fills it in. The dashboard shows both layout kinds
21
+ under **Models**.
19
22
 
20
- ## Page layouts vs step layouts
23
+ ## A page layout and a step layout
21
24
 
22
- A layout has a fixed category that decides what it backs:
25
+ Each layout has a fixed category, and the category decides what the layout gives its
26
+ shape to:
23
27
 
24
- | Layout | Backs | Used by |
28
+ | Layout | It gives its shape to | Who renders it |
25
29
  | --- | --- | --- |
26
- | **Page Layout** | A standalone [Page](/content/pages). | The SDK renders the bound entry on your server. |
27
- | **Step Layout** | A single [Step](/steps) inside a Flow. | The Step renders the bound entry in the browser. |
30
+ | **Page Layout** | A standalone [Page](/content/pages). | The SDK renders the entry on your server. |
31
+ | **Step Layout** | One [Step](/steps) inside a Flow. | The Step renders the entry in the browser. |
28
32
 
29
33
  ## Create a layout
30
34
 
31
- 1. Open your workspace and click **Models** in the sidebar.
32
- 2. Click **New Model** and choose the category, **Page Layout** or **Step Layout**.
33
- 3. Enter a name and a **Key**. The Key is a unique, stable identifier used in SDK code and API references.
34
- 4. Add fields (see below) and save.
35
+ 1. Open your workspace.
36
+ 2. Click **Models** in the sidebar.
37
+ 3. Click **New Model**.
38
+ 4. Choose the category, **Page Layout** or **Step Layout**.
39
+ 5. Enter a name and a **Key**. The Key is a unique, stable identifier. Your SDK code
40
+ and your API calls both use it.
41
+ 6. Add your fields. See below.
42
+ 7. Save.
35
43
 
36
44
  The category is fixed at creation and cannot be changed later.
37
45
 
@@ -41,30 +49,38 @@ A layout is built from fields. Each field has a type that decides its editor and
41
49
 
42
50
  | Type | Stores | Use it for |
43
51
  | --- | --- | --- |
44
- | **Single-line text** | A short string. | Titles, labels, short headlines. |
45
- | **Multi-line text** | A longer plain string. | Descriptions, paragraphs without formatting. |
46
- | **Markdown** | A Markdown string. | Rich body copy with formatting. |
47
- | **Slug** | A URL-safe string. | Path segments, identifiers. |
48
- | **Number** | A numeric value. | Prices, counts, ratings. |
49
- | **Boolean** | A true/false value. | Toggles, flags. |
50
- | **Date** | A date value. | Publish dates, deadlines. |
51
- | **Color** | A color value. | Theme accents, swatches. |
52
- | **JSON** | An arbitrary JSON value. | Structured data with no dedicated editor. |
53
- | **Group** | A nested object of fields. | Grouping related fields together. |
54
- | **Section** | An embedded [Section](/content/sections) schema. | Reusing a shared schema fragment. |
55
- | **Asset** | A reference to an [Asset Library](/content/asset-library) item. | Images, video, documents. |
56
- | **HTML asset** | A reference to an uploaded `.html` file. | Pre-built HTML embedded into content. |
52
+ | **Single-line text** | A short string. | A title, a label, or a short headline. |
53
+ | **Multi-line text** | A longer plain string. | A description, or a paragraph with no format marks. |
54
+ | **Markdown** | A Markdown string. | Body copy with format marks. |
55
+ | **Slug** | A URL-safe string. | A part of a path, or an identifier. |
56
+ | **Number** | A numeric value. | A price, a count, or a rating. |
57
+ | **Boolean** | A true or false value. | A toggle or a flag. |
58
+ | **Date** | A date value. | A publish date or a deadline. |
59
+ | **Color** | A color value. | A theme accent or a swatch. |
60
+ | **JSON** | Any JSON value. | Structured data with no editor of its own. |
61
+ | **Group** | An object of fields inside the layout. | A set of related fields, held together. |
62
+ | **Section** | A [Section](/content/sections) schema inside the layout. | A shared schema fragment that you reuse. |
63
+ | **Asset** | A link to an [Asset Library](/content/asset-library) item. | An image, a video, or a document. |
64
+ | **HTML asset** | A link to a `.html` file in your library. | HTML that you wrote before, held inside the content. |
57
65
 
58
66
  ## Repeatable and grouped fields
59
67
 
60
- Any field can be made **repeatable**, which renders as a sortable list of values rather than a single value. Use it for galleries, feature lists, or any collection.
68
+ You can make any field **repeatable**. It then renders as a sortable list of values,
69
+ and not as one value. Use it for a gallery, for a list of features, or for any
70
+ collection.
61
71
 
62
- A **Group** field nests a set of fields under one key, producing a structured object. Combine repeatable with a group to model a list of objects, such as a list of feature cards.
72
+ A **Group** field holds a set of fields under one key, and it gives a structured
73
+ object. Make a group repeatable to describe a list of objects, such as a list of
74
+ feature cards.
63
75
 
64
- ## Composing with sections
76
+ ## Build with sections
65
77
 
66
- A **Section** field embeds a reusable [Section](/content/sections) schema inside the layout. Define a common structure, such as a hero or a feature list, once as a Section, then reference it from any Page or Step Layout.
78
+ A **Section** field holds a reusable [Section](/content/sections) schema inside the
79
+ layout. Define a common structure one time as a Section, such as a hero or a list of
80
+ features. Then point at it from any Page Layout or Step Layout.
67
81
 
68
- ## Changing a schema
82
+ ## Change a schema
69
83
 
70
- Editing a layout's schema can leave existing Content Entries out of date. After a schema change, revalidate the entries that use the layout and fix any per-field errors before publishing.
84
+ A change to the schema of a layout can make a Content Entry invalid. After such
85
+ a change, check each entry that uses the layout again. Fix every field error before
86
+ you publish.
@@ -13,16 +13,19 @@ A Page is a standalone, server-rendered experience backed by CMS content, built
13
13
  alt="The experiences list, where Pages and Flows are created on the Picked dashboard"
14
14
  />
15
15
 
16
- ## Pages vs flows
16
+ ## Pages and flows
17
17
 
18
- Picked has two kinds of experience:
18
+ Picked has two experience kinds:
19
19
 
20
20
  | Experience | What it is | Use it for |
21
21
  | --- | --- | --- |
22
- | **Page** | A standalone experience rendered on your server, backed by a Content Entry. | SEO-critical landing pages, campaign pages, content the crawler must see. |
23
- | **Flow** | A multi-step, interactive experience rendered in the browser. | Quizzes, surveys, product finders, multi-step onboarding. |
22
+ | **Page** | A standalone experience that your server renders from a Content Entry. | A landing page or a campaign page where the search rank matters, and any content that a crawler must see. |
23
+ | **Flow** | An interactive experience of more than one step, which the browser renders. | A quiz, a survey, a product finder, and onboarding of more than one step. |
24
24
 
25
- Reach for a **Page** when the content must appear in the server HTML for search engines and social unfurls. Reach for a **Flow** when the value is in the interaction, and client-side rendering is fine. See [Experiences](/experiences) for the wider model.
25
+ Choose a **Page** when the content must be in the HTML from your server, for a search
26
+ engine and for a social preview. Choose a **Flow** when the value is in the
27
+ interaction, and a browser render is acceptable. See
28
+ [Experiences](/experiences) for the wider picture.
26
29
 
27
30
  ## How a page fits together
28
31
 
@@ -42,26 +45,38 @@ Author (dashboard) -> Publish -> Delivery API (config + content)
42
45
 
43
46
  ## Create a page
44
47
 
45
- 1. Open your project and select a workspace.
46
- 2. Click **Experiences** in the sidebar.
47
- 3. Click **New Experience** and choose the **Page** type.
48
- 4. Pick a **Page Layout**. The layout determines which fields the page holds.
49
- 5. Click **Create**.
48
+ 1. Open your project.
49
+ 2. Choose a workspace.
50
+ 3. Click **Experiences** in the sidebar.
51
+ 4. Click **New Experience**.
52
+ 5. Choose the **Page** type.
53
+ 6. Choose a **Page Layout**. The layout sets which fields the page holds.
54
+ 7. Click **Create**.
50
55
 
51
56
  A Content Entry is created and linked to the page on its first save, so the page always has somewhere to store its data.
52
57
 
53
58
  ## Edit page content
54
59
 
55
- The Page editor has a **Properties** tab for the page's content and a **Settings** tab for its name, condition, and layout. Fill in the fields on the **Properties** tab. The inspector on the right edits the selected field, and the preview panel shows the page as it fills in.
60
+ The Page editor has two tabs. The **Properties** tab holds the content of the page.
61
+ The **Settings** tab holds its name, its condition, and its layout. Fill in the
62
+ fields on the **Properties** tab. The inspector on the right edits the field that you
63
+ choose, and the preview panel shows the page while it fills in.
56
64
 
57
65
  ## Change or remove the layout
58
66
 
59
- Use the change-layout control on the **Settings** tab to switch the page to a different Page Layout. Unlinking a layout detaches the Content Entry from the page. The entry is not deleted, but the page no longer has content to render until you bind a layout again.
67
+ Use the change-layout control on the **Settings** tab to move the page to another
68
+ Page Layout. When you unlink a layout, Picked separates the Content Entry from the
69
+ page. It deletes no entry, but the page then has no content to render until you
70
+ attach a layout again.
60
71
 
61
72
  ## Validate and publish
62
73
 
63
- Invalid fields surface inline as per-field errors while you edit, so you can fix them before publishing. When the page is valid, publish the workspace to make it live. Publishing produces the version the Delivery API serves to anonymous readers.
74
+ An invalid field shows an error next to it while you edit, so that you can correct it
75
+ before you publish. When the page is valid, publish the workspace to make it live.
76
+ That makes the version that the Delivery API serves to an anonymous reader.
64
77
 
65
78
  ## Render a page
66
79
 
67
- A published Page is rendered by the SDK on your server. See the [Build a Personalized Page](/guides/build-a-personalized-page) guide for the end-to-end walkthrough, and [Server-Side Rendering](/sdk/ssr) for the SDK reference.
80
+ The SDK renders a published Page on your server. See the
81
+ [Build a Personalized Page](/guides/build-a-personalized-page) guide for the full
82
+ steps, and [Server-Side Rendering](/sdk/ssr) for the SDK reference.