-
-
Notifications
You must be signed in to change notification settings - Fork 9.1k
/
decorators.ts
93 lines (85 loc) · 2.64 KB
/
decorators.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
import { DecoratorFunction, StoryContext, LegacyStoryFn } from '@storybook/csf';
import { sanitizeStoryContextUpdate } from '@storybook/store';
import SlotDecorator from './SlotDecorator.svelte';
import { SvelteFramework } from './types';
/**
* Check if an object is a svelte component.
* @param obj Object
*/
function isSvelteComponent(obj: any) {
return obj.prototype && obj.prototype.$destroy !== undefined;
}
/**
* Handle component loaded with esm or cjs.
* @param obj object
*/
function unWrap(obj: any) {
return obj && obj.default ? obj.default : obj;
}
/**
* Transform a story to be compatible with the PreviewRender component.
*
* - `() => MyComponent` is translated to `() => ({ Component: MyComponent })`
* - `() => ({})` is translated to `() => ({ Component: <from context.component> })`
* - A decorator component is wrapped with SlotDecorator. The decorated component is inject through
* a <slot/>
*
* @param context StoryContext
* @param story the current story
* @param originalStory the story decorated by the current story
*/
function prepareStory(context: StoryContext<SvelteFramework>, story: any, originalStory?: any) {
let result = unWrap(story);
if (isSvelteComponent(result)) {
// wrap the component
result = {
Component: result,
};
}
if (originalStory) {
// inject the new story as a wrapper of the original story
result = {
Component: SlotDecorator,
props: {
decorator: unWrap(result.Component),
decoratorProps: result.props,
component: unWrap(originalStory.Component),
props: originalStory.props,
on: originalStory.on,
},
};
} else {
let cpn = result.Component;
if (!cpn) {
// if the component is not defined, get it the context
cpn = context.component;
}
result.Component = unWrap(cpn);
}
return result;
}
export function decorateStory(storyFn: any, decorators: any[]) {
return decorators.reduce(
(
previousStoryFn: LegacyStoryFn<SvelteFramework>,
decorator: DecoratorFunction<SvelteFramework>
) => (context: StoryContext<SvelteFramework>) => {
let story;
const decoratedStory = decorator((update) => {
story = previousStoryFn({
...context,
...sanitizeStoryContextUpdate(update),
});
return story;
}, context);
if (!story) {
story = previousStoryFn(context);
}
if (!decoratedStory || decoratedStory === story) {
return story;
}
return prepareStory(context, decoratedStory, story);
},
(context: StoryContext<SvelteFramework>) => prepareStory(context, storyFn(context))
);
}