@poveste/plugin-svelte 0.5.2 → 0.6.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/dist/client/MountVariant.js +1 -1
- package/dist/client/MountVariant.svelte +30 -3
- package/dist/client/RenderVariant.js +1 -1
- package/dist/client/RenderVariant.svelte +16 -5
- package/dist/client/mount.d.ts +11 -1
- package/dist/client/mount.js +1 -1
- package/dist/collect/index.js +1 -1
- package/package.json +6 -6
- package/src/client/MountVariant.svelte +30 -3
- package/src/client/RenderVariant.svelte +16 -5
- package/src/client/mount.ts +18 -0
- package/src/collect/index.ts +13 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{afterUpdate as e,getContext as t}from"svelte";import"svelte/internal/disclose-version";import"svelte/internal/flags/legacy";import*as
|
|
1
|
+
import{afterUpdate as e,getContext as t,onDestroy as n}from"svelte";import"svelte/internal/disclose-version";import"svelte/internal/flags/legacy";import*as r from"svelte/internal/client";r.from_html(`<!> <!>`,1);function i(i,a){let o=r.sanitize_slots(a);r.push(a,!1);let s=r.prop(a,`source`,8,null),c=r.prop(a,`responsiveDisabled`,8,!1),l=r.prop(a,`autoPropsDisabled`,8,!1),u=r.prop(a,`setupApp`,8,null),d=r.prop(a,`implicit`,8,!1),f=t(`__pvtStory`),p=t(`__pvtIndex`),m=t(`__pvtSlots`),h=t(`__pvtTargetVariantId`)??null,g=f.variants[p.value];p.value++;let _=!1;function v(){Object.assign(g,{slots:()=>({default:!0,controls:o.controls??m.controls}),source:s(),responsiveDisabled:c(),autoPropsDisabled:l(),setupApp:u(),configReady:!0}),!d()&&!f.meta?.hasVariantChildComponents&&(f.meta=f.meta||{},Object.assign(f.meta,{hasVariantChildComponents:!0}))}function y(){_||(_=!0,v())}if(h===null)y();else{let e=h.subscribe(e=>{(e===null||g?.id===e)&&y()});n(e)}e(()=>{_&&v()}),r.init();var b=r.comment(),x=r.first_child(b);r.if(x,e=>{}),r.append(i,b),r.pop()}export{i as default};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { afterUpdate, getContext } from 'svelte'
|
|
2
|
+
import { afterUpdate, getContext, onDestroy } from 'svelte'
|
|
3
3
|
|
|
4
4
|
export let source = null
|
|
5
5
|
export let responsiveDisabled = false
|
|
@@ -10,10 +10,19 @@
|
|
|
10
10
|
const story = getContext('__pvtStory')
|
|
11
11
|
const index = getContext('__pvtIndex')
|
|
12
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
|
|
13
17
|
|
|
14
18
|
const variant = story.variants[index.value]
|
|
15
19
|
index.value++
|
|
16
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
|
+
|
|
17
26
|
function updateVariant() {
|
|
18
27
|
Object.assign(variant, {
|
|
19
28
|
slots: () => ({
|
|
@@ -34,10 +43,28 @@
|
|
|
34
43
|
})
|
|
35
44
|
}
|
|
36
45
|
}
|
|
37
|
-
updateVariant()
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
function becomeTarget() {
|
|
48
|
+
if (isTarget) return
|
|
49
|
+
isTarget = true
|
|
40
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()
|
|
41
68
|
})
|
|
42
69
|
</script>
|
|
43
70
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{watch as e}from"@poveste/vendors/vue";import{getContext as t,onDestroy as n}from"svelte";import"svelte/internal/disclose-version";import"svelte/internal/flags/legacy";import*as r from"svelte/internal/client";var i=r.from_html(`<!> <!>`,1);function a(a,o){let s=r.sanitize_slots(o);r.push(o,!1);let c=t(`__pvtStory`),l=r.mutable_source(t(`__pvtVariant`)),u=t(`__pvtSlot`),d=t(`__pvtIndex`),f=c.variants[d.value];d.value++;let p=r.get(l).id===f.id,m=r.prop(o,`source`,8,null),h=r.prop(o,`initState`,8,null);h()&&p&&!r.get(l).__pvtStateSeeded&&(r.mutate(l,r.get(l).__pvtStateSeeded=!0),r.mutate(l,r.get(l).state={...r.get(l).state,...h()()})),!h()&&p&&u===`controls`&&s.controls&&!r.get(l).__pvtStateWarned&&(r.mutate(l,r.get(l).__pvtStateWarned=!0),console.error([`[poveste] Variant "${f?.title??f?.id}" has a controls slot but no \`initState\`.`,`Controls will render and appear to work, but their edits cannot reach the story:`,`the story is mounted separately for each slot, so a component-local variable is not shared.`,"Pass `initState` and read state from the snippet —",`https://poveste.dev/guide/migration-from-histoire.html#svelte-story-state-moves-to-initstate`].join(` `)));let g=r.mutable_source(r.get(l)?.state),_=e(()=>r.get(l)?.state,()=>{r.set(g,r.get(l)?.state)},{deep:!0})
|
|
1
|
+
import{watch as e}from"@poveste/vendors/vue";import{getContext as t,onDestroy as n}from"svelte";import"svelte/internal/disclose-version";import"svelte/internal/flags/legacy";import*as r from"svelte/internal/client";var i=r.from_html(`<!> <!>`,1);function a(a,o){let s=r.sanitize_slots(o);r.push(o,!1);let c=t(`__pvtStory`),l=r.mutable_source(t(`__pvtVariant`)),u=t(`__pvtSlot`),d=t(`__pvtIndex`),f=c.variants[d.value];d.value++;let p=r.get(l).id===f.id,m=r.prop(o,`source`,8,null),h=r.prop(o,`initState`,8,null);h()&&p&&!r.get(l).__pvtStateSeeded&&(r.mutate(l,r.get(l).__pvtStateSeeded=!0),r.mutate(l,r.get(l).state={...r.get(l).state,...h()()})),!h()&&p&&u===`controls`&&s.controls&&!r.get(l).__pvtStateWarned&&(r.mutate(l,r.get(l).__pvtStateWarned=!0),console.error([`[poveste] Variant "${f?.title??f?.id}" has a controls slot but no \`initState\`.`,`Controls will render and appear to work, but their edits cannot reach the story:`,`the story is mounted separately for each slot, so a component-local variable is not shared.`,"Pass `initState` and read state from the snippet —",`https://poveste.dev/guide/migration-from-histoire.html#svelte-story-state-moves-to-initstate`].join(` `)));let g=r.mutable_source(r.get(l)?.state),_=()=>{};p&&(_=e(()=>r.get(l)?.state,()=>{r.set(g,r.get(l)?.state)},{deep:!0})),n(()=>_()),r.legacy_pre_effect(()=>(r.deep_read_state(m()),r.get(g),r.get(l)),()=>{if(p){let e=typeof m()==`function`?m()(r.get(g)):m();e!=null&&Object.assign(r.get(l),{source:e})}}),r.legacy_pre_effect_reset(),r.init();var v=r.comment(),y=r.first_child(v),b=e=>{var t=i(),n=r.first_child(t),a=e=>{var t=r.comment(),n=r.first_child(t);r.slot(n,o,`default`,{get state(){return r.get(g)}},null),r.append(e,t)};r.if(n,e=>{u==="default"&&e(a)});var s=r.sibling(n,2),c=e=>{var t=r.comment(),n=r.first_child(t);r.slot(n,o,`controls`,{get state(){return r.get(g)}},null),r.append(e,t)};r.if(s,e=>{u===`controls`&&e(c)}),r.append(e,t)};r.if(y,e=>{p&&e(b)}),r.append(a,v),r.pop()}export{a as default};
|
|
@@ -42,17 +42,28 @@
|
|
|
42
42
|
|
|
43
43
|
let state = currentVariant?.state
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
+
}
|
|
48
55
|
|
|
49
|
-
onDestroy(stopWatchingState)
|
|
56
|
+
onDestroy(() => stopWatchingState())
|
|
50
57
|
|
|
51
58
|
// `source` may be a function of the state. Story props are evaluated in the
|
|
52
59
|
// component's script, where the slot's `state` is not in scope, so a string
|
|
53
60
|
// literal cannot reflect what the controls are doing — which is most of the
|
|
54
61
|
// point of the source panel (#81).
|
|
55
|
-
|
|
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) {
|
|
56
67
|
const resolvedSource = typeof source === 'function' ? source(state) : source
|
|
57
68
|
if (resolvedSource != null) {
|
|
58
69
|
Object.assign(currentVariant, {
|
package/dist/client/mount.d.ts
CHANGED
|
@@ -5,6 +5,10 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
5
5
|
type: _PropType<Story>;
|
|
6
6
|
required: true;
|
|
7
7
|
};
|
|
8
|
+
targetVariantId: {
|
|
9
|
+
type: StringConstructor;
|
|
10
|
+
default: any;
|
|
11
|
+
};
|
|
8
12
|
}>, {
|
|
9
13
|
el: import("vue").Ref<HTMLDivElement, HTMLDivElement>;
|
|
10
14
|
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
|
@@ -12,5 +16,11 @@ declare const _default: import("vue").DefineComponent<import("vue").ExtractPropT
|
|
|
12
16
|
type: _PropType<Story>;
|
|
13
17
|
required: true;
|
|
14
18
|
};
|
|
15
|
-
|
|
19
|
+
targetVariantId: {
|
|
20
|
+
type: StringConstructor;
|
|
21
|
+
default: any;
|
|
22
|
+
};
|
|
23
|
+
}>> & Readonly<{}>, {
|
|
24
|
+
targetVariantId: string;
|
|
25
|
+
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
|
|
16
26
|
export default _default;
|
package/dist/client/mount.js
CHANGED
|
@@ -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
|
|
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};
|
package/dist/collect/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{callSetupFunctions as e,mountSvelteComponent as t}from"../util/svelte.js";import n from"./Story.svelte";import r from"./Variant.svelte";import*as i from"virtual:$poveste-generated-global-setup";import*as a from"virtual:$poveste-setup";import{tick as o}from"svelte";async function s({file:s,el:c,storyData:l}){let{default:u}=await import(/* @vite-ignore */s.moduleId),d=await t(u,{target:c,props:{Hst:{Story:n,Variant:r}},context:new Map(Object.entries({__pvtAddStory(e){l.push(e)},__pvtStoryFile:s}))},`client`),f={app:d.app,story:null,variant:null};await e(i,a,f),await o()
|
|
1
|
+
import{callSetupFunctions as e,mountSvelteComponent as t}from"../util/svelte.js";import n from"./Story.svelte";import r from"./Variant.svelte";import*as i from"virtual:$poveste-generated-global-setup";import*as a from"virtual:$poveste-setup";import{tick as o}from"svelte";async function s({file:s,el:c,storyData:l}){let{default:u}=await import(/* @vite-ignore */s.moduleId),d=await t(u,{target:c,props:{Hst:{Story:n,Variant:r}},context:new Map(Object.entries({__pvtAddStory(e){l.push(e)},__pvtStoryFile:s}))},`client`),f={app:d.app,story:null,variant:null};if(await e(i,a,f),await o(),!l[0]){d.destroy();return}l[0].variants.length||l[0].variants.push({id:`_default`,title:`default`}),d.destroy()}export{s as run};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@poveste/plugin-svelte",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.6.0",
|
|
5
5
|
"description": "Poveste plugin for Svelte 5 and SvelteKit support",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "Sorin Gitlan"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@sveltejs/kit": "^2.53.0",
|
|
29
29
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
30
30
|
"svelte": "^5.46.4",
|
|
31
|
-
"poveste": "^0.
|
|
31
|
+
"poveste": "^0.6.0"
|
|
32
32
|
},
|
|
33
33
|
"peerDependenciesMeta": {
|
|
34
34
|
"@sveltejs/kit": {
|
|
@@ -40,9 +40,9 @@
|
|
|
40
40
|
"globby": "^14.0.2",
|
|
41
41
|
"launch-editor": "^2.9.1",
|
|
42
42
|
"pathe": "^1.1.2",
|
|
43
|
-
"@poveste/controls": "^0.
|
|
44
|
-
"@poveste/
|
|
45
|
-
"@poveste/
|
|
43
|
+
"@poveste/controls": "^0.6.0",
|
|
44
|
+
"@poveste/shared": "^0.6.0",
|
|
45
|
+
"@poveste/vendors": "^0.6.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
48
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"svelte-preprocess": "^6.0.3",
|
|
55
55
|
"typescript": "5.6.3",
|
|
56
56
|
"vite": "^8.0.0",
|
|
57
|
-
"poveste": "0.
|
|
57
|
+
"poveste": "0.6.0"
|
|
58
58
|
},
|
|
59
59
|
"scripts": {
|
|
60
60
|
"build": "rimraf dist && vite build && tsc -d -P tsconfig.build.json && pnpm run build:types",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { afterUpdate, getContext } from 'svelte'
|
|
2
|
+
import { afterUpdate, getContext, onDestroy } from 'svelte'
|
|
3
3
|
|
|
4
4
|
export let source = null
|
|
5
5
|
export let responsiveDisabled = false
|
|
@@ -10,10 +10,19 @@
|
|
|
10
10
|
const story = getContext('__pvtStory')
|
|
11
11
|
const index = getContext('__pvtIndex')
|
|
12
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
|
|
13
17
|
|
|
14
18
|
const variant = story.variants[index.value]
|
|
15
19
|
index.value++
|
|
16
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
|
+
|
|
17
26
|
function updateVariant() {
|
|
18
27
|
Object.assign(variant, {
|
|
19
28
|
slots: () => ({
|
|
@@ -34,10 +43,28 @@
|
|
|
34
43
|
})
|
|
35
44
|
}
|
|
36
45
|
}
|
|
37
|
-
updateVariant()
|
|
38
46
|
|
|
39
|
-
|
|
47
|
+
function becomeTarget() {
|
|
48
|
+
if (isTarget) return
|
|
49
|
+
isTarget = true
|
|
40
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()
|
|
41
68
|
})
|
|
42
69
|
</script>
|
|
43
70
|
|
|
@@ -42,17 +42,28 @@
|
|
|
42
42
|
|
|
43
43
|
let state = currentVariant?.state
|
|
44
44
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
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
|
+
}
|
|
48
55
|
|
|
49
|
-
onDestroy(stopWatchingState)
|
|
56
|
+
onDestroy(() => stopWatchingState())
|
|
50
57
|
|
|
51
58
|
// `source` may be a function of the state. Story props are evaluated in the
|
|
52
59
|
// component's script, where the slot's `state` is not in scope, so a string
|
|
53
60
|
// literal cannot reflect what the controls are doing — which is most of the
|
|
54
61
|
// point of the source panel (#81).
|
|
55
|
-
|
|
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) {
|
|
56
67
|
const resolvedSource = typeof source === 'function' ? source(state) : source
|
|
57
68
|
if (resolvedSource != null) {
|
|
58
69
|
Object.assign(currentVariant, {
|
package/src/client/mount.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ref as _ref,
|
|
13
13
|
watch as _watch,
|
|
14
14
|
} from '@poveste/vendors/vue'
|
|
15
|
+
import { writable } from 'svelte/store'
|
|
15
16
|
// @ts-expect-error virtual module id
|
|
16
17
|
import * as generatedSetup from 'virtual:$poveste-generated-global-setup'
|
|
17
18
|
// @ts-expect-error virtual module id
|
|
@@ -32,6 +33,14 @@ export default _defineComponent({
|
|
|
32
33
|
type: Object as _PropType<Story>,
|
|
33
34
|
required: true,
|
|
34
35
|
},
|
|
36
|
+
|
|
37
|
+
// Set by a sandbox: the one variant this realm serves. The story's `{#each}`
|
|
38
|
+
// still instantiates a MountVariant per variant — that is the user's
|
|
39
|
+
// template — but the others can skip their bookkeeping (#197).
|
|
40
|
+
targetVariantId: {
|
|
41
|
+
type: String,
|
|
42
|
+
default: null,
|
|
43
|
+
},
|
|
35
44
|
},
|
|
36
45
|
|
|
37
46
|
setup(props) {
|
|
@@ -40,6 +49,14 @@ export default _defineComponent({
|
|
|
40
49
|
let target: HTMLDivElement
|
|
41
50
|
let destroyApp: (() => void) | null = null
|
|
42
51
|
|
|
52
|
+
// A store rather than a value, so a retargeted realm (#240) can tell the
|
|
53
|
+
// variant it now serves to register without remounting the story — the
|
|
54
|
+
// context is fixed at mount, a store subscription is not.
|
|
55
|
+
const targetVariantId = writable<string | null>(props.targetVariantId)
|
|
56
|
+
_watch(() => props.targetVariantId, (id) => {
|
|
57
|
+
targetVariantId.set(id)
|
|
58
|
+
})
|
|
59
|
+
|
|
43
60
|
async function mountStory() {
|
|
44
61
|
target = document.createElement('div')
|
|
45
62
|
el.value.appendChild(target)
|
|
@@ -55,6 +72,7 @@ export default _defineComponent({
|
|
|
55
72
|
},
|
|
56
73
|
context: new Map(Object.entries({
|
|
57
74
|
__pvtStory: props.story,
|
|
75
|
+
__pvtTargetVariantId: targetVariantId,
|
|
58
76
|
})),
|
|
59
77
|
}, 'client')
|
|
60
78
|
app = mountedApp.app
|
package/src/collect/index.ts
CHANGED
|
@@ -42,7 +42,19 @@ export async function run({ file, el, storyData }: ServerRunPayload) {
|
|
|
42
42
|
|
|
43
43
|
await tick()
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
// A file with no `Hst.Story` in it collects nothing, which is a thing people
|
|
46
|
+
// write — a scratch file, a component that lost its story tag in a refactor.
|
|
47
|
+
// The optional chain below used to guard only the read: with no story the
|
|
48
|
+
// condition came out true and the body then dereferenced the same `undefined`,
|
|
49
|
+
// so the collector crashed the whole build instead of skipping one file. The
|
|
50
|
+
// Vue collector warns and carries on, and the shared warning downstream
|
|
51
|
+
// (`No story found for …`) is already written for exactly this.
|
|
52
|
+
if (!storyData[0]) {
|
|
53
|
+
mountedApp.destroy()
|
|
54
|
+
return
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (!storyData[0].variants.length) {
|
|
46
58
|
storyData[0].variants.push({
|
|
47
59
|
id: '_default',
|
|
48
60
|
title: 'default',
|