@poveste/plugin-svelte 0.1.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/LICENSE +22 -0
- package/assets/histoire-svelte-text.svg +89 -0
- package/assets/histoire-svelte.svg +52 -0
- package/dist/client/MountStory.js +1 -0
- package/dist/client/MountStory.svelte +24 -0
- package/dist/client/MountVariant.js +1 -0
- package/dist/client/MountVariant.svelte +47 -0
- package/dist/client/RenderStory.js +1 -0
- package/dist/client/RenderStory.svelte +27 -0
- package/dist/client/RenderVariant.js +1 -0
- package/dist/client/RenderVariant.svelte +32 -0
- package/dist/client/Stub.js +1 -0
- package/dist/client/Stub.svelte +0 -0
- package/dist/client/Wrap.js +1 -0
- package/dist/client/Wrap.svelte +63 -0
- package/dist/client/index.d.ts +8 -0
- package/dist/client/index.js +1 -0
- package/dist/client/mount.d.ts +16 -0
- package/dist/client/mount.js +1 -0
- package/dist/client/render.d.ts +34 -0
- package/dist/client/render.js +1 -0
- package/dist/client/util.d.ts +4 -0
- package/dist/client/util.js +1 -0
- package/dist/collect/Story.js +1 -0
- package/dist/collect/Story.svelte +34 -0
- package/dist/collect/Variant.js +1 -0
- package/dist/collect/Variant.svelte +24 -0
- package/dist/collect/index.d.ts +2 -0
- package/dist/collect/index.js +1 -0
- package/dist/commands/generate-story.client.d.ts +3 -0
- package/dist/commands/generate-story.client.js +27 -0
- package/dist/commands/generate-story.server.d.ts +3 -0
- package/dist/commands/generate-story.server.js +52 -0
- package/dist/helpers.d.ts +87 -0
- package/dist/helpers.js +6 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.node.d.ts +3 -0
- package/dist/index.node.js +90 -0
- package/dist/util/list-components.d.ts +1 -0
- package/dist/util/list-components.js +15 -0
- package/dist/util/story-hmr.d.ts +7 -0
- package/dist/util/story-hmr.js +30 -0
- package/dist/util/svelte.d.ts +18 -0
- package/dist/util/svelte.js +102 -0
- package/package.json +57 -0
- package/src/client/MountStory.svelte +24 -0
- package/src/client/MountVariant.svelte +47 -0
- package/src/client/RenderStory.svelte +27 -0
- package/src/client/RenderVariant.svelte +32 -0
- package/src/client/Stub.svelte +0 -0
- package/src/client/Wrap.svelte +63 -0
- package/src/client/index.ts +12 -0
- package/src/client/mount.ts +113 -0
- package/src/client/render.ts +191 -0
- package/src/client/util.ts +52 -0
- package/src/collect/Story.svelte +34 -0
- package/src/collect/Variant.svelte +24 -0
- package/src/collect/index.ts +53 -0
- package/src/commands/generate-story.client.ts +29 -0
- package/src/commands/generate-story.server.ts +62 -0
- package/src/helpers.ts +96 -0
- package/src/index.node.ts +101 -0
- package/src/index.ts +1 -0
- package/src/util/list-components.ts +16 -0
- package/src/util/story-hmr.ts +52 -0
- package/src/util/svelte.ts +137 -0
- package/svelte.config.js +5 -0
- package/tsconfig.build.json +7 -0
- package/tsconfig.json +41 -0
- package/vite.config.ts +103 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { onMount, createEventDispatcher } from 'svelte'
|
|
3
|
+
import {
|
|
4
|
+
createApp as _createApp,
|
|
5
|
+
h as _h,
|
|
6
|
+
reactive as _reactive,
|
|
7
|
+
} from '@poveste/vendors/vue'
|
|
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
|
+
} else {
|
|
41
|
+
dispatch(key, ...args)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return _h(controlComponent, {
|
|
48
|
+
modelValue: value,
|
|
49
|
+
...state.attrs,
|
|
50
|
+
...finalListeners,
|
|
51
|
+
key: 'component',
|
|
52
|
+
})
|
|
53
|
+
},
|
|
54
|
+
})
|
|
55
|
+
app.mount(el)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
$: updateState(value, $$restProps)
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<div bind:this={el}>
|
|
62
|
+
{controlComponent.name}
|
|
63
|
+
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import type { Story } from '@poveste/shared'
|
|
2
|
+
import type {
|
|
3
|
+
PropType as _PropType,
|
|
4
|
+
} from '@poveste/vendors/vue'
|
|
5
|
+
import type { SvelteStorySetupApi } from '../helpers.js'
|
|
6
|
+
import { components } from '@poveste/controls'
|
|
7
|
+
import {
|
|
8
|
+
defineComponent as _defineComponent,
|
|
9
|
+
h as _h,
|
|
10
|
+
onMounted as _onMounted,
|
|
11
|
+
onUnmounted as _onUnmounted,
|
|
12
|
+
ref as _ref,
|
|
13
|
+
watch as _watch,
|
|
14
|
+
} from '@poveste/vendors/vue'
|
|
15
|
+
// @ts-expect-error virtual module id
|
|
16
|
+
import * as generatedSetup from 'virtual:$histoire-generated-global-setup'
|
|
17
|
+
// @ts-expect-error virtual module id
|
|
18
|
+
import * as setup from 'virtual:$histoire-setup'
|
|
19
|
+
import {
|
|
20
|
+
callSetupFunctions,
|
|
21
|
+
mountSvelteComponent,
|
|
22
|
+
} from '../util/svelte.js'
|
|
23
|
+
import MountStorySvelte from './MountStory.svelte'
|
|
24
|
+
import MountVariantSvelte from './MountVariant.svelte'
|
|
25
|
+
import StubComponent from './Stub.svelte'
|
|
26
|
+
|
|
27
|
+
export default _defineComponent({
|
|
28
|
+
name: 'MountStory',
|
|
29
|
+
|
|
30
|
+
props: {
|
|
31
|
+
story: {
|
|
32
|
+
type: Object as _PropType<Story>,
|
|
33
|
+
required: true,
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
|
|
37
|
+
setup(props) {
|
|
38
|
+
const el = _ref<HTMLDivElement>()
|
|
39
|
+
let app: any
|
|
40
|
+
let target: HTMLDivElement
|
|
41
|
+
let destroyApp: (() => void) | null = null
|
|
42
|
+
|
|
43
|
+
async function mountStory() {
|
|
44
|
+
target = document.createElement('div')
|
|
45
|
+
el.value.appendChild(target)
|
|
46
|
+
|
|
47
|
+
const mountedApp = await mountSvelteComponent(props.story.file.component, {
|
|
48
|
+
target,
|
|
49
|
+
props: {
|
|
50
|
+
Hst: {
|
|
51
|
+
Story: MountStorySvelte,
|
|
52
|
+
Variant: MountVariantSvelte,
|
|
53
|
+
...getControls(),
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
context: new Map(Object.entries({
|
|
57
|
+
__hstStory: props.story,
|
|
58
|
+
})),
|
|
59
|
+
}, 'client')
|
|
60
|
+
app = mountedApp.app
|
|
61
|
+
destroyApp = mountedApp.destroy
|
|
62
|
+
|
|
63
|
+
const setupApi: SvelteStorySetupApi = {
|
|
64
|
+
app,
|
|
65
|
+
story: props.story,
|
|
66
|
+
variant: null,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
await callSetupFunctions(generatedSetup, setup, setupApi)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function unmountStory() {
|
|
73
|
+
destroyApp?.()
|
|
74
|
+
destroyApp = null
|
|
75
|
+
if (target) {
|
|
76
|
+
target.parentNode?.removeChild(target)
|
|
77
|
+
target = null
|
|
78
|
+
}
|
|
79
|
+
app = null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
_watch(() => props.story.id, async () => {
|
|
83
|
+
unmountStory()
|
|
84
|
+
await mountStory()
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
_onMounted(async () => {
|
|
88
|
+
await mountStory()
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
_onUnmounted(() => {
|
|
92
|
+
unmountStory()
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
el,
|
|
97
|
+
}
|
|
98
|
+
},
|
|
99
|
+
|
|
100
|
+
render() {
|
|
101
|
+
return _h('div', {
|
|
102
|
+
ref: 'el',
|
|
103
|
+
})
|
|
104
|
+
},
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
function getControls() {
|
|
108
|
+
const result: Record<string, any> = {}
|
|
109
|
+
for (const key in components) {
|
|
110
|
+
result[key.substring(3)] = StubComponent
|
|
111
|
+
}
|
|
112
|
+
return result
|
|
113
|
+
}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import type { Story, Variant } from '@poveste/shared'
|
|
2
|
+
import type {
|
|
3
|
+
PropType as _PropType,
|
|
4
|
+
} from '@poveste/vendors/vue'
|
|
5
|
+
import type { SvelteStorySetupApi, SvelteStorySetupHandler } from '../helpers.js'
|
|
6
|
+
import { components } from '@poveste/controls'
|
|
7
|
+
import {
|
|
8
|
+
defineComponent as _defineComponent,
|
|
9
|
+
h as _h,
|
|
10
|
+
onMounted as _onMounted,
|
|
11
|
+
onUnmounted as _onUnmounted,
|
|
12
|
+
ref as _ref,
|
|
13
|
+
watch as _watch,
|
|
14
|
+
} from '@poveste/vendors/vue'
|
|
15
|
+
// @ts-expect-error virtual module id
|
|
16
|
+
import * as generatedSetup from 'virtual:$histoire-generated-global-setup'
|
|
17
|
+
// @ts-expect-error virtual module id
|
|
18
|
+
import * as setup from 'virtual:$histoire-setup'
|
|
19
|
+
import {
|
|
20
|
+
callSetupFunctions,
|
|
21
|
+
createWrappedComponent,
|
|
22
|
+
getLegacyStateApi,
|
|
23
|
+
mountSvelteComponent,
|
|
24
|
+
} from '../util/svelte.js'
|
|
25
|
+
import RenderStorySvelte from './RenderStory.svelte'
|
|
26
|
+
import RenderVariantSvelte from './RenderVariant.svelte'
|
|
27
|
+
import { syncState } from './util'
|
|
28
|
+
import Wrap from './Wrap.svelte'
|
|
29
|
+
|
|
30
|
+
export default _defineComponent({
|
|
31
|
+
name: 'RenderStory',
|
|
32
|
+
|
|
33
|
+
props: {
|
|
34
|
+
variant: {
|
|
35
|
+
type: Object as _PropType<Variant>,
|
|
36
|
+
required: true,
|
|
37
|
+
},
|
|
38
|
+
|
|
39
|
+
story: {
|
|
40
|
+
type: Object as _PropType<Story>,
|
|
41
|
+
required: true,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
slotName: {
|
|
45
|
+
type: String,
|
|
46
|
+
default: 'default',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
|
|
50
|
+
setup(props, { emit }) {
|
|
51
|
+
const el = _ref<HTMLDivElement>()
|
|
52
|
+
let app: any
|
|
53
|
+
let target: HTMLDivElement
|
|
54
|
+
|
|
55
|
+
let tearDownHandlers: (() => void)[] = []
|
|
56
|
+
|
|
57
|
+
function documentOn(event, cb) {
|
|
58
|
+
document.addEventListener(event, cb)
|
|
59
|
+
const off = () => document.removeEventListener(event, cb)
|
|
60
|
+
tearDownHandlers.push(off)
|
|
61
|
+
return {
|
|
62
|
+
off,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function mountStory() {
|
|
67
|
+
target = document.createElement('div')
|
|
68
|
+
el.value.appendChild(target)
|
|
69
|
+
|
|
70
|
+
let components = []
|
|
71
|
+
const { off: registerComponentOff } = documentOn('SvelteRegisterComponent', (e) => {
|
|
72
|
+
const { component } = e.detail
|
|
73
|
+
components.push(component)
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
const mountedApp = await mountSvelteComponent(props.story.file.component, {
|
|
77
|
+
target,
|
|
78
|
+
props: {
|
|
79
|
+
Hst: {
|
|
80
|
+
Story: RenderStorySvelte,
|
|
81
|
+
Variant: RenderVariantSvelte,
|
|
82
|
+
...getControls(),
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
context: new Map(Object.entries({
|
|
86
|
+
__hstStory: props.story,
|
|
87
|
+
__hstVariant: props.variant,
|
|
88
|
+
__hstSlot: props.slotName,
|
|
89
|
+
})),
|
|
90
|
+
}, 'client')
|
|
91
|
+
app = mountedApp.app
|
|
92
|
+
tearDownHandlers.push(() => {
|
|
93
|
+
mountedApp.destroy()
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
let appComponent = components.find(c => c.$$ && app?.$$ && c.$$ === app.$$) ?? app
|
|
97
|
+
registerComponentOff()
|
|
98
|
+
components = []
|
|
99
|
+
|
|
100
|
+
function patchReplaceIfAvailable() {
|
|
101
|
+
const origReplace = appComponent?.$replace
|
|
102
|
+
if (!origReplace) {
|
|
103
|
+
return
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
appComponent.$replace = (...args) => {
|
|
107
|
+
const result = origReplace.apply(appComponent, args)
|
|
108
|
+
appComponent = result ?? appComponent
|
|
109
|
+
return result
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
patchReplaceIfAvailable()
|
|
113
|
+
|
|
114
|
+
const stateApi = getLegacyStateApi(appComponent)
|
|
115
|
+
if (stateApi) {
|
|
116
|
+
const { apply, stop } = syncState(props.variant.state, (value) => {
|
|
117
|
+
stateApi.injectState(value)
|
|
118
|
+
})
|
|
119
|
+
tearDownHandlers.push(stop)
|
|
120
|
+
|
|
121
|
+
let frameId: number
|
|
122
|
+
const syncFromComponent = () => {
|
|
123
|
+
apply(stateApi.captureState())
|
|
124
|
+
frameId = requestAnimationFrame(syncFromComponent)
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
frameId = requestAnimationFrame(syncFromComponent)
|
|
128
|
+
tearDownHandlers.push(() => {
|
|
129
|
+
cancelAnimationFrame(frameId)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
apply(stateApi.captureState())
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const setupApi: SvelteStorySetupApi = {
|
|
136
|
+
app,
|
|
137
|
+
story: props.story,
|
|
138
|
+
variant: props.variant,
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await callSetupFunctions(generatedSetup, setup, setupApi, props.variant.setupApp as SvelteStorySetupHandler | null)
|
|
142
|
+
|
|
143
|
+
emit('ready')
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function unmountStory() {
|
|
147
|
+
tearDownHandlers.forEach(fn => fn())
|
|
148
|
+
tearDownHandlers = []
|
|
149
|
+
if (target) {
|
|
150
|
+
target.parentNode?.removeChild(target)
|
|
151
|
+
target = null
|
|
152
|
+
}
|
|
153
|
+
app = null
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
_watch(() => props.story.id, async () => {
|
|
157
|
+
unmountStory()
|
|
158
|
+
await mountStory()
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
_onMounted(async () => {
|
|
162
|
+
await mountStory()
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
_onUnmounted(() => {
|
|
166
|
+
unmountStory()
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
el,
|
|
171
|
+
}
|
|
172
|
+
},
|
|
173
|
+
|
|
174
|
+
render() {
|
|
175
|
+
return _h('div', {
|
|
176
|
+
ref: 'el',
|
|
177
|
+
})
|
|
178
|
+
},
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
function getControls() {
|
|
182
|
+
const result: Record<string, any> = {}
|
|
183
|
+
for (const key in components) {
|
|
184
|
+
result[key.substring(3)] = wrapComponent(components[key])
|
|
185
|
+
}
|
|
186
|
+
return result
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function wrapComponent(controlComponent) {
|
|
190
|
+
return createWrappedComponent(Wrap, controlComponent)
|
|
191
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { applyState, clone } from '@poveste/shared'
|
|
2
|
+
import { watch as _watch } from '@poveste/vendors/vue'
|
|
3
|
+
|
|
4
|
+
function cleanupState(state: Record<string, any>): Record<string, any> {
|
|
5
|
+
const result = {}
|
|
6
|
+
for (const key in state) {
|
|
7
|
+
if (key === 'Hst') continue
|
|
8
|
+
const value = state[key]
|
|
9
|
+
if (typeof value === 'function') continue
|
|
10
|
+
if (typeof value === 'undefined') continue
|
|
11
|
+
if (value instanceof HTMLElement) continue
|
|
12
|
+
if (typeof value === 'object' && value?.$$) continue
|
|
13
|
+
result[key] = value
|
|
14
|
+
}
|
|
15
|
+
return result
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function syncState(variantState, onChange: (state) => unknown) {
|
|
19
|
+
let syncing = false
|
|
20
|
+
|
|
21
|
+
const _stop = _watch(() => variantState, (value) => {
|
|
22
|
+
if (value == null) return
|
|
23
|
+
if (!syncing) {
|
|
24
|
+
syncing = true
|
|
25
|
+
onChange(cleanupState(value))
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
syncing = false
|
|
29
|
+
}
|
|
30
|
+
}, {
|
|
31
|
+
deep: true,
|
|
32
|
+
immediate: true,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
function apply(value) {
|
|
36
|
+
if (value == null) return
|
|
37
|
+
if (!syncing) {
|
|
38
|
+
syncing = true
|
|
39
|
+
applyState(variantState, clone(cleanupState(value)))
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
syncing = false
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return {
|
|
47
|
+
apply,
|
|
48
|
+
stop() {
|
|
49
|
+
_stop()
|
|
50
|
+
},
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext, setContext } from 'svelte'
|
|
3
|
+
|
|
4
|
+
export let title = null
|
|
5
|
+
export let id = null
|
|
6
|
+
export let group = null
|
|
7
|
+
export let layout = null
|
|
8
|
+
export let icon = null
|
|
9
|
+
export let iconColor = null
|
|
10
|
+
export let docsOnly = false
|
|
11
|
+
|
|
12
|
+
const addStory = getContext('__hstAddStory')
|
|
13
|
+
const file = getContext('__hstStoryFile')
|
|
14
|
+
|
|
15
|
+
const story = {
|
|
16
|
+
id: id ?? file.id,
|
|
17
|
+
title: title ?? file.fileName,
|
|
18
|
+
group,
|
|
19
|
+
layout,
|
|
20
|
+
icon,
|
|
21
|
+
iconColor,
|
|
22
|
+
docsOnly,
|
|
23
|
+
variants: [],
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
addStory(story)
|
|
27
|
+
|
|
28
|
+
setContext('__hstStory', story)
|
|
29
|
+
setContext('__hstAddVariant', (variant) => {
|
|
30
|
+
story.variants.push(variant)
|
|
31
|
+
})
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<slot />
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script>
|
|
2
|
+
import { getContext } from 'svelte'
|
|
3
|
+
|
|
4
|
+
export let title = 'untitled'
|
|
5
|
+
export let id = null
|
|
6
|
+
export let icon = null
|
|
7
|
+
export let iconColor = null
|
|
8
|
+
|
|
9
|
+
const story = getContext('__hstStory')
|
|
10
|
+
const addVariant = getContext('__hstAddVariant')
|
|
11
|
+
|
|
12
|
+
function generateId () {
|
|
13
|
+
return `${story.id}-${story.variants.length}`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const variant = {
|
|
17
|
+
id: id ?? generateId(),
|
|
18
|
+
title,
|
|
19
|
+
icon,
|
|
20
|
+
iconColor,
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
addVariant(variant)
|
|
24
|
+
</script>
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import type { ServerRunPayload } from '@poveste/shared'
|
|
2
|
+
import type { SvelteStorySetupApi } from '../helpers.js'
|
|
3
|
+
import { tick } from 'svelte'
|
|
4
|
+
// @ts-expect-error virtual module id
|
|
5
|
+
import * as generatedSetup from 'virtual:$histoire-generated-global-setup'
|
|
6
|
+
// @ts-expect-error virtual module id
|
|
7
|
+
import * as setup from 'virtual:$histoire-setup'
|
|
8
|
+
import {
|
|
9
|
+
callSetupFunctions,
|
|
10
|
+
mountSvelteComponent,
|
|
11
|
+
} from '../util/svelte.js'
|
|
12
|
+
import Story from './Story.svelte'
|
|
13
|
+
import Variant from './Variant.svelte'
|
|
14
|
+
|
|
15
|
+
export async function run({ file, el, storyData }: ServerRunPayload) {
|
|
16
|
+
const { default: Comp } = await import(/* @vite-ignore */ file.moduleId)
|
|
17
|
+
|
|
18
|
+
const mountedApp = await mountSvelteComponent(Comp, {
|
|
19
|
+
target: el,
|
|
20
|
+
props: {
|
|
21
|
+
Hst: {
|
|
22
|
+
Story,
|
|
23
|
+
Variant,
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
context: new Map(Object.entries({
|
|
27
|
+
__hstAddStory(data) {
|
|
28
|
+
storyData.push(data)
|
|
29
|
+
},
|
|
30
|
+
__hstStoryFile: file,
|
|
31
|
+
})),
|
|
32
|
+
}, 'client')
|
|
33
|
+
const app = mountedApp.app
|
|
34
|
+
|
|
35
|
+
const setupApi: SvelteStorySetupApi = {
|
|
36
|
+
app,
|
|
37
|
+
story: null,
|
|
38
|
+
variant: null,
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
await callSetupFunctions(generatedSetup, setup, setupApi)
|
|
42
|
+
|
|
43
|
+
await tick()
|
|
44
|
+
|
|
45
|
+
if (!storyData[0]?.variants.length) {
|
|
46
|
+
storyData[0].variants.push({
|
|
47
|
+
id: '_default',
|
|
48
|
+
title: 'default',
|
|
49
|
+
})
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
mountedApp.destroy()
|
|
53
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { ClientCommandOptions } from 'poveste'
|
|
2
|
+
import { kebabCase } from 'change-case'
|
|
3
|
+
import { openStory, sendEvent } from 'poveste/plugin'
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
prompts: [
|
|
7
|
+
{
|
|
8
|
+
field: 'component',
|
|
9
|
+
label: 'Choose a component',
|
|
10
|
+
type: 'select',
|
|
11
|
+
options: async search => sendEvent('listSvelteComponents', { search }),
|
|
12
|
+
required: true,
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
field: 'fileName',
|
|
16
|
+
label: 'File name',
|
|
17
|
+
type: 'text',
|
|
18
|
+
required: true,
|
|
19
|
+
defaultValue: answers => answers.component?.replace(/[^/]+\/([^/]+)\.svelte$/, '$1.story.svelte'),
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
clientAction: (params) => {
|
|
23
|
+
const index = params.component.lastIndexOf('/')
|
|
24
|
+
const dirname = params.component.substring(0, index + 1)
|
|
25
|
+
const file = `${dirname}${params.fileName}`
|
|
26
|
+
const storyId = kebabCase(file.toLowerCase())
|
|
27
|
+
openStory(storyId)
|
|
28
|
+
},
|
|
29
|
+
} as ClientCommandOptions
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { PluginCommand } from 'poveste'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import launchEditor from 'launch-editor'
|
|
4
|
+
import path from 'pathe'
|
|
5
|
+
|
|
6
|
+
export default {
|
|
7
|
+
id: 'histoire:plugin-svelte:generate-story',
|
|
8
|
+
label: 'Generate Svelte story from component',
|
|
9
|
+
icon: 'https://svelte.dev/favicon.png',
|
|
10
|
+
searchText: 'generate create',
|
|
11
|
+
async serverAction(params) {
|
|
12
|
+
const targetFile = path.join(path.dirname(params.component), params.fileName)
|
|
13
|
+
|
|
14
|
+
if (fs.existsSync(targetFile)) {
|
|
15
|
+
throw new Error(`File ${targetFile} already exists`)
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { component, componentName, isTs } = await getComponentInfo(params.component)
|
|
19
|
+
|
|
20
|
+
const content = `<script${isTs ? ' lang="ts"' : ''}>
|
|
21
|
+
${isTs
|
|
22
|
+
? `import type { Hst } from '@poveste/plugin-svelte'\n
|
|
23
|
+
`
|
|
24
|
+
: ''}import ${componentName} from './${component}'
|
|
25
|
+
|
|
26
|
+
export let Hst${isTs ? ': Hst' : ''}
|
|
27
|
+
</script>
|
|
28
|
+
|
|
29
|
+
<Hst.Story>
|
|
30
|
+
<Hst.Variant title="Default">
|
|
31
|
+
<${componentName} />
|
|
32
|
+
|
|
33
|
+
<svelte:fragment slot="controls">
|
|
34
|
+
<!-- Put controls here -->
|
|
35
|
+
</svelte:fragment>
|
|
36
|
+
</Hst.Variant>
|
|
37
|
+
</Hst.Story>
|
|
38
|
+
`
|
|
39
|
+
|
|
40
|
+
await fs.promises.writeFile(targetFile, content, 'utf-8')
|
|
41
|
+
|
|
42
|
+
launchEditor(targetFile)
|
|
43
|
+
},
|
|
44
|
+
clientSetupFile: '@poveste/plugin-svelte/dist/commands/generate-story.client.js',
|
|
45
|
+
} as PluginCommand
|
|
46
|
+
|
|
47
|
+
async function isComponentTs(component: string) {
|
|
48
|
+
const componentContent = await fs.promises.readFile(component, 'utf-8')
|
|
49
|
+
return componentContent.includes('lang="ts"')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async function getComponentInfo(file: string) {
|
|
53
|
+
const component = path.basename(file)
|
|
54
|
+
const componentName = component.replace(path.extname(component), '')
|
|
55
|
+
const isTs = await isComponentTs(file)
|
|
56
|
+
|
|
57
|
+
return {
|
|
58
|
+
component,
|
|
59
|
+
componentName,
|
|
60
|
+
isTs,
|
|
61
|
+
}
|
|
62
|
+
}
|