@picked/svelte 0.0.1-dev.1789541668638 → 0.0.1-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.
Files changed (132) hide show
  1. package/dist/component.d.ts +5 -5
  2. package/dist/component.js +1 -1
  3. package/dist/context.js +1 -1
  4. package/dist/form/index.d.ts +15 -3
  5. package/dist/form/index.js +1 -1
  6. package/dist/hooks/client.d.ts +1 -1
  7. package/dist/hooks/client.js +1 -1
  8. package/dist/hooks/field.d.ts +5 -16
  9. package/dist/hooks/field.js +1 -1
  10. package/dist/hooks/index.d.ts +1 -9
  11. package/dist/hooks/index.js +1 -1
  12. package/dist/hooks/step.d.ts +15 -93
  13. package/dist/hooks/step.js +1 -1
  14. package/dist/hooks/storage.d.ts +2 -2
  15. package/dist/hooks/storage.js +1 -1
  16. package/dist/hooks/stores.d.ts +1 -1
  17. package/dist/hooks/stores.js +1 -1
  18. package/dist/index.d.ts +1 -8
  19. package/dist/index.js +1 -1
  20. package/dist/plugins/devtools/DevToolsExperience.svelte +53 -355
  21. package/dist/plugins/devtools/PickedLogo.svelte +58 -0
  22. package/dist/plugins/devtools/components/ExperienceInstanceListItem.svelte +4 -17
  23. package/dist/plugins/devtools/components/ExperienceInstancesTable.svelte +19 -26
  24. package/dist/plugins/devtools/components/Tabs.svelte +12 -69
  25. package/dist/plugins/devtools/experience.d.ts +1 -0
  26. package/dist/plugins/devtools/experience.js +1 -0
  27. package/dist/plugins/devtools/index.d.ts +0 -2
  28. package/dist/plugins/devtools/index.js +1 -1
  29. package/dist/plugins/devtools/plugin.d.ts +5 -37
  30. package/dist/plugins/devtools/plugin.js +1 -1
  31. package/dist/plugins/devtools/screens/components/ComponentsListScreen.svelte +14 -18
  32. package/dist/plugins/devtools/screens/experience-instances/ExperienceInstancesListScreen.svelte +3 -1
  33. package/dist/plugins/devtools/screens/experiences/ExperienceDetailsScreen.svelte +33 -31
  34. package/dist/plugins/devtools/screens/experiences/ExperienceExperienceInstancesListScreen.svelte +3 -1
  35. package/dist/plugins/devtools/screens/experiences/ExperienceTreeScreen.svelte +103 -293
  36. package/dist/plugins/devtools/screens/experiences/ExperiencesListScreen.svelte +1 -2
  37. package/dist/plugins/devtools/screens/frameworks/FrameworksListScreen.svelte +13 -15
  38. package/dist/plugins/devtools/screens/history/HistoryEntriesTable.svelte +16 -22
  39. package/dist/plugins/devtools/screens/history/HistoryEntryListItem.svelte +1 -7
  40. package/dist/plugins/devtools/screens/predicates/PredicatesListScreen.svelte +13 -15
  41. package/dist/plugins/devtools/screens/project/ProjectScreen.svelte +1 -46
  42. package/dist/plugins/framework/index.js +1 -1
  43. package/dist/plugins/framework/plugin.d.ts +4 -4
  44. package/dist/plugins/framework/plugin.js +1 -1
  45. package/dist/render/browser.d.ts +2 -35
  46. package/dist/render/browser.js +1 -1
  47. package/dist/render/server.d.ts +8 -22
  48. package/dist/render/server.js +1 -1
  49. package/dist/router/Step.svelte +4 -6
  50. package/dist/router/StepRouter.svelte +34 -14
  51. package/dist/router/context.d.ts +3 -3
  52. package/dist/router/context.js +1 -1
  53. package/dist/router/index.js +1 -1
  54. package/dist/server/index.d.ts +2 -2
  55. package/dist/server/index.js +1 -1
  56. package/dist/utils/array.js +1 -1
  57. package/dist/vite-env.d.js +1 -0
  58. package/package.json +33 -106
  59. package/dist/.tsbuildinfo +0 -1
  60. package/dist/_virtual/_vite/preload-helper.js +0 -1
  61. package/dist/components/LazyImage.svelte +0 -192
  62. package/dist/components/index.d.ts +0 -1
  63. package/dist/components/index.js +0 -1
  64. package/dist/experience/ExperienceHost.svelte +0 -112
  65. package/dist/experience/ExperienceSlot.svelte +0 -154
  66. package/dist/experience/HtmlRender.svelte +0 -52
  67. package/dist/experience/set-picked-context.d.ts +0 -29
  68. package/dist/experience/set-picked-context.js +0 -1
  69. package/dist/form/__tests__/CreateFormHarness.svelte +0 -30
  70. package/dist/form/create-form.js +0 -1
  71. package/dist/form/create-form.svelte.d.ts +0 -40
  72. package/dist/form/create-form.svelte.js +0 -1
  73. package/dist/form/get-form.d.ts +0 -30
  74. package/dist/form/get-form.js +0 -1
  75. package/dist/hooks/action.d.ts +0 -40
  76. package/dist/hooks/action.js +0 -1
  77. package/dist/hooks/content.d.ts +0 -18
  78. package/dist/hooks/content.js +0 -1
  79. package/dist/hooks/create-query/index.d.ts +0 -145
  80. package/dist/hooks/create-query/index.js +0 -1
  81. package/dist/hooks/events.d.ts +0 -2
  82. package/dist/hooks/events.js +0 -1
  83. package/dist/hooks/feature.d.ts +0 -47
  84. package/dist/hooks/feature.js +0 -1
  85. package/dist/hooks/predicate.d.ts +0 -3
  86. package/dist/hooks/predicate.js +0 -1
  87. package/dist/hooks/reference.d.ts +0 -61
  88. package/dist/hooks/reference.js +0 -1
  89. package/dist/plugins/devtools/PickedIcon.svelte +0 -19
  90. package/dist/plugins/devtools/components/AdaptedToolHost.svelte +0 -103
  91. package/dist/plugins/devtools/customTools.d.ts +0 -27
  92. package/dist/plugins/devtools/customTools.js +0 -1
  93. package/dist/plugins/devtools/screens/config/ConfigScreen.svelte +0 -160
  94. package/dist/plugins/devtools/screens/content/ContentListScreen.svelte +0 -89
  95. package/dist/plugins/devtools/screens/custom-tools/CustomToolsScreen.svelte +0 -29
  96. package/dist/plugins/devtools/screens/events/EventListItem.svelte +0 -216
  97. package/dist/plugins/devtools/screens/events/EventsListScreen.svelte +0 -18
  98. package/dist/plugins/devtools/screens/events/EventsTable.svelte +0 -76
  99. package/dist/plugins/devtools/screens/features/FeaturesListScreen.svelte +0 -239
  100. package/dist/plugins/devtools/screens/fields/FieldTableRow.svelte +0 -276
  101. package/dist/plugins/devtools/screens/fields/FieldsListScreen.svelte +0 -12
  102. package/dist/plugins/devtools/screens/fields/FieldsTable.svelte +0 -78
  103. package/dist/plugins/devtools/screens/identity/IdentityScreen.svelte +0 -66
  104. package/dist/plugins/devtools/screens/responses/ResponseTableRow.svelte +0 -280
  105. package/dist/plugins/devtools/screens/responses/ResponsesListScreen.svelte +0 -12
  106. package/dist/plugins/devtools/screens/responses/ResponsesTable.svelte +0 -88
  107. package/dist/plugins/devtools/ui/actions/Button.svelte +0 -175
  108. package/dist/plugins/devtools/ui/actions/CopyButton.svelte +0 -88
  109. package/dist/plugins/devtools/ui/data/Badge.svelte +0 -62
  110. package/dist/plugins/devtools/ui/data/CodeBlock.svelte +0 -38
  111. package/dist/plugins/devtools/ui/data/DataTable.svelte +0 -144
  112. package/dist/plugins/devtools/ui/data/EmptyState.svelte +0 -26
  113. package/dist/plugins/devtools/ui/data/ExpandableRow.svelte +0 -66
  114. package/dist/plugins/devtools/ui/data/VisualizationContainer.svelte +0 -55
  115. package/dist/plugins/devtools/ui/feedback/Banner.svelte +0 -116
  116. package/dist/plugins/devtools/ui/feedback/Spinner.svelte +0 -79
  117. package/dist/plugins/devtools/ui/forms/Checkbox.svelte +0 -139
  118. package/dist/plugins/devtools/ui/forms/RadioGroup.svelte +0 -218
  119. package/dist/plugins/devtools/ui/forms/Select.svelte +0 -137
  120. package/dist/plugins/devtools/ui/forms/Switch.svelte +0 -158
  121. package/dist/plugins/devtools/ui/forms/TextField.svelte +0 -125
  122. package/dist/plugins/devtools/ui/index.d.ts +0 -22
  123. package/dist/plugins/devtools/ui/index.js +0 -1
  124. package/dist/plugins/devtools/ui/layout/Card.svelte +0 -55
  125. package/dist/plugins/devtools/ui/layout/Divider.svelte +0 -34
  126. package/dist/plugins/devtools/ui/layout/Spacer.svelte +0 -11
  127. package/dist/plugins/devtools/ui/layout/Stack.svelte +0 -129
  128. package/dist/plugins/devtools/ui/overlays/Tooltip.svelte +0 -90
  129. package/dist/plugins/devtools/ui/tokens.css +0 -144
  130. package/dist/plugins/devtools/ui/typography/Heading.svelte +0 -55
  131. package/dist/plugins/devtools/ui/typography/Text.svelte +0 -93
  132. package/dist/utils/ErrorBoundary.svelte +0 -27
@@ -1,154 +0,0 @@
1
- <script lang="ts">
2
- /**
3
- * @file Slot-based experience renderer. Renders every registered experience that targets the
4
- * named slot and whose condition is active, ordered by placement. Active is read synchronously
5
- * from the seeded condition-results store (sync on SSR / hydration first paint); on a cache miss
6
- * (standalone, no snapshot) the condition is evaluated asynchronously and the store update
7
- * re-renders reactively.
8
- */
9
- import type { ExperienceStore, ExperienceTarget } from '@picked/client'
10
- import { evaluateConditionMemo, hashRule, ruleReferencesActionDeep } from '@picked/client/server'
11
- import { getPicked, useUnit } from '../hooks'
12
- import ExperienceHost from './ExperienceHost.svelte'
13
-
14
- type ExperienceConfig = ReturnType<ExperienceStore['configStore']['getState']>
15
- type ConditionRule = ExperienceConfig['decisionLogic']
16
-
17
- interface Props {
18
- /**
19
- * Slot name. Maps to the `.picked-slot-<name>` selector that targeted experiences declare.
20
- * Named `name` rather than `slot` because Svelte's compiler reserves the `slot` attribute for
21
- * legacy named-slot assignment, so it cannot be used as a component prop.
22
- */
23
- name: string
24
- }
25
-
26
- const { name }: Props = $props()
27
-
28
- const client = getPicked()
29
- const selector = $derived(`.picked-slot-${name}`)
30
-
31
- const PLACEMENT_ORDER: ExperienceTarget['placement'][] = [
32
- 'replace',
33
- 'before',
34
- 'prepend',
35
- 'append',
36
- 'after',
37
- ]
38
-
39
- interface Candidate {
40
- experience: ExperienceStore
41
- placement: ExperienceTarget['placement']
42
- condition: ConditionRule
43
- hash: string
44
- }
45
-
46
- const experiences = useUnit(client.experiences.listStore)
47
- const conditionResults = useUnit(client.conditionResults.store)
48
- const conditions = useUnit(client.conditions.listStore)
49
-
50
- const conditionsByKey = $derived.by(() => {
51
- const byKey: Parameters<typeof ruleReferencesActionDeep>[1] = {}
52
- for (const condition of $conditions) {
53
- byKey[condition.key] = condition
54
- }
55
-
56
- return byKey
57
- })
58
-
59
- /**
60
- * Returns the sort rank for a placement; unknown placements sort last.
61
- *
62
- * @param {ExperienceTarget['placement']} placement - The target placement.
63
- * @returns {number} The placement's index in the precedence order.
64
- * @example
65
- * placementRank('append')
66
- */
67
- function placementRank(placement: ExperienceTarget['placement']): number {
68
- const index = PLACEMENT_ORDER.indexOf(placement)
69
- return index === -1 ? PLACEMENT_ORDER.length : index
70
- }
71
-
72
- /**
73
- * Maps an experience to a slot candidate, or null when it does not target this slot or carries
74
- * an action-referencing condition.
75
- *
76
- * @param {ExperienceStore} experience - The experience to inspect.
77
- * @returns {Candidate | null} The candidate, or null when the experience is not an eligible slot match.
78
- * @example
79
- * toCandidate(experienceStore)
80
- */
81
- function toCandidate(experience: ExperienceStore): Candidate | null {
82
- const config = experience.configStore.getState()
83
- const target = config.targetSelectors.find(
84
- (selectorTarget) => selectorTarget.selector === selector,
85
- )
86
- if (!target) {
87
- return null
88
- }
89
-
90
- // Action-referencing conditions are never cached (their side effect must re-run), so they can
91
- // never resolve through the synchronous `peek` the slot path relies on. Slots do not support
92
- // action-gated conditions in v1; excluding them also stops the selection effect from re-firing
93
- // the action on every render. The deep check follows composed `conditions.<key>` references so a
94
- // condition that reaches an action transitively is excluded too.
95
- if (ruleReferencesActionDeep(config.decisionLogic, conditionsByKey)) {
96
- return null
97
- }
98
-
99
- return {
100
- experience,
101
- placement: target.placement,
102
- condition: config.decisionLogic,
103
- hash: hashRule(config.decisionLogic),
104
- }
105
- }
106
-
107
- const candidates = $derived(
108
- $experiences
109
- .map(toCandidate)
110
- .filter((candidate): candidate is Candidate => candidate !== null)
111
- .sort((a, b) => placementRank(a.placement) - placementRank(b.placement)),
112
- )
113
-
114
- // Referencing `$conditionResults` keeps this recompute reactive to late condition writes
115
- // (the standalone cache-miss path), so a `peek` that returned `undefined` re-renders once
116
- // the async evaluation resolves and writes the store. An active `replace` experience wins:
117
- // the first one (it sorts first) renders alone, replacing any other slot matches.
118
- const active = $derived.by(() => {
119
- void $conditionResults
120
- const activeCandidates = candidates.filter(
121
- (candidate) => client.conditionResults.peek(candidate.hash) === true,
122
- )
123
- const firstReplace = activeCandidates.find((candidate) => candidate.placement === 'replace')
124
- return firstReplace ? [firstReplace] : activeCandidates
125
- })
126
-
127
- /**
128
- * Builds a plain, JSON-serialisable subset of the current URL for the evaluation context.
129
- * The live `Location` object is intentionally not passed: json-logic predicates read plain
130
- * values, and this mirrors the `SerializeLocation` shape the server selects against.
131
- *
132
- * @returns {Record<string, string>} The plain location subset.
133
- * @example
134
- * buildLocationContext()
135
- */
136
- function buildLocationContext(): Record<string, string> {
137
- const { href, pathname, search, hostname, origin, protocol, port, host, hash } = window.location
138
- return { href, pathname, search, hostname, origin, protocol, port, host, hash }
139
- }
140
-
141
- $effect(() => {
142
- for (const candidate of candidates) {
143
- if (client.conditionResults.peek(candidate.hash) === undefined) {
144
- void evaluateConditionMemo(client, candidate.condition, {
145
- context: { location: buildLocationContext() },
146
- })
147
- }
148
- }
149
- })
150
- </script>
151
-
152
- {#each active as candidate (candidate.experience.id)}
153
- <ExperienceHost experience={candidate.experience} {client} />
154
- {/each}
@@ -1,52 +0,0 @@
1
- <script lang="ts">
2
- /**
3
- * @file Renders a resolved html-asset field into a shadow root and re-executes its
4
- * Picked-tagged scripts. On the server the markup is emitted as a declarative shadow DOM
5
- * template, a parser-only feature the browser attaches as a real shadow root while parsing
6
- * the response, so content is present from first paint. On the client, the first commit
7
- * adopts that parser-attached root and only rehydrates its scripts; a client-only mount or a
8
- * later content change attaches and writes the shadow root imperatively instead.
9
- */
10
- import {
11
- isHtmlAssetValue,
12
- rehydrateScripts,
13
- supportsShadowRoot,
14
- supportsWindow,
15
- } from '@picked/client'
16
-
17
- interface Props {
18
- /** The resolved html-asset field value (for example `content.body`). */
19
- html: unknown
20
- }
21
-
22
- const { html }: Props = $props()
23
-
24
- const value = $derived(isHtmlAssetValue(html) ? html : null)
25
- const markup = $derived(value?.content ?? '')
26
- const serverMarkup = $derived(
27
- supportsWindow() ? '' : `<template shadowrootmode="open">${markup}</template>`,
28
- )
29
-
30
- let host = $state<HTMLDivElement>()
31
- let seeded = false
32
-
33
- $effect(() => {
34
- if (!supportsShadowRoot() || !host) return
35
-
36
- const existingShadow = host.shadowRoot
37
- const isFirstRun = !seeded
38
- seeded = true
39
-
40
- if (existingShadow && isFirstRun) {
41
- if (markup) void rehydrateScripts(existingShadow)
42
- return
43
- }
44
-
45
- const shadow = existingShadow ?? host.attachShadow({ mode: 'open' })
46
- shadow.innerHTML = markup
47
- if (markup) void rehydrateScripts(shadow)
48
- })
49
- </script>
50
-
51
- <!-- eslint-disable-next-line svelte/no-at-html-tags -- markup is a trusted, Picked-transformed html-asset field, not arbitrary user input -->
52
- <div bind:this={host}>{@html serverMarkup}</div>
@@ -1,29 +0,0 @@
1
- import type { CreateClientOptions, Picked } from '@picked/client';
2
- import { type PickedSnapshot } from '@picked/client/server';
3
- type SetPickedContextParams = {
4
- client: Picked;
5
- snapshot?: PickedSnapshot;
6
- } | {
7
- options: CreateClientOptions;
8
- snapshot?: PickedSnapshot;
9
- };
10
- /**
11
- * Provides a Picked client to descendant components through Svelte context, starting it in the browser.
12
- *
13
- * Call this once at the top of a component's `<script>` so `setContext` and `onMount` run during
14
- * component initialisation. Pass `options` to create the client and synchronously hydrate it from an
15
- * optional SSR snapshot (a `versionId` mismatch is tolerated; the client reconciles via `start()`),
16
- * or pass an existing `client` (such as the app's single global client) to render experiences
17
- * against it — supply `snapshot` alongside `client` to SSR-seed that shared client rather than
18
- * creating a second one. In the browser the client is started from `onMount`; `start()` is
19
- * idempotent, so a client that was already started is left untouched.
20
- *
21
- * @param {SetPickedContextParams} params - `{ client, snapshot? }` or `{ options, snapshot? }`.
22
- * @returns {Picked} The client placed into context.
23
- * @example
24
- * setPickedContext({ options })
25
- * @example
26
- * setPickedContext({ client: globalClient, snapshot })
27
- */
28
- export declare function setPickedContext(params: SetPickedContextParams): Picked;
29
- export {};
@@ -1 +0,0 @@
1
- import{CLIENT_CONTEXT_KEY as e}from"../context.js";import{onMount as t,setContext as n}from"svelte";import{createClient as r,supportsWindow as i}from"@picked/client";import{registerProjectConfig as a}from"@picked/client/server";function o(e,t){let n=e.session.store.getState().id;e.seededVersionId=t.versionId,a(e,t.projectConfig,{isPreview:!1,sessionId:n}),t.content.forEach(t=>e.registerContent(t)),e.conditionResults.seed(t.conditionResults)}function s(e,t){let n=r(e);return t&&o(n,t),n}function c(r){let a;return`client`in r?(r.snapshot&&o(r.client,r.snapshot),a=r.client):a=s(r.options,r.snapshot),n(e,a),t(()=>{i()&&a.start()}),a}export{c as setPickedContext};
@@ -1,30 +0,0 @@
1
- <script lang="ts">
2
- // Test-only harness. `createForm` registers option callbacks with `$effect`,
3
- // which requires a real component instance — mounting this is how the callback
4
- // lifecycle (registration on mount, teardown on unmount) gets exercised.
5
- import { untrack } from 'svelte'
6
- import type { Store } from 'effector'
7
- import { createForm, type FormCallbackOptions } from '../create-form.svelte'
8
-
9
- interface HarnessProps {
10
- formId: string
11
- title: Store<string>
12
- fieldKeys: Store<string[]>
13
- options?: FormCallbackOptions
14
- imperativeCallback?: () => void
15
- }
16
-
17
- const { formId, title, fieldKeys, options, imperativeCallback }: HarnessProps = $props()
18
-
19
- // Props are read once, at init, on purpose: the harness is mounted with fixed
20
- // props to exercise registration and teardown, and `createForm` itself is an
21
- // init-time call. `untrack` states that intent rather than suppressing the
22
- // state_referenced_locally warning.
23
- untrack(() => {
24
- const instance = createForm(formId, title, fieldKeys, options)
25
-
26
- if (imperativeCallback) {
27
- instance.form.onSuccess(imperativeCallback)
28
- }
29
- })
30
- </script>
@@ -1 +0,0 @@
1
- import{getExperience as e,getPicked as t}from"../hooks/client.js";import{createForm as n}from"@picked/client/form";import*as r from"svelte/internal/client";function i(i,a,o,s){let c=n({client:t(),experienceInstance:e()},i,a,o);if(s?.onBeforeSubmit){let e=s.onBeforeSubmit;r.user_effect(()=>c.form.onBeforeSubmit(e))}if(s?.onSuccess){let e=s.onSuccess;r.user_effect(()=>c.form.onSuccess(e))}if(s?.onError){let e=s.onError;r.user_effect(()=>c.form.onError(e))}return{...c,form:{...c.form,props:{...c.form.props,onsubmit:e=>c.form.props.onsubmit(e)},onBeforeSubmit:e=>{r.user_effect(()=>c.form.onBeforeSubmit(e))},onSuccess:e=>{r.user_effect(()=>c.form.onSuccess(e))},onError:e=>{r.user_effect(()=>c.form.onError(e))}}}}export{i as createForm};
@@ -1,40 +0,0 @@
1
- /** @file Svelte wrapper for createForm — lifecycle management and plain-function event handlers. */
2
- import type { Store } from 'effector';
3
- import { type FormInstance as CoreFormInstance, type ErrorCallback, type FormCallbackOptions, type SubmitCallback, type SubmitEventWithCurrentTarget, type SuccessCallback } from '@picked/client/form';
4
- export type { FormField, FormCallbackOptions } from '@picked/client/form';
5
- /**
6
- * Svelte FormInstance — identical to core but callback registration returns void
7
- * (cleanup is handled automatically via $effect, not by the consumer).
8
- */
9
- export interface FormInstance<TFieldKeys extends string = string> extends Omit<CoreFormInstance<TFieldKeys>, 'form'> {
10
- form: Omit<CoreFormInstance<TFieldKeys>['form'], 'onBeforeSubmit' | 'onSuccess' | 'onError' | 'props'> & {
11
- props: {
12
- onsubmit: (e: SubmitEventWithCurrentTarget) => void;
13
- };
14
- onBeforeSubmit: (callback: SubmitCallback<TFieldKeys>) => void;
15
- onSuccess: (callback: SuccessCallback<TFieldKeys>) => void;
16
- onError: (callback: ErrorCallback) => void;
17
- };
18
- }
19
- /**
20
- * Creates a form instance with Svelte lifecycle management.
21
- *
22
- * Wraps the framework-agnostic createForm from `@picked/client/form`:
23
- * - Injects client and experienceInstance from Svelte context.
24
- * - Wraps `form.props.onsubmit` as a plain function (not an Effector EventCallable).
25
- * - Auto-wires callback cleanup via `$effect` so consumers don't need to manage lifecycle.
26
- *
27
- * Used internally by setStepContext — access via getStep() in components.
28
- *
29
- * @param {string} formId - Unique identifier for this form instance.
30
- * @param {Store<string>} title - Reactive store holding the form/step title.
31
- * @param {Store<string[]>} fieldKeys - Reactive store of field keys that belong to this form.
32
- * @param {FormCallbackOptions} [options] - Submit callback slots, registered once for the component's lifetime.
33
- * @returns {FormInstance} A form instance with reactive field stores, submission handlers, and callback registration.
34
- * @example
35
- * ```ts
36
- * const { form, fields } = createForm('lead-capture', $title, $fieldKeys, { onSuccess })
37
- * ```
38
- * @design-parity Mirrors `useForm`'s options argument in `@picked/react`.
39
- */
40
- export declare function createForm(formId: string, title: Store<string>, fieldKeys: Store<string[]>, options?: FormCallbackOptions): FormInstance;
@@ -1 +0,0 @@
1
- export * from './create-form.js';
@@ -1,30 +0,0 @@
1
- /** @file Legacy getForm() helper — imperative form submission with callback-based lifecycle. */
2
- import type { ValidationError } from '@picked/client';
3
- interface GetFormOptions {
4
- id: string;
5
- title: string;
6
- onSuccess?: () => void | Promise<void>;
7
- onError?: (errors: ValidationError[]) => void | Promise<void>;
8
- }
9
- type SubmitEventWithCurrentTarget = SubmitEvent & {
10
- currentTarget: EventTarget & HTMLFormElement;
11
- };
12
- /**
13
- * Creates a form submission handler with imperative callback lifecycle.
14
- *
15
- * Wires an Effector pipeline that builds responses from FormData and commits them.
16
- * Unhandled commit failures are surfaced via the onError callback.
17
- *
18
- * @param {GetFormOptions} options - Form configuration including callbacks.
19
- * @returns {object} An object with the form submit event to spread onto a form element.
20
- * @example
21
- * ```ts
22
- * const { form } = getForm({ id: 'lead', title: 'Lead Capture', onSuccess: () => {} })
23
- * ```
24
- */
25
- export declare function getForm({ id: formId, title, onError, onSuccess }: GetFormOptions): {
26
- form: {
27
- onsubmit: import("effector").EventCallable<SubmitEventWithCurrentTarget>;
28
- };
29
- };
30
- export {};
@@ -1 +0,0 @@
1
- import{getExperience as e,getPicked as t}from"../hooks/client.js";import{getStep as n}from"../hooks/step.js";import"../hooks/index.js";import{buildResponsesFromFormData as r}from"@picked/client/form";import{attach as i,createEffect as a,createEvent as o,sample as s,split as c}from"effector";function l({id:l,title:u,onError:d,onSuccess:f}){let p=t(),m=n(),h=e(),{currentStepStore:g}=h,_=o(),v=a(e=>p.responses.commit(e)),y=i({source:{step:g},effect:a(({step:e})=>{p.eventBus({type:`form_submit_success`,form:{id:l,title:u},experience:h,step:e??void 0}),f?.()})}),b=i({source:{step:g},mapParams:(e,t)=>({step:t.step,errors:e.errors}),effect:a(({step:e,errors:t})=>{p.eventBus({type:`form_submit_error`,form:{id:l,title:u},exception:{reason:t},experience:h,step:e??void 0}),t.forEach(t=>{p.eventBus({type:`field_validation_error`,exception:{reason:[t]},experience:h,step:e??void 0})}),d?.(t)})});return s({clock:_,source:{step:g},fn:({step:e})=>({formId:l,title:u,step:e}),target:a(({formId:e,title:t,step:n})=>{p.eventBus({type:`form_submit`,form:{id:e,title:t},experience:h,step:n??void 0})})}),s({clock:_,source:{fields:p.fields.listStore,stepFields:m.fields,step:g},fn:({stepFields:e},t)=>(t.preventDefault(),r(e,new FormData(t.currentTarget))),target:v}),c({source:v.doneData,match:{hasErrors:({errors:e})=>e.length>0},cases:{hasErrors:b,__:y}}),s({clock:v.fail,fn:({error:e})=>({errors:[{fieldKey:``,userMessage:`An unexpected error occurred`,systemMessage:e instanceof Error?e.message:String(e),value:null}]}),target:b}),{form:{onsubmit:_}}}export{l as getForm};
@@ -1,40 +0,0 @@
1
- /** @file Svelte hooks for consuming registered actions from the Picked client. */
2
- import { type Action, type ActionKeys, type ExperienceInstance } from '@picked/client';
3
- import { type Store } from 'effector';
4
- /**
5
- * Returns the reactive evokable action store for the given action key.
6
- *
7
- * When `options.experience` is provided, the wrapped call passes that
8
- * experience as the action's context, so manually-invoked handlers can
9
- * behave as if they were triggered by that experience — for example to
10
- * call `context.experience.close()` after a submit.
11
- *
12
- * @param {ActionKeys} actionKey - Action key from the workspace schema.
13
- * @param {object} [options] - Optional invocation overrides.
14
- * @param {ExperienceInstance} options.experience - Experience to bind as the action's context.
15
- * @returns {Store<() => ReturnType<Action>>} A store containing the callable action function or undefined.
16
- * @example
17
- * ```ts
18
- * const actionStore = getAction('log-event')
19
- * const bound = getAction('submit-form', { experience: getExperience() })
20
- * ```
21
- */
22
- export declare function getAction(actionKey: ActionKeys, options?: {
23
- experience: ExperienceInstance;
24
- }): Store<() => ReturnType<Action>>;
25
- /**
26
- * Returns a reactive store holding the latest result of invoking the keyed action.
27
- * Re-evaluates automatically when the underlying action store updates.
28
- *
29
- * @param {ActionKeys} actionKey - Action key from the workspace schema.
30
- * @param {object} [options] - Optional invocation overrides.
31
- * @param {ExperienceInstance} options.experience - Experience to bind as the action's context.
32
- * @returns {Store<string | string[] | boolean | void | undefined>} A store containing the latest action return value.
33
- * @example
34
- * ```ts
35
- * const result = getActionResult('is-logged-in')
36
- * ```
37
- */
38
- export declare function getActionResult(actionKey: ActionKeys, options?: {
39
- experience: ExperienceInstance;
40
- }): import("effector").StoreWritable<void | string | boolean | string[] | undefined>;
@@ -1 +0,0 @@
1
- import{getPicked as e}from"./client.js";import"@picked/client";import{attach as t,createEffect as n,createEvent as r,createStore as i,sample as a}from"effector";function o(t,n){return e().actions.getEvokableAction(t,n)}function s(e,s){let c=o(e,s),l=i(void 0,{skipVoid:!1}),u=r(),d=t({source:c,mapParams:(e,t)=>t,effect:n(async e=>{if(e)return await e()})});return a({clock:u,target:d}),a({clock:d.doneData,target:l}),u(),a({clock:c,target:u}),l}export{o as getAction,s as getActionResult};
@@ -1,18 +0,0 @@
1
- /**
2
- * @file Svelte lookup helper for the Picked content registry. Mirrors `getField(key)`
3
- * — returns the registry store, leaving subscription to the consumer.
4
- */
5
- import type { Store } from 'effector';
6
- import { type TypedContent } from '@picked/client';
7
- /**
8
- * Returns the registry store for a content id.
9
- *
10
- * @template TData
11
- * @param {string} id - The content record id to look up.
12
- * @returns {Store<TypedContent<TData> | null>} The registry store; `null` until content is registered.
13
- * @example
14
- * ```svelte
15
- * const banner = getContent<WelcomePage>('lc_banner')
16
- * ```
17
- */
18
- export declare function getContent<TData extends Record<string, unknown> = Record<string, unknown>>(id: string): Store<TypedContent<TData> | null>;
@@ -1 +0,0 @@
1
- import{getPicked as e}from"./client.js";import{toTypedContentStore as t}from"@picked/client";function n(n){let r=e();return t(r.contents.getById(n))}export{n as getContent};
@@ -1,145 +0,0 @@
1
- import { type Store } from 'effector';
2
- interface QueryOptions {
3
- refetch?: boolean;
4
- staleTime?: number;
5
- retry?: number;
6
- retryDelay?: number;
7
- }
8
- export interface QueryResult<T> {
9
- data: Store<T | null>;
10
- error: Store<Error | null>;
11
- isLoading: Store<boolean>;
12
- refetch: () => Promise<T>;
13
- invalidate: () => void;
14
- }
15
- export type QueryFactory<Params, Results> = (params: Params, queryOptions?: QueryOptions) => QueryResult<Results>;
16
- /**
17
- * Effector-powered data fetching helper inspired by [SWR](https://www.npmjs.com/package/swr).
18
- *
19
- * It provides:
20
- * - Request de-duplication per key (in-flight promise reuse)
21
- * - Stale-while-revalidate caching with per-key timestamps
22
- * - Automatic retries with exponential backoff
23
- * - Fine-grained invalidation (per key, per namespace, or global)
24
- *
25
- * Behavior overview:
26
- * - Cache key: built from the `keyFn(params)` within a `namespace` to avoid collisions across domains.
27
- * - Staleness: when a record is older than `staleTime`, the next read will revalidate in the background.
28
- * - Deduplication: concurrent reads for the same key share the same promise.
29
- * - Retries: failures are retried up to `retry` times using exponential backoff starting at `retryDelay` ms.
30
- *
31
- * Type parameters:
32
- * - Params: the shape of parameters passed to the fetcher
33
- * - Results: the shape of the resolved fetcher result
34
- *
35
- * @param fetcher A function that performs the async request and returns a Promise of the result.
36
- * @param keyFn A function that builds a stable cache key from the provided params.
37
- * Use all inputs that affect the result to prevent collisions.
38
- * @param options Optional configuration applied to all queries created by this factory.
39
- * @param options.namespace Logical grouping for cache separation. Defaults to "default".
40
- * @param options.defaultStaleTime Default time in ms before data is considered stale. Defaults to 5 minutes.
41
- * @param options.defaultRetry Default max retry attempts on failure. Defaults to 3.
42
- * @param options.defaultRetryDelay Base delay in ms for retries; exponential backoff is applied. Defaults to 1000ms.
43
- *
44
- * @returns A QueryFactory(params, queryOptions) that produces QueryResult stores and controls for a specific key.
45
- *
46
- * Example: Basic usage with request de-duplication and caching
47
- * ```typescript
48
- * type User = { id: string; name: string }
49
- *
50
- * async function fetchUser({ id }: { id: string }): Promise<User> {
51
- * const res = await fetch(`/api/users/${id}`)
52
- * if (!res.ok) throw new Error('Failed to load user')
53
- * return res.json()
54
- * }
55
- *
56
- * const userQuery = createQuery(fetchUser, (p) => `user:${p.id}`, {
57
- * namespace: 'users',
58
- * defaultStaleTime: 60_000, // 1 minute
59
- * defaultRetry: 2,
60
- * defaultRetryDelay: 500,
61
- * })
62
- *
63
- * // Later in your code (each call uses the same key -> dedup + cache)
64
- * const { data, error, isLoading, refetch, invalidate } = userQuery({ id: '42' })
65
- *
66
- * // Subscribe reactively via Effector API:
67
- * const stopDataWatch = data.watch((value) => {
68
- * console.log('User data changed:', value)
69
- * })
70
- * const stopErrorWatch = error.watch((err) => {
71
- * if (err) console.error('User query error:', err)
72
- * })
73
- * const stopLoadingWatch = isLoading.watch((pending) => {
74
- * console.log('Loading:', pending)
75
- * })
76
- *
77
- * // Manually refetch (ignores staleness)
78
- * refetch()
79
- *
80
- * // Invalidate only this key (forces next read to refetch)
81
- * invalidate()
82
- *
83
- * // Clean up watchers when leaving scope
84
- * stopDataWatch()
85
- * stopErrorWatch()
86
- * stopLoadingWatch()
87
- * ```
88
- *
89
- * Example: Per-call overrides (staleTime, retry)
90
- * ```typescript
91
- * const fastUserQuery = createQuery(fetchUser, (p) => `user:${p.id}`, {
92
- * namespace: 'users',
93
- * defaultStaleTime: 5 * 60_000, // 5 minutes
94
- * })
95
- *
96
- * // For this call, we want fresher data and fewer retries:
97
- * const fast = fastUserQuery({ id: '42' }, { staleTime: 5_000, retry: 1 })
98
- *
99
- * // For another call, rely on defaults:
100
- * const normal = fastUserQuery({ id: '42' })
101
- * ```
102
- *
103
- * Example: Using multiple params in the key
104
- * ```typescript
105
- * type ListParams = { page: number; q?: string }
106
- * const listQuery = createQuery(
107
- * async (p: ListParams) => {
108
- * const u = new URL('/api/items', window.location.origin)
109
- * u.searchParams.set('page', String(p.page))
110
- * if (p.q) u.searchParams.set('q', p.q)
111
- * const r = await fetch(u)
112
- * if (!r.ok) throw new Error('Failed')
113
- * return r.json() as Promise<{ items: unknown[]; total: number }>
114
- * },
115
- * // Include all inputs that affect response:
116
- * (p) => `items:page=${p.page}:q=${p.q ?? ''}`,
117
- * { namespace: 'items' },
118
- * )
119
- * ```
120
- */
121
- export declare function createQuery<Params, Results>(fetcher: (params: Params) => Promise<Results>, keyFn: (params: Params) => string, options?: {
122
- namespace?: string;
123
- defaultStaleTime?: number;
124
- defaultRetry?: number;
125
- defaultRetryDelay?: number;
126
- }): QueryFactory<Params, Results>;
127
- export declare const queryCache: {
128
- invalidate: (namespace: string, key?: string) => void;
129
- clear: () => void;
130
- };
131
- export declare const queryPresets: {
132
- realtime: {
133
- defaultStaleTime: number;
134
- defaultRetry: number;
135
- };
136
- standard: {
137
- defaultStaleTime: number;
138
- defaultRetry: number;
139
- };
140
- static: {
141
- defaultStaleTime: number;
142
- defaultRetry: number;
143
- };
144
- };
145
- export {};
@@ -1 +0,0 @@
1
- import{createEffect as e,createStore as t,sample as n}from"effector";var r=new Map;function i(e){return r.has(e)||r.set(e,new Map),r.get(e)}function a(e,t){let n=i(e).get(t);n&&(n.promise=null,n.timestamp=0)}function o(e){i(e).forEach(e=>{e.promise=null,e.timestamp=0})}function s(){r.clear()}function c(r,o,s={}){let{namespace:c=`default`,defaultStaleTime:u=3e5,defaultRetry:d=3,defaultRetryDelay:f=1e3}=s,p=i(c),m=e(async e=>{let{key:t,params:n,options:i}=e,a=p.get(t)?.promise,o=p.get(t),s=i.refetch||!a||o&&Date.now()-o.timestamp>(i.staleTime??o.staleTime);if(!a||s){a=l(()=>r(n),i.retry??d,i.retryDelay??f);let e=p.get(t);e&&(e.promise=a,e.timestamp=Date.now(),e.staleTime=i.staleTime??u)}return{key:t,promise:a,result:await a}});return(r,i={})=>{let s=o(r),l=p.get(s);l||(l={promise:null,data:t(null),error:t(null),isLoading:t(!1),timestamp:0,staleTime:i.staleTime??u},p.set(s,l));let d=e(e=>e);return n({source:m.doneData,filter:e=>e.key===s,fn:e=>e.promise,target:d}),l.isLoading.on(m.pending,(e,t)=>t),l.isLoading.on(d.pending,(e,t)=>t),l.data.on(d.doneData,(e,t)=>t),l.error.on(d.doneData,()=>null),l.error.on(d.failData,(e,t)=>t),l.error.on(m.failData,(e,t)=>t),(!l.promise||Date.now()-l.timestamp>l.staleTime)&&m({key:s,params:r,options:i}),{data:l.data,error:l.error,isLoading:l.isLoading,refetch:()=>m({key:s,params:r,options:{...i,refetch:!0}}).then(({result:e})=>e),invalidate:()=>a(c,s)}}}async function l(e,t,n){let r;for(let i=0;i<=t;i++)try{return await e()}catch(e){r=e instanceof Error?e:Error(String(e)),i<t&&await new Promise(e=>{setTimeout(e,n*2**i)})}throw r}var u={invalidate:(e,t)=>{t?a(e,t):o(e)},clear:()=>s()},d={realtime:{defaultStaleTime:5e3,defaultRetry:1},standard:{defaultStaleTime:3e5,defaultRetry:3},static:{defaultStaleTime:36e5,defaultRetry:2}};export{c as createQuery,u as queryCache,d as queryPresets};
@@ -1,2 +0,0 @@
1
- import type { AnalyticsProductList } from '@picked/analytics';
2
- export declare const getTrackRecommendationPresentEvent: () => import("effector").Effect<AnalyticsProductList, void, Error>;
@@ -1 +0,0 @@
1
- import{getExperience as e,getPicked as t}from"./client.js";import{attach as n}from"effector";import{trackRecommendationPresentEvent as r}from"@picked/analytics";var i=()=>{let{session:i,projectId:a}=t(),o=e();return n({source:{config:o.configStore,step:o.currentStepStore,sessionSnapshot:i.store},async effect({config:e,step:t,sessionSnapshot:n},i){if(!t)throw Error(`Cannot track recommendation present event: missing experience step.`);return r({projectId:a,experience:{id:o.experienceId,title:e.name},sessionId:n.id,identifiers:n.identifiers,isUser:n.isUser,step:t,productList:i})}})};export{i as getTrackRecommendationPresentEvent};
@@ -1,47 +0,0 @@
1
- /**
2
- * @file Svelte hooks for accessing feature flag evaluation from the Picked client.
3
- */
4
- import type { Store } from 'effector';
5
- import type { FeatureKeys, FeatureResult, FeatureValueFor } from '@picked/client';
6
- type FeatureBucketValue = boolean | string | undefined;
7
- /**
8
- * Returns the reactive store wrapping a feature in an evokable function.
9
- *
10
- * @param {FeatureKeys} featureName - Feature key from the workspace schema.
11
- * @returns {Store<() => Promise<FeatureBucketValue>>} The evokable-feature store.
12
- * @example
13
- * const $evokable = getFeature('winter-sale')
14
- */
15
- export declare function getFeature(featureName: FeatureKeys): Store<() => Promise<FeatureBucketValue>>;
16
- /**
17
- * Returns a store that resolves to a feature's evaluated bucket result.
18
- *
19
- * The evaluation wiring belongs to the client, which builds it once per feature and
20
- * resolves it once, so repeated calls share one store instead of growing the graph.
21
- *
22
- * The key type is inferred from the argument, so a workspace-known text feature narrows
23
- * its `bucket` to that feature's declared arms.
24
- *
25
- * @template K
26
- * @param {K} featureName - Feature key from the workspace schema.
27
- * @returns {Store<FeatureResult<FeatureValueFor<K>> | undefined>} A store holding the resolved bucket result, or undefined until resolved.
28
- * @example
29
- * const $result = getFeatureResult('winter-sale')
30
- */
31
- export declare function getFeatureResult<K extends FeatureKeys>(featureName: K): Store<FeatureResult<FeatureValueFor<K>> | undefined>;
32
- /**
33
- * Returns a store holding a feature's admin `enabled` flag.
34
- *
35
- * Unlike {@link getFeatureResult}, this reads the static config flag directly and does not
36
- * trigger bucket resolution — so a disabled feature (`enabled: false`) can be told apart
37
- * from an enabled feature whose session simply was not allocated. Resolves to `undefined`
38
- * when the feature is unregistered or carries no `enabled` metadata (for example,
39
- * manually-registered features).
40
- *
41
- * @param {FeatureKeys} featureName - Feature key from the workspace schema.
42
- * @returns {Store<boolean | undefined>} A store holding the feature's `enabled` flag, or undefined when unknown.
43
- * @example
44
- * const $enabled = getFeatureEnabled('winter-sale')
45
- */
46
- export declare function getFeatureEnabled(featureName: FeatureKeys): Store<boolean | undefined>;
47
- export {};
@@ -1 +0,0 @@
1
- import{getPicked as e}from"./client.js";function t(t){return e().features.getEvokableFeature(t)}function n(t){return e().features.getFeatureResult(t)}function r(t){return e().features.getById(t).map(e=>e?.enabled,{skipVoid:!1})}export{t as getFeature,r as getFeatureEnabled,n as getFeatureResult};
@@ -1,3 +0,0 @@
1
- import { type Predicate } from '@picked/client';
2
- export declare function getPredicate(predicateName: string): import("effector").Store<() => ReturnType<Predicate>>;
3
- export declare function getPredicateResult(predicateName: string): import("effector").StoreWritable<string | boolean | string[] | undefined>;
@@ -1 +0,0 @@
1
- import{getPicked as e}from"./client.js";import"@picked/client";import{attach as t,createEffect as n,createEvent as r,createStore as i,sample as a}from"effector";function o(t){return e().predicates.getEvokablePredicate(t)}function s(e){let s=o(e),c=i(void 0,{skipVoid:!1}),l=r(),u=t({source:s,mapParams:(e,t)=>t,effect:n(async e=>{if(e)return await e()})});return a({clock:l,target:u}),a({clock:u.doneData,target:c}),l(),a({clock:s,target:l}),c}export{o as getPredicate,s as getPredicateResult};