@picked/svelte 0.0.1-dev.1774244905386 → 0.0.1-dev.1774912386475

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.
@@ -0,0 +1 @@
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){let s=n({client:t(),experienceInstance:e()},i,a,o);return{...s,form:{...s.form,onBeforeSubmit:e=>{r.user_effect(()=>s.form.onBeforeSubmit(e))},onSuccess:e=>{r.user_effect(()=>s.form.onSuccess(e))},onError:e=>{r.user_effect(()=>s.form.onError(e))}}}}export{i as createForm};
@@ -0,0 +1,24 @@
1
+ import { Store } from 'effector';
2
+ import { FormInstance as CoreFormInstance, ErrorCallback, SubmitCallback, SuccessCallback } from '@picked/client/form';
3
+ export type { FormField } from '@picked/client/form';
4
+ /**
5
+ * Svelte FormInstance — identical to core but callback registration returns void
6
+ * (cleanup is handled automatically via $effect, not by the consumer).
7
+ */
8
+ export interface FormInstance<TFieldIds extends string = string> extends Omit<CoreFormInstance<TFieldIds>, 'form'> {
9
+ form: Omit<CoreFormInstance<TFieldIds>['form'], 'onBeforeSubmit' | 'onSuccess' | 'onError'> & {
10
+ onBeforeSubmit: (callback: SubmitCallback<TFieldIds>) => void;
11
+ onSuccess: (callback: SuccessCallback<TFieldIds>) => void;
12
+ onError: (callback: ErrorCallback) => void;
13
+ };
14
+ }
15
+ /**
16
+ * Creates a form instance with Svelte lifecycle management.
17
+ *
18
+ * Wraps the framework-agnostic createForm from @picked/client/form:
19
+ * - Injects client and experienceInstance from Svelte context
20
+ * - Auto-wires callback cleanup via $effect so consumers don't need to manage lifecycle
21
+ *
22
+ * Used internally by setStepContext — access via getStep() in components.
23
+ */
24
+ export declare function createForm(formId: string, title: Store<string>, fieldIds: Store<string[]>): FormInstance;
@@ -0,0 +1 @@
1
+ export * from './create-form.js';
@@ -0,0 +1,16 @@
1
+ import { ValidationError } from '@picked/client';
2
+ interface GetFormOptions {
3
+ id: string;
4
+ title: string;
5
+ onSuccess?: () => void | Promise<void>;
6
+ onError?: (errors: ValidationError[]) => void | Promise<void>;
7
+ }
8
+ type SubmitEventWithCurrentTarget = SubmitEvent & {
9
+ currentTarget: EventTarget & HTMLFormElement;
10
+ };
11
+ export declare function getForm({ id: formId, title, onError, onSuccess }: GetFormOptions): {
12
+ form: {
13
+ onsubmit: import('effector').EventCallable<SubmitEventWithCurrentTarget>;
14
+ };
15
+ };
16
+ export {};
@@ -0,0 +1 @@
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}}),{form:{onsubmit:_}}}export{l as getForm};
@@ -1,25 +1,2 @@
1
- import { ValidationError } from '@picked/client';
2
- interface GetFormOptions {
3
- id: string;
4
- title: string;
5
- onSuccess?: () => void | Promise<void>;
6
- onError?: (errors: ValidationError[]) => void | Promise<void>;
7
- }
8
- type SubmitEventWithCurrentTarget = SubmitEvent & {
9
- currentTarget: EventTarget & HTMLFormElement;
10
- };
11
- /**
12
- *
13
- * @param root0
14
- * @param root0.id
15
- * @param root0.title
16
- * @param root0.onError
17
- * @param root0.onSuccess
18
- * @example
19
- */
20
- export declare function getForm({ id: formId, title, onError, onSuccess }: GetFormOptions): {
21
- form: {
22
- onsubmit: import('effector').EventCallable<SubmitEventWithCurrentTarget>;
23
- };
24
- };
25
- export {};
1
+ export type { FormField } from '@picked/client/form';
2
+ export { getForm } from './get-form';
@@ -1 +1 @@
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{attach as r,createEffect as i,createEvent as a,sample as o,split as s}from"effector";function c({id:c,title:l,onError:u,onSuccess:d}){let f=t(),p=n(),m=e(),{currentStepStore:h}=m,g=a(),_=i(e=>f.responses.commit(e)),v=r({source:{step:h},effect:i(async({step:e})=>{f.eventBus({type:`form_submit_success`,form:{id:c,title:l},experience:m,step:e??void 0}),await d?.()})}),y=r({source:{step:h},mapParams:(e,t)=>({step:t.step,errors:e.errors}),effect:i(async({step:e,errors:t})=>{f.eventBus({type:`form_submit_error`,form:{id:c,title:l},exception:{reason:t},experience:m,step:e??void 0}),t.forEach(t=>{f.eventBus({type:`field_validation_error`,exception:{reason:[t]},experience:m,step:e??void 0})}),await u?.(t)})});return o({clock:g,source:{step:h},fn:({step:e})=>({formId:c,title:l,step:e}),target:i(({formId:e,title:t,step:n})=>{f.eventBus({type:`form_submit`,form:{id:e,title:t},experience:m,step:n??void 0})})}),o({clock:g,source:{fields:f.fields.listStore,stepFields:p.fields,step:h},fn:({stepFields:e},t)=>{t.preventDefault();let n=new FormData(t.currentTarget),r=Array.from(n.entries()),i={data:{},push(e){let t=e.questionId,n=this.data[t];n&&Array.isArray(n)&&Array.isArray(e.value)?Array.isArray(n)&&Array.isArray(e.value)&&(typeof n[0]==`string`?this.data[t]=[...n,...e.value].map(String):typeof n[0]==`number`?this.data[t]=[...n,...e.value].map(Number):typeof n[0]==`boolean`?this.data[t]=[...n,...e.value].map(e=>!!e):this.data[t]=e.value):this.data[t]=e.value}};return e.forEach(e=>{let t=r.filter(([t])=>t===e.key||t===e.id);t.length===0&&(t=[[e.id,``]]),t.forEach(([,t])=>{let n=e.id;if(t===``){i.push({questionId:n,value:null});return}switch(e.type){case`text`:i.push({questionId:n,value:e.multiple?[String(t)]:String(t)});break;case`number`:i.push({questionId:n,value:e.multiple?[Number(t)]:Number(t)});break;case`boolean`:i.push({questionId:n,value:e.multiple?[t===`true`]:t===`true`});break;case`object`:break}})}),i.data},target:_}),s({source:_.doneData,match:{hasErrors:({errors:e})=>e.length>0},cases:{hasErrors:y,__:v}}),{form:{onsubmit:g}}}export{c as getForm};
1
+ import{getForm as e}from"./get-form.js";export{e as getForm};
@@ -1,3 +1,4 @@
1
+ /** @file Public re-exports for Svelte hook utilities. */
1
2
  export { getPicked, getExperience } from './client';
2
3
  export { getPredicate, getPredicateResult } from './predicate';
3
4
  export { getFeature, getFeatureResult } from './feature';
@@ -1,13 +1,24 @@
1
1
  import { Store } from 'effector';
2
- import { ExperienceStep, Field, Response } from '@picked/client';
3
- type FieldWithValue = Field & {
4
- value: Response | undefined;
5
- };
6
- export interface StepContext {
2
+ import { ExperienceStep } from '@picked/client';
3
+ import { FormInstance, FormField } from '../form/create-form.svelte';
4
+ export interface StepContext extends FormInstance {
7
5
  step: Store<ExperienceStep>;
8
- fields: Store<FieldWithValue[]>;
6
+ /** Directly accessible fields with current response values — usable without a form. */
7
+ fields: Store<FormField[]>;
8
+ isActive: Store<boolean>;
9
+ /** @deprecated Use `isActive` instead. */
9
10
  isActiveStep: Store<boolean>;
10
11
  }
11
- export declare function getStep(): StepContext;
12
+ /**
13
+ * Creates and sets step context in the Svelte context tree.
14
+ *
15
+ * @param stepId - The step identifier.
16
+ * @example setStepContext('step-1')
17
+ */
12
18
  export declare function setStepContext(stepId: string): StepContext;
13
- export {};
19
+ /**
20
+ * Retrieves the step context from the Svelte context tree.
21
+ *
22
+ * @example getStep()
23
+ */
24
+ export declare function getStep(): StepContext;
@@ -1 +1 @@
1
- import{STEP_CONTEXT_KEY as e}from"../context.js";import{getPicked as t}from"./client.js";import{getStepFields as n}from"../utils/get-step-fields.js";import{getStepRouter as r}from"../router/context.js";import{attach as i,combine as a,createEffect as o,createStore as s,sample as c}from"effector";import{getContext as l,setContext as u}from"svelte";function d(){return l(e)}function f(l){let d=t(),{activeStep:f}=r(),p=f.map(e=>e?.id===l),m=d.steps.listStore.map(e=>{let t=e.find(e=>(e.key??e.id)===l);if(!t)throw Error(`Step with id "${l}" not found in the step registry.`);return t}),h=s([]),g=a({fields:h,responses:d.responses.listStore},({fields:e,responses:t})=>e.map(e=>{let n=t.find(t=>t.fieldKey===e.key||t.fieldId===e.id)?.value;return{...e,value:n}})),_=i({source:a({step:m,fields:d.fields.listStore}),effect:o(async({step:e,fields:t})=>await n(d,e.fieldKeys&&e.fieldKeys.length>0?t.filter(t=>(e.fieldKeys??[]).includes(t.key)):t.filter(t=>(e.fieldIds??[]).includes(t.id))))});return c({source:{isActiveStep:p},filter:({isActiveStep:e})=>e,target:_}),c({clock:d.responses.listStore,source:{isActiveStep:p},filter:({isActiveStep:e})=>e,target:_}),c({source:_.doneData,target:h}),u(e,{step:m,fields:g,isActiveStep:p})}export{d as getStep,f as setStepContext};
1
+ import{STEP_CONTEXT_KEY as e}from"../context.js";import{getPicked as t}from"./client.js";import{getStepRouter as n}from"../router/context.js";import{getStepFields as r}from"@picked/client/form";import{attach as i,combine as a,createEffect as o,createStore as s,sample as c}from"effector";import{getContext as l,setContext as u}from"svelte";import{createForm as d}from"../form/create-form.svelte";function f(l){let f=t(),{activeStep:p}=n(),m=p.map(e=>e?.key===l),h=f.steps.listStore.map(e=>e.find(e=>e.key===l)??{id:l,key:l,name:``,fieldIds:[]}),g=s([]),_=i({source:a({step:h,fields:f.fields.listStore}),mapParams:(e,t)=>t,effect:o(async({step:e,fields:t})=>await r(f,t.filter(t=>e.fieldIds.includes(t.id)||e.fieldIds.includes(t.key))))});c({source:{isActiveStep:m},filter:({isActiveStep:e})=>e,target:_}),c({clock:f.responses.listStore,source:{isActiveStep:m},filter:({isActiveStep:e})=>e,target:_}),c({source:_.doneData,target:g});let v=g.map(e=>e.map(e=>e.id));return u(e,{step:h,isActive:m,isActiveStep:m,...d(l,h.map(e=>e.name),v)})}function p(){return l(e)}export{p as getStep,f as setStepContext};
@@ -7,7 +7,7 @@
7
7
  export let experienceInstance: ExperienceInstance
8
8
 
9
9
  const client = getPicked()
10
- const experienceLookup = client.experiences.get(experienceInstance.experienceId)
10
+ const experienceStore = client.experiences.get(experienceInstance.experienceId)
11
11
 
12
12
  const currentNode = experienceInstance.currentNodeStore
13
13
  const currentStep = experienceInstance.currentStepStore
@@ -17,11 +17,9 @@
17
17
  const isOpen = experienceInstance.isOpenStore
18
18
 
19
19
  $: totalNextStepNodes = $nextStepNodes.length
20
- $: experienceName = $experienceLookup?.name ?? experienceInstance.experienceId
20
+ $: experienceName = $experienceStore?.name ?? experienceInstance.experienceId
21
21
  $: currentNodeDisplay = $currentNode
22
- ? (('name' in $currentNode && $currentNode.name) ||
23
- ('stepKey' in $currentNode && $currentNode.stepKey) ||
24
- $currentNode.id)
22
+ ? (('stepKey' in $currentNode && $currentNode.stepKey) || $currentNode.id)
25
23
  : ''
26
24
  $: currentStepDisplay = $currentStep?.name ?? ''
27
25
  </script>
@@ -32,7 +30,7 @@
32
30
  <td>{currentNodeDisplay}</td>
33
31
  <td>{$currentNode?.type || ''}</td>
34
32
  <td>{currentStepDisplay}</td>
35
- <td>{$currentStep?.title || ''}</td>
33
+ <td>{$currentStep?.name || ''}</td>
36
34
  <td>{totalNextStepNodes}</td>
37
35
  <td>{$stepsToOrigin[0]} - {$stepsToOrigin[1]}</td>
38
36
  <td>{$stepsToLeaf[0]} - {$stepsToLeaf[1]}</td>
@@ -1 +1 @@
1
- import{adaptSvelteComponent as e}from"../../component.js";import{__vitePreload as t}from"../../_virtual/_vite/preload-helper.js";import{lazyComponent as n}from"@picked/client";import{createExperience as r,createExperiencePlugin as i}from"@picked/client/plugins/create-experience";var a=a=>{let o=r({id:`devtools`,name:`Picked Devtools`,condition:!1,initializeOpen:!1,targets:[{selector:`body`,placement:`append`}],component:e(n(()=>t(()=>import(`./DevToolsExperience.svelte`),[])))});return o.addStep({label:`Tools`}),[{name:`svelte-devtools`,setup:e=>{a?.enabled&&e.eventBus.watch(t=>{t.type===`ready`&&e.experiences.launch({key:o.key,options:{bypassCondition:!0}})})}},i({experiences:[o]})]};export{a as svelteDevtoolsPlugin};
1
+ import{adaptSvelteComponent as e}from"../../component.js";import{__vitePreload as t}from"../../_virtual/_vite/preload-helper.js";import{lazyComponent as n}from"@picked/client";import{createExperience as r,createExperiencePlugin as i}from"@picked/client/plugins/create-experience";var a=a=>{let o=r({id:`devtools`,key:`devtools`,name:`Picked Devtools`,condition:!1,initializeOpen:!1,targets:[{selector:`body`,placement:`append`}],component:e(n(()=>t(()=>import(`./DevToolsExperience.svelte`),[])))});return o.addStep({name:`Tools`}),[{name:`svelte-devtools`,setup:e=>{a?.enabled&&e.eventBus.watch(t=>{t.type===`ready`&&e.experiences.launch({key:o.key,options:{bypassCondition:!0}})})}},i({experiences:[o]})]};export{a as svelteDevtoolsPlugin};
@@ -14,9 +14,9 @@
14
14
  'experience' in event.payload && event.payload.experience
15
15
  ? event.payload.experience.experienceId
16
16
  : undefined
17
- const eventExpLookup = client.experiences.get(eventExpId ?? '')
17
+ const eventExperienceStore = client.experiences.get(eventExpId ?? '')
18
18
  $: eventExpName = eventExpId
19
- ? ($eventExpLookup?.name ?? eventExpId)
19
+ ? ($eventExperienceStore?.name ?? eventExpId)
20
20
  : '-'
21
21
 
22
22
  /**
@@ -73,19 +73,37 @@
73
73
  * ```
74
74
  */
75
75
  function getStepFields(step: unknown): PayloadField[] {
76
- if (!step || typeof step !== 'object') return []
76
+ if (!step || typeof step !== 'object'){
77
+ return []
78
+ }
79
+
77
80
  const fields: PayloadField[] = []
78
- if ('id' in step && step.id) fields.push({ label: 'Step ID', value: step.id })
81
+ if ('key' in step && step.key) {
82
+ fields.push({ label: 'Step Key', value: step.key })
83
+ }
84
+
79
85
  // eslint-disable-next-line sonarjs/deprecation -- backwards-compat fallback for label
80
86
  const stepName = ('name' in step && step.name) || ('label' in step && step.label)
81
- if (stepName) fields.push({ label: 'Step Name', value: stepName })
87
+ if (stepName) {
88
+ fields.push({ label: 'Step Name', value: stepName })
89
+ }
90
+
82
91
  return fields
83
92
  }
84
93
 
94
+ /** Scalar payload keys to extract and their display labels. JSON-serializable values are stringified. */
95
+ const SCALAR_KEYS: { key: string; label: string; serialize?: boolean }[] = [
96
+ { key: 'value', label: 'Value' },
97
+ { key: 'form', label: 'Form', serialize: true },
98
+ { key: 'feature', label: 'Feature', serialize: true },
99
+ { key: 'exception', label: 'Exception', serialize: true },
100
+ { key: 'version', label: 'Version' },
101
+ ]
102
+
85
103
  /**
86
104
  * Extracts scalar (non-nested) fields from an event bus payload.
87
105
  *
88
- * @param payload - The event bus payload to extract fields from.
106
+ * @param payload - The event bus payload to extract scalar fields from.
89
107
  * @example
90
108
  * ```typescript
91
109
  * getScalarFields({ type: 'step', value: 42 })
@@ -94,23 +112,22 @@
94
112
  */
95
113
  function getScalarFields(payload: EventBusPayload): PayloadField[] {
96
114
  const fields: PayloadField[] = []
97
- if ('value' in payload && payload.value !== undefined)
98
- fields.push({ label: 'Value', value: payload.value })
99
- if ('form' in payload && payload.form)
100
- fields.push({ label: 'Form', value: JSON.stringify(payload.form) })
101
- if ('feature' in payload && payload.feature)
102
- fields.push({ label: 'Feature', value: JSON.stringify(payload.feature) })
103
- if ('exception' in payload && payload.exception)
104
- fields.push({ label: 'Exception', value: JSON.stringify(payload.exception) })
105
- if ('version' in payload && payload.version)
106
- fields.push({ label: 'Version', value: payload.version })
115
+ const record = payload as Record<string, unknown>
116
+
117
+ for (const { key, label, serialize } of SCALAR_KEYS) {
118
+ const raw = record[key]
119
+ if (raw !== undefined) {
120
+ fields.push({ label, value: serialize ? JSON.stringify(raw) : raw })
121
+ }
122
+ }
123
+
107
124
  return fields
108
125
  }
109
126
 
110
127
  /**
111
- * Builds a complete list of display fields from an event bus payload.
128
+ * Builds a flat list of display fields from an event bus payload.
112
129
  *
113
- * @param payload - The event bus payload to extract all fields from.
130
+ * @param payload - The event bus payload to extract fields from.
114
131
  * @example
115
132
  * ```typescript
116
133
  * getPayloadFields({ type: 'session', id: 'sess-1' })
@@ -120,12 +137,19 @@
120
137
  function getPayloadFields(payload: EventBusPayload): PayloadField[] {
121
138
  const fields: PayloadField[] = [{ label: 'Type', value: payload.type }]
122
139
  fields.push(...getScalarFields(payload))
123
- if ('experience' in payload && payload.experience)
140
+
141
+ if ('experience' in payload && payload.experience) {
124
142
  fields.push(...getExperienceFields(payload.experience))
125
- if ('step' in payload && payload.step)
143
+ }
144
+
145
+ if ('step' in payload && payload.step) {
126
146
  fields.push(...getStepFields(payload.step))
127
- if ('id' in payload && payload.id && payload.type === 'session')
147
+ }
148
+
149
+ if ('id' in payload && payload.id && payload.type === 'session') {
128
150
  fields.push({ label: 'Session ID', value: payload.id })
151
+ }
152
+
129
153
  return fields
130
154
  }
131
155
 
@@ -12,7 +12,7 @@
12
12
  let selectedNode = null
13
13
  // eslint-disable-next-line @typescript-eslint/no-unused-vars, sonarjs/no-unused-collection -- reserved for future path highlighting
14
14
  let highlightedPath: string[][] = []
15
- let error = null
15
+ let error: string | null = null
16
16
  const loading = false
17
17
 
18
18
  let treeRenderingDone = false
@@ -138,7 +138,7 @@
138
138
  const getNodeLabel = (node: ExperienceNode): string => {
139
139
  if (node.type === 'origin') return 'Start'
140
140
  if (node.type === 'step')
141
- return node.name ?? node.stepKey ?? node.stepId ?? 'Unknown Step'
141
+ return node.name ?? 'Unknown Step'
142
142
  if (node.type === 'condition') {
143
143
  const conditionId = node.conditionId
144
144
  const conditionItem = conditionId ? conditionsMap.get(conditionId) : undefined
@@ -6,8 +6,8 @@
6
6
  export let historyEntry: HistoryEntry
7
7
 
8
8
  const client = getPicked()
9
- const experienceLookup = client.experiences.get(historyEntry.experienceId)
10
- $: experienceName = $experienceLookup?.name ?? historyEntry.experienceId
9
+ const experienceStore = client.experiences.get(historyEntry.experienceId)
10
+ $: experienceName = $experienceStore?.name ?? historyEntry.experienceId
11
11
  </script>
12
12
 
13
13
  <tr>
@@ -15,7 +15,8 @@
15
15
  // eslint-disable-next-line svelte/prefer-svelte-reactivity -- Set is reassigned for Svelte reactivity via `selectedOptions = selectedOptions`
16
16
  let selectedOptions: Set<PrimitiveFieldValue> = new Set()
17
17
 
18
- $: hasOptions = field?.options && field.options.length > 0
18
+ $: hasOptions = Array.isArray(field?.options) && field.options.length > 0
19
+ $: staticOptions = Array.isArray(field?.options) ? field.options : null
19
20
  $: currentValue = response?.value ?? null
20
21
 
21
22
  /**
@@ -159,14 +160,14 @@
159
160
  */
160
161
  async function saveEdit() {
161
162
  try {
162
- let newValue: unknown
163
+ let newValue: FieldValue
163
164
 
164
165
  if (hasOptions) {
165
166
  const values = Array.from(selectedOptions)
166
167
  if (field?.multiple) {
167
168
  newValue = values
168
169
  } else {
169
- newValue = values[0] ?? null
170
+ newValue = values.at(0) ?? null
170
171
  }
171
172
  } else {
172
173
  newValue = parseValue(editValue)
@@ -210,9 +211,9 @@
210
211
  <td>
211
212
  {#if isEditing}
212
213
  <Stack direction="vertical" gap="small">
213
- {#if hasOptions && field?.options}
214
+ {#if hasOptions && staticOptions}
214
215
  <Stack direction="vertical" gap="small">
215
- {#each field.options as option (option.id)}
216
+ {#each staticOptions as option (option.id)}
216
217
  <label class="option-label">
217
218
  {#if field.multiple}
218
219
  <input
@@ -1,24 +1,30 @@
1
1
  <script lang="ts">
2
+ /** @file Step component that registers a step with the router and renders its content. */
2
3
  import { type Component, type Snippet } from 'svelte'
3
4
  import { setStepContext } from '../hooks'
4
5
  import { getStepRouter } from './context'
5
6
 
6
7
  interface Props {
7
- id: string
8
+ /** Preferred prop: the step key used for registration and lookup. */
9
+ key?: string
10
+ /** @deprecated Use `key` instead. Accepted for backwards compatibility. */
11
+ id?: string
8
12
  component?: Component | Promise<Component> | Promise<{ default: Component }>
9
13
  children?: Snippet
10
14
  }
11
15
 
12
- const { id, component, children }: Props = $props()
16
+ const { key, id, component, children }: Props = $props()
17
+
18
+ const resolvedKey = key ?? id ?? ''
13
19
 
14
20
  const step = {
15
- id,
16
- key: id
21
+ id: resolvedKey,
22
+ key: resolvedKey,
17
23
  }
18
24
 
19
25
  const { registerStep, unregisterStep } = getStepRouter()
20
26
 
21
- setStepContext(id)
27
+ setStepContext(resolvedKey)
22
28
 
23
29
  $effect(() => {
24
30
  registerStep(step)
@@ -35,7 +35,7 @@
35
35
  // we just skip them.
36
36
  if (hasActiveStep) return
37
37
 
38
- const isMatchingStep = step.id === currentStepStore.getState()?.id
38
+ const isMatchingStep = step.key === currentStepStore.getState()?.key
39
39
 
40
40
  if (isMatchingStep) {
41
41
  setActiveStepEvent(step)
@@ -52,7 +52,7 @@
52
52
 
53
53
  sample({
54
54
  source: { steps: stepsStore, currentStep: currentStepStore },
55
- fn: ({ steps, currentStep }) => steps.find((s) => s.id === currentStep?.key) || null,
55
+ fn: ({ steps, currentStep }) => steps.find((s) => s.key === currentStep?.key) || null,
56
56
  target: setActiveStepEvent,
57
57
  })
58
58
 
@@ -1,6 +1,7 @@
1
1
  import { Store } from 'effector';
2
2
  export interface Step {
3
3
  id: string;
4
+ key: string;
4
5
  }
5
6
  interface ContextOptions {
6
7
  activeStep: Store<Step | null>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@picked/svelte",
3
- "version": "0.0.1-dev.1774244905386",
3
+ "version": "0.0.1-dev.1774912386475",
4
4
  "dependencies": {
5
5
  "d3": "^7.9.0"
6
6
  },
@@ -18,7 +18,7 @@
18
18
  "@vitest/coverage-v8": "^4.1.0",
19
19
  "effector": "^23.3.0",
20
20
  "fast-glob": "^3.3.3",
21
- "happy-dom": "^20.0.2",
21
+ "happy-dom": "^20.8.8",
22
22
  "size-limit": "^12.0.0",
23
23
  "svelte": "^5.46.4",
24
24
  "svelte-check": "^4.2.2",
@@ -88,7 +88,7 @@
88
88
  },
89
89
  "module": "./dist/index.js",
90
90
  "peerDependencies": {
91
- "@picked/client": "0.0.1-dev.1774244905386",
91
+ "@picked/client": "0.0.1-dev.1774912386475",
92
92
  "effector": "^23.3.0",
93
93
  "svelte": "^5.46.4"
94
94
  },
@@ -108,7 +108,7 @@
108
108
  "svelte-check": "svelte-check --tsconfig ./tsconfig.json",
109
109
  "svelte-check:report": "mkdir -p ./.reports && pnpm svelte-check --tsconfig ./tsconfig.json --output=machine > ./.reports/svelte-check.txt || [ -f './.reports/svelte-check.txt' ]",
110
110
  "test": "vitest run",
111
- "test:coverage": "vitest run --coverage",
111
+ "test:coverage": "../../scripts/vitest-coverage.sh",
112
112
  "test:packaged-types": "attw --pack",
113
113
  "test:watch": "vitest",
114
114
  "type-check": "tsgo -p . --noEmit"
@@ -1,2 +0,0 @@
1
- import { Field, Picked } from '@picked/client';
2
- export declare function getStepFields(client: Picked, fields: Field[]): Promise<Field[]>;
@@ -1 +0,0 @@
1
- import{evaluateRuleLogic as e}from"@picked/client";function t(e){return e.options?.some(e=>`condition`in e)??!1}function n(e){return e.some(e=>e.condition||e.conditionKey||t(e))}async function r(e,t){return t.conditionKey?e.conditions.getByKey(t.conditionKey).getState()?.logic??null:t.condition??null}async function i(i,a){return a.length===0||!n(a)?a:(await Promise.all(a.map(async n=>{let a=await r(i,n);if(!(!a||await e(i,a)))return null;if(!n.options||!t(n))return n;let o=(await Promise.all(n.options.map(async t=>t.condition?await e(i,t.condition)?t:null:t))).filter(e=>e!==null);return o.length===n.options.length?n:o.length===0?null:{...n,options:o}}))).filter(e=>e!==null)}export{i as getStepFields};