@poveste/plugin-svelte 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ // https://github.com/microsoft/TypeScript/issues/33079
2
+ export * from './dist/client/index'
package/collect.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ // https://github.com/microsoft/TypeScript/issues/33079
2
+ export * from './dist/collect/index'
@@ -1 +1 @@
1
- import e from"./MountVariant.svelte";import{getContext as t,setContext as n}from"svelte";import"svelte/internal/disclose-version";import"svelte/internal/flags/legacy";import*as r from"svelte/internal/client";import{omitInheritStoryProps as i}from"@poveste/shared";function a(a,o){let s=r.sanitize_slots(o),c=r.legacy_rest_props(o,[`children`,`$$slots`,`$$events`,`$$legacy`]),l=r.legacy_rest_props(c,[]);r.push(o,!1);let u=t(`__pvtStory`);n(`__pvtIndex`,{value:0}),n(`__pvtSlots`,s);let d=Object.keys(u).filter(e=>!i.includes(e)).reduce((e,t)=>(e[t]=u[t],e),{});r.init();var f=r.comment(),p=r.first_child(f),m=t=>{e(t,r.spread_props(()=>d,()=>l,{implicit:!0,children:(e,t)=>{var n=r.comment(),i=r.first_child(n);r.slot(i,o,`default`,{},null),r.append(e,n)},$$slots:{default:!0,controls:(e,t)=>{var n=r.comment(),i=r.first_child(n);r.slot(i,o,`controls`,{},null),r.append(e,n)}}}))},h=e=>{var t=r.comment(),n=r.first_child(t);r.slot(n,o,`default`,{},null),r.append(e,t)};r.if(p,e=>{r.untrack(()=>u.variants.length===1&&u.variants[0].id===`_default`)?e(m):e(h,-1)}),r.append(a,f),r.pop()}export{a as default};
1
+ import e from"./MountVariant.svelte";import{omitInheritStoryProps as t}from"@poveste/shared";import{getContext as n,setContext as r}from"svelte";import"svelte/internal/disclose-version";import"svelte/internal/flags/legacy";import*as i from"svelte/internal/client";function a(a,o){let s=i.sanitize_slots(o),c=i.legacy_rest_props(o,[`children`,`$$slots`,`$$events`,`$$legacy`]),l=i.legacy_rest_props(c,[]);i.push(o,!1);let u=n(`__pvtStory`);r(`__pvtIndex`,{value:0}),r(`__pvtSlots`,s);let d=Object.keys(u).filter(e=>!t.includes(e)).reduce((e,t)=>(e[t]=u[t],e),{});i.init();var f=i.comment(),p=i.first_child(f),m=t=>{e(t,i.spread_props(()=>d,()=>l,{implicit:!0,children:(e,t)=>{var n=i.comment(),r=i.first_child(n);i.slot(r,o,`default`,{},null),i.append(e,n)},$$slots:{default:!0,controls:(e,t)=>{var n=i.comment(),r=i.first_child(n);i.slot(r,o,`controls`,{},null),i.append(e,n)}}}))},h=e=>{var t=i.comment(),n=i.first_child(t);i.slot(n,o,`default`,{},null),i.append(e,t)};i.if(p,e=>{i.untrack(()=>u.variants.length===1&&u.variants[0].id===`_default`)?e(m):e(h,-1)}),i.append(a,f),i.pop()}export{a as default};
@@ -1,5 +1,5 @@
1
- export { default as MountStory } from './mount';
2
- export { default as RenderStory } from './render';
1
+ export { default as MountStory } from './mount.js';
2
+ export { default as RenderStory } from './render.js';
3
3
  declare module '@poveste/shared' {
4
4
  interface StoryMeta {
5
5
  hasVariantChildComponents?: boolean;
@@ -1 +1 @@
1
- import{callSetupFunctions as e,mountSvelteComponent as t}from"../util/svelte.js";import n from"./MountVariant.svelte";import r from"./MountStory.svelte";import i from"./Stub.svelte";import{components as a}from"@poveste/controls";import{defineComponent as o,h as s,onMounted as c,onUnmounted as l,ref as u,watch as d}from"@poveste/vendors/vue";import{writable as f}from"svelte/store";import*as p from"virtual:$poveste-generated-global-setup";import*as m from"virtual:$poveste-setup";var h=o({name:`MountStory`,props:{story:{type:Object,required:!0},targetVariantId:{type:String,default:null}},setup(i){let a=u(),o,s,h=null,_=f(i.targetVariantId);d(()=>i.targetVariantId,e=>{_.set(e)});async function v(){s=document.createElement(`div`),a.value.appendChild(s);let c=await t(i.story.file.component,{target:s,props:{Hst:{Story:r,Variant:n,...g()}},context:new Map(Object.entries({__pvtStory:i.story,__pvtTargetVariantId:_}))},`client`);o=c.app,h=c.destroy;let l={app:o,story:i.story,variant:null};await e(p,m,l)}function y(){h?.(),h=null,s&&=(s.parentNode?.removeChild(s),null),o=null}return d(()=>i.story.id,async()=>{y(),await v()}),c(async()=>{await v()}),l(()=>{y()}),{el:a}},render(){return s(`div`,{ref:`el`})}});function g(){let e={};for(let t in a)e[t.substring(3)]=i;return e}export{h as default};
1
+ import{callSetupFunctions as e,mountSvelteComponent as t}from"../util/svelte.js";import n from"./MountVariant.svelte";import r from"./MountStory.svelte";import i from"./Stub.svelte";import{components as a}from"@poveste/controls";import{defineComponent as o,h as s,onMounted as c,onUnmounted as l,ref as u,watch as d}from"@poveste/vendors/vue";import{writable as f}from"svelte/store";import*as p from"virtual:$poveste-generated-global-setup";import*as m from"virtual:$poveste-setup";var h=o({name:`MountStory`,props:{story:{type:Object,required:!0},targetVariantId:{type:String,default:null}},setup(i){let a=u(),o,s,h=null,_=f(i.targetVariantId);d(()=>i.targetVariantId,e=>{_.set(e)});async function v(){s=document.createElement(`div`),a.value.appendChild(s);let c=await t(i.story.file.component,{target:s,props:{Hst:{Story:r,Variant:n,...g()}},context:new Map(Object.entries({__pvtStory:i.story,__pvtTargetVariantId:_}))},`client`,{storyId:i.story.id,variantId:i.targetVariantId??void 0});o=c.app,h=c.destroy;let l={app:o,story:i.story,variant:null};await e(p,m,l)}function y(){h?.(),h=null,s&&=(s.parentNode?.removeChild(s),null),o=null}return d(()=>i.story.id,async()=>{y(),await v()}),c(async()=>{await v()}),l(()=>{y()}),{el:a}},render(){return s(`div`,{ref:`el`})}});function g(){let e={};for(let t in a)e[t.substring(3)]=i;return e}export{h as default};
@@ -1 +1 @@
1
- import{callSetupFunctions as e,createWrappedComponent as t,getLegacyStateApi as n,mountSvelteComponent as r}from"../util/svelte.js";import i from"./RenderStory.svelte";import a from"./RenderVariant.svelte";import{syncState as o}from"./util.js";import s from"./Wrap.svelte";import{components as c}from"@poveste/controls";import{defineComponent as l,h as u,onMounted as d,onUnmounted as f,ref as p,watch as m}from"@poveste/vendors/vue";import*as h from"virtual:$poveste-generated-global-setup";import*as g from"virtual:$poveste-setup";var _=l({name:`RenderStory`,props:{variant:{type:Object,required:!0},story:{type:Object,required:!0},slotName:{type:String,default:`default`}},setup(t,{emit:s}){let c=p(),l,u,_=[];function y(e,t){document.addEventListener(e,t);let n=()=>document.removeEventListener(e,t);return _.push(n),{off:n}}async function b(){u=document.createElement(`div`),c.value.appendChild(u);let d=[],{off:f}=y(`SvelteRegisterComponent`,e=>{let{component:t}=e.detail;d.push(t)}),p=await r(t.story.file.component,{target:u,props:{Hst:{Story:i,Variant:a,...v()}},context:new Map(Object.entries({__pvtStory:t.story,__pvtVariant:t.variant,__pvtSlot:t.slotName}))},`client`);l=p.app,_.push(()=>{p.destroy()});let m=d.find(e=>e.$$&&l?.$$&&e.$$===l.$$)??l;f(),d=[];function b(){let e=m?.$replace;e&&(m.$replace=(...t)=>{let n=e.apply(m,t);return m=n??m,n})}b();let x=n(m);if(x){let{apply:e,stop:n}=o(t.variant.state,e=>{x.injectState(e)});_.push(n);let r,i=()=>{e(x.captureState()),r=requestAnimationFrame(i)};r=requestAnimationFrame(i),_.push(()=>{cancelAnimationFrame(r)}),e(x.captureState())}let S={app:l,story:t.story,variant:t.variant};await e(h,g,S,t.variant.setupApp),s(`ready`)}function x(){_.forEach(e=>e()),_=[],u&&=(u.parentNode?.removeChild(u),null),l=null}return m(()=>t.story.id,async()=>{x(),await b()}),d(async()=>{await b()}),f(()=>{x()}),{el:c}},render(){return u(`div`,{ref:`el`})}});function v(){let e={};for(let t in c)e[t.substring(3)]=y(c[t]);return e}function y(e){return t(s,e)}export{_ as default};
1
+ import{callSetupFunctions as e,createWrappedComponent as t,getLegacyStateApi as n,mountSvelteComponent as r}from"../util/svelte.js";import i from"./RenderStory.svelte";import a from"./RenderVariant.svelte";import{syncState as o}from"./util.js";import s from"./Wrap.svelte";import{components as c}from"@poveste/controls";import{defineComponent as l,h as u,onMounted as d,onUnmounted as f,ref as p,watch as m}from"@poveste/vendors/vue";import*as h from"virtual:$poveste-generated-global-setup";import*as g from"virtual:$poveste-setup";var _=l({name:`RenderStory`,props:{variant:{type:Object,required:!0},story:{type:Object,required:!0},slotName:{type:String,default:`default`}},setup(t,{emit:s}){let c=p(),l,u,_=[];function y(e,t){document.addEventListener(e,t);let n=()=>document.removeEventListener(e,t);return _.push(n),{off:n}}async function b(){u=document.createElement(`div`),c.value.appendChild(u);let d=[],{off:f}=y(`SvelteRegisterComponent`,e=>{let{component:t}=e.detail;d.push(t)}),p=await r(t.story.file.component,{target:u,props:{Hst:{Story:i,Variant:a,...v()}},context:new Map(Object.entries({__pvtStory:t.story,__pvtVariant:t.variant,__pvtSlot:t.slotName}))},`client`,{storyId:t.story.id,variantId:t.variant?.id});l=p.app,_.push(()=>{p.destroy()});let m=d.find(e=>e.$$&&l?.$$&&e.$$===l.$$)??l;f(),d=[];function b(){let e=m?.$replace;e&&(m.$replace=(...t)=>{let n=e.apply(m,t);return m=n??m,n})}b();let x=n(m);if(x){let{apply:e,stop:n}=o(t.variant.state,e=>{x.injectState(e)});_.push(n);let r,i=()=>{e(x.captureState()),r=requestAnimationFrame(i)};r=requestAnimationFrame(i),_.push(()=>{cancelAnimationFrame(r)}),e(x.captureState())}let S={app:l,story:t.story,variant:t.variant};await e(h,g,S,t.variant.setupApp),s(`ready`)}function x(){_.forEach(e=>e()),_=[],u&&=(u.parentNode?.removeChild(u),null),l=null}return m(()=>t.story.id,async()=>{x(),await b()}),d(async()=>{await b()}),f(()=>{x()}),{el:c}},render(){return u(`div`,{ref:`el`})}});function v(){let e={};for(let t in c)e[t.substring(3)]=y(c[t]);return e}function y(e){return t(s,e)}export{_ as default};
@@ -1,4 +1,6 @@
1
+ import type { StoryError } from '@poveste/shared';
1
2
  import type { SvelteStorySetupApi, SvelteStorySetupHandler } from '../helpers.js';
3
+ type StoryOccupant = Pick<StoryError, 'storyId' | 'variantId'>;
2
4
  type SetupModule = Record<string, unknown>;
3
5
  export interface MountedSvelteComponent {
4
6
  app: any;
@@ -8,7 +10,7 @@ export interface LegacyStateApi {
8
10
  captureState: () => Record<string, any> | null;
9
11
  injectState: (state: Record<string, any>) => void;
10
12
  }
11
- export declare function mountSvelteComponent(component: any, options: Record<string, any>, mode?: 'auto' | 'client' | 'server-compat'): Promise<MountedSvelteComponent>;
13
+ export declare function mountSvelteComponent(component: any, options: Record<string, any>, mode?: 'auto' | 'client' | 'server-compat', occupant?: StoryOccupant): Promise<MountedSvelteComponent>;
12
14
  export declare function getLegacyStateApi(app: any): LegacyStateApi | null;
13
15
  export declare function callSetupFunctions(generatedSetup: SetupModule, setup: SetupModule, setupApi: SvelteStorySetupApi, variantSetupApp?: SvelteStorySetupHandler | null): Promise<void>;
14
16
  export declare function createWrappedComponent(Wrap: any, controlComponent: any): {
@@ -1,3 +1,4 @@
1
+ import { reportStoryError } from '@poveste/shared';
1
2
  import * as svelte from 'svelte';
2
3
  const setupHookNames = [
3
4
  'setupSvelte3',
@@ -7,10 +8,25 @@ const setupHookNames = [
7
8
  function loadSvelteModule(moduleId) {
8
9
  return import(/* @vite-ignore */ moduleId);
9
10
  }
10
- export async function mountSvelteComponent(component, options, mode = 'auto') {
11
+ function report(mount, occupant) {
12
+ try {
13
+ return mount();
14
+ }
15
+ catch (error) {
16
+ reportStoryError(error, occupant);
17
+ throw error;
18
+ }
19
+ }
20
+ export async function mountSvelteComponent(component, options, mode = 'auto',
21
+ // Which story this is, so a report is not misattributed to whatever the realm
22
+ // was retargeted to next (#240).
23
+ occupant) {
11
24
  if (mode !== 'server-compat') {
12
25
  if (typeof svelte?.mount === 'function') {
13
- const app = svelte.mount(component, options);
26
+ // Svelte throws out of `mount` rather than swallowing it, so this only
27
+ // reports and rethrows — the host needs to know a story is broken, and
28
+ // nothing downstream should behave differently for it (#323).
29
+ const app = report(() => svelte.mount(component, options), occupant);
14
30
  return {
15
31
  app,
16
32
  destroy: () => {
@@ -27,7 +43,7 @@ export async function mountSvelteComponent(component, options, mode = 'auto') {
27
43
  }
28
44
  try {
29
45
  // eslint-disable-next-line new-cap
30
- const app = new component(options);
46
+ const app = report(() => new component(options), occupant);
31
47
  return {
32
48
  app,
33
49
  destroy: () => {
package/package.json CHANGED
@@ -1,34 +1,66 @@
1
1
  {
2
2
  "name": "@poveste/plugin-svelte",
3
3
  "type": "module",
4
- "version": "0.6.1",
4
+ "version": "0.8.0",
5
5
  "description": "Poveste plugin for Svelte 5 and SvelteKit support",
6
6
  "author": {
7
7
  "name": "Sorin Gitlan"
8
8
  },
9
9
  "license": "MIT",
10
+ "homepage": "https://poveste.dev",
10
11
  "repository": {
11
12
  "url": "https://github.com/poveste-dev/poveste.git",
12
13
  "type": "git",
13
14
  "directory": "packages/poveste-plugin-svelte"
14
15
  },
16
+ "bugs": "https://github.com/poveste-dev/poveste/issues",
17
+ "keywords": [
18
+ "poveste",
19
+ "histoire",
20
+ "storybook",
21
+ "component-playground",
22
+ "component-explorer",
23
+ "stories",
24
+ "styleguide",
25
+ "design-system",
26
+ "vite",
27
+ "svelte",
28
+ "svelte5",
29
+ "sveltekit",
30
+ "plugin"
31
+ ],
15
32
  "publishConfig": {
16
33
  "access": "public"
17
34
  },
18
35
  "exports": {
19
- "./client": "./dist/client/index.js",
20
- "./collect": "./dist/collect/index.js",
36
+ "./client": {
37
+ "types": "./dist/client/index.d.ts",
38
+ "default": "./dist/client/index.js"
39
+ },
40
+ "./collect": {
41
+ "types": "./dist/collect/index.d.ts",
42
+ "default": "./dist/collect/index.js"
43
+ },
21
44
  ".": "./dist/index.node.js",
22
45
  "./*": "./*"
23
46
  },
24
47
  "main": "./dist/index.node.js",
25
48
  "module": "./dist/index.node.js",
26
49
  "types": "./dist/index.node.d.ts",
50
+ "files": [
51
+ "assets",
52
+ "client.d.ts",
53
+ "collect.d.ts",
54
+ "dist"
55
+ ],
56
+ "engines": {
57
+ "node": "^22.22.2 || ^24.15.0 || >=26.0.0"
58
+ },
27
59
  "peerDependencies": {
28
60
  "@sveltejs/kit": "^2.53.0",
29
61
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
30
62
  "svelte": "^5.46.4",
31
- "poveste": "^0.6.1"
63
+ "poveste": "^0.8.0"
32
64
  },
33
65
  "peerDependenciesMeta": {
34
66
  "@sveltejs/kit": {
@@ -40,9 +72,9 @@
40
72
  "globby": "^14.0.2",
41
73
  "launch-editor": "^2.9.1",
42
74
  "pathe": "^1.1.2",
43
- "@poveste/controls": "^0.6.1",
44
- "@poveste/shared": "^0.6.1",
45
- "@poveste/vendors": "^0.6.1"
75
+ "@poveste/controls": "^0.8.0",
76
+ "@poveste/shared": "^0.8.0",
77
+ "@poveste/vendors": "^0.8.0"
46
78
  },
47
79
  "devDependencies": {
48
80
  "@sveltejs/vite-plugin-svelte": "^7.0.0",
@@ -54,7 +86,7 @@
54
86
  "svelte-preprocess": "^6.0.3",
55
87
  "typescript": "5.6.3",
56
88
  "vite": "^8.0.0",
57
- "poveste": "0.6.1"
89
+ "poveste": "0.8.0"
58
90
  },
59
91
  "scripts": {
60
92
  "build": "rimraf dist && vite build && tsc -d -P tsconfig.build.json && pnpm run build:types",
@@ -1,27 +0,0 @@
1
- <script>
2
- import { omitInheritStoryProps } from '@poveste/shared'
3
- import { getContext, setContext } from 'svelte'
4
- import MountVariant from './MountVariant.svelte'
5
-
6
- const story = getContext('__pvtStory')
7
- const index = { value: 0 }
8
- setContext('__pvtIndex', index)
9
- setContext('__pvtSlots', $$slots)
10
-
11
- // Not `$:`: Svelte invalidates a reactive statement when a variable it
12
- // references is reassigned, and `story` is a const read from context that
13
- // never is — so the statement ran exactly once whichever way it is written.
14
- const inheritedFromStory = Object.keys(story).filter(key => !omitInheritStoryProps.includes(key)).reduce((acc, key) => {
15
- acc[key] = story[key]
16
- return acc
17
- }, {})
18
- </script>
19
-
20
- {#if story.variants.length === 1 && story.variants[0].id === '_default'}
21
- <MountVariant {...inheritedFromStory} {...$$restProps} implicit>
22
- <slot />
23
- <slot name="controls" slot="controls" />
24
- </MountVariant>
25
- {:else}
26
- <slot />
27
- {/if}
@@ -1,74 +0,0 @@
1
- <script>
2
- import { afterUpdate, getContext, onDestroy } from 'svelte'
3
-
4
- export let source = null
5
- export let responsiveDisabled = false
6
- export let autoPropsDisabled = false
7
- export let setupApp = null
8
- export let implicit = false
9
-
10
- const story = getContext('__pvtStory')
11
- const index = getContext('__pvtIndex')
12
- const storySlots = getContext('__pvtSlots')
13
- // A store: a sandbox sets it to the one variant this realm serves and changes
14
- // it when the realm is retargeted (#240). Null in the app realm, which keeps
15
- // every variant's bookkeeping.
16
- const targetVariantId = getContext('__pvtTargetVariantId') ?? null
17
-
18
- const variant = story.variants[index.value]
19
- index.value++
20
-
21
- // A sandbox mounts the story to serve one variant. The others still get an
22
- // instance — that is the story's `{#each}` — but their slot/config sync and
23
- // the afterUpdate re-run are work for a variant this realm never renders (#197).
24
- let isTarget = false
25
-
26
- function updateVariant() {
27
- Object.assign(variant, {
28
- slots: () => ({
29
- default: true,
30
- controls: $$slots.controls ?? storySlots.controls,
31
- }),
32
- source,
33
- responsiveDisabled,
34
- autoPropsDisabled,
35
- setupApp,
36
- configReady: true,
37
- })
38
-
39
- if (!implicit && !story.meta?.hasVariantChildComponents) {
40
- story.meta = story.meta || {}
41
- Object.assign(story.meta, {
42
- hasVariantChildComponents: true,
43
- })
44
- }
45
- }
46
-
47
- function becomeTarget() {
48
- if (isTarget) return
49
- isTarget = true
50
- updateVariant()
51
- }
52
-
53
- if (targetVariantId === null) {
54
- becomeTarget()
55
- }
56
- else {
57
- // Subscribed rather than `$`-read: the subscriber runs as the store is
58
- // set, so the variant has registered before the render pass that follows
59
- // the retarget mounts it.
60
- const unsubscribe = targetVariantId.subscribe((id) => {
61
- if (id === null || variant?.id === id) becomeTarget()
62
- })
63
- onDestroy(unsubscribe)
64
- }
65
-
66
- afterUpdate(() => {
67
- if (isTarget) updateVariant()
68
- })
69
- </script>
70
-
71
- {#if false}
72
- <slot />
73
- <slot name="controls" />
74
- {/if}
@@ -1,77 +0,0 @@
1
- <script>
2
- import { watch as _watch } from '@poveste/vendors/vue'
3
- import { getContext, onDestroy, setContext } from 'svelte'
4
-
5
- const story = getContext('__pvtStory')
6
- const currentVariant = getContext('__pvtVariant')
7
- const slotName = getContext('__pvtSlot')
8
-
9
- const index = { value: 0 }
10
- setContext('__pvtIndex', index)
11
-
12
- export let source = null
13
- export let initState = null
14
-
15
- // Poveste owns the state, not the story component.
16
- //
17
- // The story is mounted once per slot — the app renders it with
18
- // `slot-name="controls"`, the preview with the default — so a `let count` in
19
- // the story exists twice and cannot be shared. Svelte 4 bridged the two
20
- // instances with `$capture_state` / `$inject_state`; Svelte 5 provides neither,
21
- // and no shim does either. So state lives on the variant, which both mounts
22
- // read from the same context object and which the sandbox bridge already
23
- // serialises across the iframe boundary (#81).
24
- //
25
- // Whichever mount arrives first seeds it; the second must not, or it would
26
- // clobber whatever the user has already changed.
27
- if (initState && currentVariant && !currentVariant.__pvtStateSeeded) {
28
- currentVariant.__pvtStateSeeded = true
29
- currentVariant.state = { ...currentVariant.state, ...initState() }
30
- }
31
-
32
- // Only from the mount that renders the controls. The story is mounted once per
33
- // slot and, for an iframe layout, in a different realm — so the flag below cannot
34
- // dedupe across them and the warning would appear twice.
35
- if (!initState && slotName === 'controls' && $$slots.controls && currentVariant && !currentVariant.__pvtStateWarned) {
36
- currentVariant.__pvtStateWarned = true
37
- console.error([
38
- `[poveste] Story "${story?.title ?? story?.id}" has a controls slot but no \`initState\`.`,
39
- 'Controls will render and appear to work, but their edits cannot reach the story:',
40
- 'the story is mounted separately for each slot, so a component-local variable is not shared.',
41
- 'Pass `initState` and read state from the snippet —',
42
- 'https://poveste.dev/guide/migration-from-histoire.html#svelte-story-state-moves-to-initstate',
43
- ].join(' '))
44
- }
45
-
46
- // `variant.state` is a Vue-reactive object, so Svelte has no way to know when a
47
- // control writes into it. Mirroring the reference back into a local on every
48
- // Vue tick is what makes the template re-render: Svelte's invalidation treats
49
- // any object assignment as a change, so reassigning the same proxy is enough.
50
- let state = currentVariant?.state
51
-
52
- const stopWatchingState = _watch(() => currentVariant?.state, () => {
53
- state = currentVariant?.state
54
- }, { deep: true })
55
-
56
- onDestroy(stopWatchingState)
57
-
58
- // `source` may be a function of the state. Story props are evaluated in the
59
- // component's script, where the slot's `state` is not in scope, so a string
60
- // literal cannot reflect what the controls are doing — which is most of the
61
- // point of the source panel (#81).
62
- $: {
63
- const resolvedSource = typeof source === 'function' ? source(state) : source
64
- if (resolvedSource != null) {
65
- Object.assign(currentVariant, {
66
- source: resolvedSource,
67
- })
68
- }
69
- }
70
- </script>
71
-
72
- {#if slotName === 'controls'}
73
- <slot name="controls" {state} />
74
- {/if}
75
- {#if slotName === 'default' || story.meta?.hasVariantChildComponents}
76
- <slot {state} />
77
- {/if}
@@ -1,83 +0,0 @@
1
- <script>
2
- import { watch as _watch } from '@poveste/vendors/vue'
3
- import { getContext, onDestroy } from 'svelte'
4
-
5
- const story = getContext('__pvtStory')
6
- const currentVariant = getContext('__pvtVariant')
7
- const slotName = getContext('__pvtSlot')
8
- const index = getContext('__pvtIndex')
9
-
10
- const variant = story.variants[index.value]
11
- index.value++
12
-
13
- // Not `$:`: Svelte invalidates a reactive statement when a variable it
14
- // references is reassigned, and both of these are consts that never are —
15
- // so the statement ran exactly once whichever way it is written.
16
- const shouldRender = currentVariant.id === variant.id
17
-
18
- export let source = null
19
- export let initState = null
20
-
21
- // Same contract as `RenderStory`: poveste owns the state because the story is
22
- // mounted once per slot, so a component-local variable cannot be shared (#81).
23
- // `variant.state` is also the only bucket the sandbox bridge carries across the
24
- // iframe boundary, which is why state is per variant rather than per story.
25
- if (initState && shouldRender && !currentVariant.__pvtStateSeeded) {
26
- currentVariant.__pvtStateSeeded = true
27
- currentVariant.state = { ...currentVariant.state, ...initState() }
28
- }
29
-
30
- // Controls mount only — see the note in RenderStory: the two mounts do not share
31
- // a realm for iframe layouts, so this is what keeps it to one warning.
32
- if (!initState && shouldRender && slotName === 'controls' && $$slots.controls && !currentVariant.__pvtStateWarned) {
33
- currentVariant.__pvtStateWarned = true
34
- console.error([
35
- `[poveste] Variant "${variant?.title ?? variant?.id}" has a controls slot but no \`initState\`.`,
36
- 'Controls will render and appear to work, but their edits cannot reach the story:',
37
- 'the story is mounted separately for each slot, so a component-local variable is not shared.',
38
- 'Pass `initState` and read state from the snippet —',
39
- 'https://poveste.dev/guide/migration-from-histoire.html#svelte-story-state-moves-to-initstate',
40
- ].join(' '))
41
- }
42
-
43
- let state = currentVariant?.state
44
-
45
- // Only the variant that renders watches. The story's `{#each}` instantiates
46
- // one of these per variant in every realm, and a deep Vue watcher per
47
- // instance on the same state object was a thousand watchers to render one
48
- // button (#197). The others render nothing, so they have nothing to update.
49
- let stopWatchingState = () => {}
50
- if (shouldRender) {
51
- stopWatchingState = _watch(() => currentVariant?.state, () => {
52
- state = currentVariant?.state
53
- }, { deep: true })
54
- }
55
-
56
- onDestroy(() => stopWatchingState())
57
-
58
- // `source` may be a function of the state. Story props are evaluated in the
59
- // component's script, where the slot's `state` is not in scope, so a string
60
- // literal cannot reflect what the controls are doing — which is most of the
61
- // point of the source panel (#81).
62
- //
63
- // Guarded by `shouldRender`: this is *this* variant's `source`, and it goes
64
- // onto `currentVariant` — so an unguarded instance for another variant would
65
- // overwrite the rendered variant's source with its own.
66
- $: if (shouldRender) {
67
- const resolvedSource = typeof source === 'function' ? source(state) : source
68
- if (resolvedSource != null) {
69
- Object.assign(currentVariant, {
70
- source: resolvedSource,
71
- })
72
- }
73
- }
74
- </script>
75
-
76
- {#if shouldRender}
77
- {#if slotName === 'default'}
78
- <slot {state} />
79
- {/if}
80
- {#if slotName === 'controls'}
81
- <slot name="controls" {state} />
82
- {/if}
83
- {/if}
File without changes
@@ -1,68 +0,0 @@
1
- <script>
2
- import {
3
- createApp as _createApp,
4
- h as _h,
5
- reactive as _reactive,
6
- } from '@poveste/vendors/vue'
7
- import { createEventDispatcher, onMount } from 'svelte'
8
-
9
- export let controlComponent
10
- export let value
11
-
12
- const dispatch = createEventDispatcher()
13
-
14
- let el
15
-
16
- let app
17
-
18
- const state = _reactive({})
19
-
20
- function updateState(value, attrs) {
21
- Object.assign(state, {
22
- value,
23
- attrs,
24
- })
25
- }
26
-
27
- onMount(() => {
28
- updateState(value, $$restProps)
29
-
30
- app = _createApp({
31
- render() {
32
- const finalListeners = {}
33
- if (controlComponent.emits) {
34
- for (const k in controlComponent.emits) {
35
- const key = Array.isArray(controlComponent.emits) ? controlComponent.emits[k] : k
36
- const finalKey = key === 'input' ? 'update:modelValue' : key
37
- finalListeners[`on${finalKey.charAt(0).toUpperCase()}${finalKey.substring(1)}`] = (...args) => {
38
- if (key === 'update:modelValue') {
39
- value = args[0]
40
- }
41
- else {
42
- dispatch(key, ...args)
43
- }
44
- }
45
- }
46
- }
47
-
48
- // `state` is the Vue-reactive mirror kept in sync by the `$:` below.
49
- // Reading the plain `value` here would make the render depend on a
50
- // variable Vue cannot track — it only saw fresh values because the
51
- // `state` mutation was what triggered the re-render in the first place.
52
- return _h(controlComponent, {
53
- modelValue: state.value,
54
- ...state.attrs,
55
- ...finalListeners,
56
- key: 'component',
57
- })
58
- },
59
- })
60
- app.mount(el)
61
- })
62
-
63
- $: updateState(value, $$restProps)
64
- </script>
65
-
66
- <div bind:this={el}>
67
- {controlComponent.name}
68
- </div>
@@ -1,12 +0,0 @@
1
- export { default as MountStory } from './mount'
2
- export { default as RenderStory } from './render'
3
-
4
- declare module '@poveste/shared' {
5
- interface StoryMeta {
6
- hasVariantChildComponents?: boolean
7
- }
8
- }
9
-
10
- export function generateSourceCode() {
11
- // noop
12
- }