storybook 10.1.0-alpha.9 → 10.1.0-beta.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/_browser-chunks/Color-FTG7SQDA.js +1097 -0
- package/dist/_browser-chunks/WithTooltip-LMROHDUP.js +1651 -0
- package/dist/_browser-chunks/chunk-2FRVAXCZ.js +7 -0
- package/dist/_browser-chunks/{chunk-FDWKXLBI.js → chunk-2XZMBGTA.js} +44 -109
- package/dist/_browser-chunks/chunk-3IAH5M2U.js +171 -0
- package/dist/_browser-chunks/chunk-3OXGAGBE.js +779 -0
- package/dist/_browser-chunks/{chunk-TMDZCWME.js → chunk-3PJE6VLG.js} +1 -3
- package/dist/_browser-chunks/{chunk-VAMFPZY3.js → chunk-45UGUKRX.js} +2 -7
- package/dist/_browser-chunks/chunk-6XWLIJQL.js +11 -0
- package/dist/_browser-chunks/{chunk-MM7DTO55.js → chunk-A242L54C.js} +10 -16
- package/dist/_browser-chunks/chunk-AIOS4NGK.js +252 -0
- package/dist/_browser-chunks/chunk-AS2HQEYC.js +14 -0
- package/dist/_browser-chunks/chunk-AXG2BOBL.js +836 -0
- package/dist/_browser-chunks/{chunk-MH6AXFXB.js → chunk-CHUV5WSW.js} +0 -5
- package/dist/_browser-chunks/chunk-EUVGDK4H.js +93 -0
- package/dist/_browser-chunks/chunk-EZSQOHRI.js +18 -0
- package/dist/_browser-chunks/{chunk-CADGRH3P.js → chunk-FNXWN6IK.js} +3 -8
- package/dist/_browser-chunks/chunk-FQ7SLVLR.js +66 -0
- package/dist/_browser-chunks/chunk-GFLS4VP3.js +64 -0
- package/dist/_browser-chunks/chunk-GFY5R5EY.js +47 -0
- package/dist/_browser-chunks/{chunk-L2D73C6Z.js → chunk-H6XK3RSC.js} +13 -21
- package/dist/_browser-chunks/chunk-IPA5A322.js +71 -0
- package/dist/_browser-chunks/chunk-JP7NCOJX.js +37 -0
- package/dist/_browser-chunks/chunk-KJHJLCBK.js +11 -0
- package/dist/_browser-chunks/{chunk-OWPZQM2D.js → chunk-L4RMQ7D7.js} +60 -110
- package/dist/_browser-chunks/chunk-P4F4UVXX.js +951 -0
- package/dist/_browser-chunks/{chunk-AB7OOPUX.js → chunk-QKODTO7K.js} +0 -5
- package/dist/_browser-chunks/chunk-RP5RXKFU.js +2491 -0
- package/dist/_browser-chunks/chunk-SL75JR6Y.js +9 -0
- package/dist/_browser-chunks/chunk-SS2NHR7W.js +2969 -0
- package/dist/_browser-chunks/chunk-UD6FQLAF.js +1481 -0
- package/dist/_browser-chunks/chunk-VYJQ7RU5.js +2853 -0
- package/dist/_browser-chunks/chunk-WJYERY3R.js +136 -0
- package/dist/_browser-chunks/chunk-XJNX76GA.js +85 -0
- package/dist/_browser-chunks/{chunk-F4Q6SGTB.js → chunk-YKE5S47A.js} +177 -399
- package/dist/_browser-chunks/{chunk-SN4J4IQ3.js → chunk-ZUWEVLDX.js} +1 -7
- package/dist/_browser-chunks/{formatter-OMEEQ6HG.js → formatter-QJ4M4OGQ.js} +4 -9
- package/dist/_browser-chunks/{syntaxhighlighter-CAVLW7PM.js → syntaxhighlighter-IQDEPFLK.js} +704 -1848
- package/dist/_node-chunks/{builder-manager-SM3UWERX.js → builder-manager-BDAQHXFI.js} +510 -1019
- package/dist/_node-chunks/camelcase-3C7DZZPX.js +37 -0
- package/dist/_node-chunks/chunk-2IIQTGNE.js +6024 -0
- package/dist/_node-chunks/chunk-56U5LEMP.js +3043 -0
- package/dist/_node-chunks/chunk-7LIRCAQE.js +20 -0
- package/dist/_node-chunks/chunk-7RN6TXKP.js +603 -0
- package/dist/_node-chunks/chunk-7SJ7PZNL.js +4523 -0
- package/dist/_node-chunks/{chunk-HHSTA6QS.js → chunk-BG4RDXG7.js} +8 -10
- package/dist/_node-chunks/chunk-CBQKMXLQ.js +18 -0
- package/dist/_node-chunks/chunk-CN2IW2KQ.js +1564 -0
- package/dist/_node-chunks/chunk-CQMAU6UQ.js +943 -0
- package/dist/_node-chunks/{chunk-EBUEXRH5.js → chunk-D6ND3TVY.js} +116 -276
- package/dist/_node-chunks/chunk-DC355CYB.js +61 -0
- package/dist/_node-chunks/{chunk-SGM3ZCCT.js → chunk-EVK2SBW5.js} +292 -688
- package/dist/_node-chunks/chunk-IXWEUXJ2.js +119 -0
- package/dist/_node-chunks/{chunk-F6EFOEC7.js → chunk-KVRF22SH.js} +469 -983
- package/dist/_node-chunks/chunk-LEDP4QQW.js +919 -0
- package/dist/_node-chunks/{chunk-GHIBZRKD.js → chunk-MMVV6DGG.js} +8133 -8887
- package/dist/_node-chunks/chunk-O5CGEVRI.js +29 -0
- package/dist/_node-chunks/chunk-OZZO56XN.js +299 -0
- package/dist/_node-chunks/chunk-POT2EVGD.js +78 -0
- package/dist/_node-chunks/chunk-R5YGFSTV.js +3781 -0
- package/dist/_node-chunks/chunk-SQCTM2OS.js +23 -0
- package/dist/_node-chunks/chunk-UFOFO5H7.js +54 -0
- package/dist/_node-chunks/chunk-VBF7ALJF.js +72 -0
- package/dist/_node-chunks/chunk-W6MAMTUF.js +70 -0
- package/dist/_node-chunks/chunk-WURL4XOT.js +46662 -0
- package/dist/_node-chunks/chunk-XGK6MVKR.js +61 -0
- package/dist/_node-chunks/chunk-YV3GDSDT.js +765 -0
- package/dist/_node-chunks/{chunk-ATDHMMIZ.js → chunk-YWV55YW3.js} +15 -24
- package/dist/_node-chunks/dist-KEP4IFRN.js +121 -0
- package/dist/_node-chunks/globby-4WUBTDCN.js +3452 -0
- package/dist/_node-chunks/lib-JVOEKTYM.js +366 -0
- package/dist/_node-chunks/mdx-N42X6CFJ-C5WFYYXR.js +14329 -0
- package/dist/_node-chunks/p-limit-LDY632RS.js +116 -0
- package/dist/actions/decorator.js +21 -42
- package/dist/actions/index.js +3 -3
- package/dist/babel/index.d.ts +671 -335
- package/dist/babel/index.js +10 -11
- package/dist/bin/core.js +601 -1548
- package/dist/bin/dispatcher.js +36 -36
- package/dist/bin/loader.js +24 -38
- package/dist/channels/index.js +98 -234
- package/dist/cli/index.d.ts +1479 -133
- package/dist/cli/index.js +30 -8540
- package/dist/client-logger/index.js +31 -61
- package/dist/common/index.d.ts +139 -62
- package/dist/common/index.js +66 -51
- package/dist/components/index.d.ts +575 -273
- package/dist/components/index.js +14863 -4313
- package/dist/core-events/index.js +2 -66
- package/dist/core-server/index.d.ts +3 -2
- package/dist/core-server/index.js +2908 -8518
- package/dist/core-server/presets/common-manager.css +2 -2
- package/dist/core-server/presets/common-manager.js +2521 -5233
- package/dist/core-server/presets/common-override-preset.js +31 -60
- package/dist/core-server/presets/common-preset.js +663 -962
- package/dist/csf/index.js +534 -1179
- package/dist/csf-tools/index.js +9 -9
- package/dist/docs-tools/index.js +6 -6
- package/dist/highlight/index.js +2 -2
- package/dist/instrumenter/index.js +199 -415
- package/dist/manager/globals-runtime.js +59044 -67141
- package/dist/manager/globals.js +2 -3
- package/dist/manager/manager-stores.d.ts +1 -0
- package/dist/manager/manager-stores.js +23 -0
- package/dist/manager/runtime.js +11511 -10953
- package/dist/manager-api/index.d.ts +1811 -2
- package/dist/manager-api/index.js +1348 -2401
- package/dist/manager-errors.d.ts +9 -0
- package/dist/manager-errors.js +3 -3
- package/dist/mocking-utils/index.d.ts +1126 -0
- package/dist/mocking-utils/index.js +1181 -0
- package/dist/node-logger/index.d.ts +192 -24
- package/dist/node-logger/index.js +23 -4471
- package/dist/preview/globals.js +2 -3
- package/dist/preview/runtime.js +10799 -22393
- package/dist/preview-api/index.d.ts +68 -69
- package/dist/preview-api/index.js +13 -13
- package/dist/preview-errors.d.ts +9 -0
- package/dist/preview-errors.js +4 -4
- package/dist/router/index.js +347 -899
- package/dist/server-errors.d.ts +34 -1
- package/dist/server-errors.js +17 -10
- package/dist/telemetry/index.d.ts +24 -3
- package/dist/telemetry/index.js +25 -24
- package/dist/test/index.js +6131 -11916
- package/dist/theming/create.d.ts +1 -0
- package/dist/theming/create.js +4 -4
- package/dist/theming/index.d.ts +3366 -2599
- package/dist/theming/index.js +501 -1091
- package/dist/types/index.d.ts +72 -8
- package/dist/types/index.js +27 -12
- package/dist/viewport/index.js +3 -3
- package/package.json +26 -17
- package/dist/_browser-chunks/Color-7ZNS6F6B.js +0 -1676
- package/dist/_browser-chunks/WithTooltip-SK46ZJ2J.js +0 -13
- package/dist/_browser-chunks/chunk-6A7OIVEL.js +0 -66
- package/dist/_browser-chunks/chunk-B4A3ADP3.js +0 -3816
- package/dist/_browser-chunks/chunk-BOOOPFZF.js +0 -2335
- package/dist/_browser-chunks/chunk-FSBVR7H5.js +0 -106
- package/dist/_browser-chunks/chunk-FUOHXXZT.js +0 -23
- package/dist/_browser-chunks/chunk-GTKOCWCT.js +0 -17
- package/dist/_browser-chunks/chunk-HHW4FUMO.js +0 -12
- package/dist/_browser-chunks/chunk-JVSKG4YS.js +0 -4052
- package/dist/_browser-chunks/chunk-LASUB7TL.js +0 -76
- package/dist/_browser-chunks/chunk-LYCSRYYR.js +0 -101
- package/dist/_browser-chunks/chunk-NVV6MIOE.js +0 -243
- package/dist/_browser-chunks/chunk-OBXWFEPB.js +0 -852
- package/dist/_browser-chunks/chunk-OPCDBBL3.js +0 -48
- package/dist/_browser-chunks/chunk-PB6FZ3WE.js +0 -130
- package/dist/_browser-chunks/chunk-RNE2IUTB.js +0 -1300
- package/dist/_browser-chunks/chunk-RW5PKMWM.js +0 -4182
- package/dist/_browser-chunks/chunk-SYS437NN.js +0 -122
- package/dist/_browser-chunks/chunk-U46RQHA4.js +0 -12
- package/dist/_browser-chunks/chunk-UTNZYD2N.js +0 -311
- package/dist/_browser-chunks/chunk-VUAFL5XK.js +0 -20
- package/dist/_browser-chunks/chunk-XDGMHOV7.js +0 -2197
- package/dist/_browser-chunks/chunk-XW6KSYKF.js +0 -16
- package/dist/_browser-chunks/chunk-Y3M7TW6K.js +0 -1041
- package/dist/_browser-chunks/chunk-ZNRFDIVA.js +0 -233
- package/dist/_node-chunks/camelcase-H5QSGQLK.js +0 -18
- package/dist/_node-chunks/chunk-3THWHQOC.js +0 -61
- package/dist/_node-chunks/chunk-45YUOLTU.js +0 -69
- package/dist/_node-chunks/chunk-4QSNCPAU.js +0 -64656
- package/dist/_node-chunks/chunk-744PQSOU.js +0 -79
- package/dist/_node-chunks/chunk-74Z2U7QG.js +0 -1544
- package/dist/_node-chunks/chunk-7MB7TFPO.js +0 -1198
- package/dist/_node-chunks/chunk-A7GS4RFT.js +0 -697
- package/dist/_node-chunks/chunk-BIA3A5UM.js +0 -61
- package/dist/_node-chunks/chunk-C5G7CLWX.js +0 -1657
- package/dist/_node-chunks/chunk-DLFUKMYJ.js +0 -1531
- package/dist/_node-chunks/chunk-EMRGRXKT.js +0 -111
- package/dist/_node-chunks/chunk-EX46EHHY.js +0 -420
- package/dist/_node-chunks/chunk-F76QKNOJ.js +0 -304
- package/dist/_node-chunks/chunk-HDCRUTEF.js +0 -220
- package/dist/_node-chunks/chunk-HUYAOIPH.js +0 -90
- package/dist/_node-chunks/chunk-IBJZQZJC.js +0 -101
- package/dist/_node-chunks/chunk-KZN2RDDT.js +0 -6712
- package/dist/_node-chunks/chunk-LYUNFU3F.js +0 -4741
- package/dist/_node-chunks/chunk-N44SIS6K.js +0 -28
- package/dist/_node-chunks/chunk-NILZM6KR.js +0 -18
- package/dist/_node-chunks/chunk-PC4ZRP6W.js +0 -34
- package/dist/_node-chunks/chunk-TJNGOQUH.js +0 -4272
- package/dist/_node-chunks/chunk-UBSYLHIL.js +0 -1250
- package/dist/_node-chunks/chunk-UTCLXPOC.js +0 -1518
- package/dist/_node-chunks/chunk-WOXXODXP.js +0 -5029
- package/dist/_node-chunks/chunk-XC4MEUA6.js +0 -1586
- package/dist/_node-chunks/chunk-YRXXMKRR.js +0 -2256
- package/dist/_node-chunks/dist-SL73W244.js +0 -175
- package/dist/_node-chunks/globby-ZSHAUQZ5.js +0 -5222
- package/dist/_node-chunks/lib-U2VIPUTI.js +0 -518
- package/dist/_node-chunks/mdx-N42X6CFJ-ZLHD33JK.js +0 -22017
- package/dist/_node-chunks/p-limit-K5BS5MSV.js +0 -168
- package/dist/_node-chunks/plugin-5PD4YIUH.js +0 -129
- package/dist/_node-chunks/plugin-MONDT2WL.js +0 -159
- package/dist/_node-chunks/webpack-inject-mocker-runtime-plugin-EUZJRG3W.js +0 -69102
- package/dist/_node-chunks/webpack-mock-plugin-T4LDXEHE.js +0 -124
- package/dist/core-server/presets/webpack/loaders/storybook-mock-transform-loader.js +0 -36
- package/dist/core-server/presets/webpack/loaders/webpack-automock-loader.js +0 -33
|
@@ -0,0 +1,2969 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isTestEnvironment,
|
|
3
|
+
pauseAnimations,
|
|
4
|
+
waitForAnimations
|
|
5
|
+
} from "./chunk-IPA5A322.js";
|
|
6
|
+
import {
|
|
7
|
+
require_main
|
|
8
|
+
} from "./chunk-3OXGAGBE.js";
|
|
9
|
+
import {
|
|
10
|
+
SNIPPET_RENDERED,
|
|
11
|
+
combineParameters
|
|
12
|
+
} from "./chunk-VYJQ7RU5.js";
|
|
13
|
+
import {
|
|
14
|
+
isEqual
|
|
15
|
+
} from "./chunk-3IAH5M2U.js";
|
|
16
|
+
import {
|
|
17
|
+
invariant
|
|
18
|
+
} from "./chunk-AS2HQEYC.js";
|
|
19
|
+
import {
|
|
20
|
+
require_ansi_to_html
|
|
21
|
+
} from "./chunk-YKE5S47A.js";
|
|
22
|
+
import {
|
|
23
|
+
mapValues,
|
|
24
|
+
pickBy
|
|
25
|
+
} from "./chunk-AIOS4NGK.js";
|
|
26
|
+
import {
|
|
27
|
+
isPlainObject
|
|
28
|
+
} from "./chunk-GFLS4VP3.js";
|
|
29
|
+
import {
|
|
30
|
+
require_memoizerific
|
|
31
|
+
} from "./chunk-WJYERY3R.js";
|
|
32
|
+
import {
|
|
33
|
+
dedent
|
|
34
|
+
} from "./chunk-JP7NCOJX.js";
|
|
35
|
+
import {
|
|
36
|
+
__toESM
|
|
37
|
+
} from "./chunk-A242L54C.js";
|
|
38
|
+
|
|
39
|
+
// src/preview-api/modules/addons/main.ts
|
|
40
|
+
import { global } from "@storybook/global";
|
|
41
|
+
|
|
42
|
+
// src/preview-api/modules/addons/storybook-channel-mock.ts
|
|
43
|
+
import { Channel } from "storybook/internal/channels";
|
|
44
|
+
function mockChannel() {
|
|
45
|
+
let transport = {
|
|
46
|
+
setHandler: () => {
|
|
47
|
+
},
|
|
48
|
+
send: () => {
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
return new Channel({ transport });
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// src/preview-api/modules/addons/main.ts
|
|
55
|
+
var AddonStore = class {
|
|
56
|
+
constructor() {
|
|
57
|
+
this.getChannel = () => {
|
|
58
|
+
if (!this.channel) {
|
|
59
|
+
let channel = mockChannel();
|
|
60
|
+
return this.setChannel(channel), channel;
|
|
61
|
+
}
|
|
62
|
+
return this.channel;
|
|
63
|
+
};
|
|
64
|
+
this.ready = () => this.promise;
|
|
65
|
+
this.hasChannel = () => !!this.channel;
|
|
66
|
+
this.setChannel = (channel) => {
|
|
67
|
+
this.channel = channel, this.resolve();
|
|
68
|
+
};
|
|
69
|
+
this.promise = new Promise((res) => {
|
|
70
|
+
this.resolve = () => res(this.getChannel());
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}, KEY = "__STORYBOOK_ADDONS_PREVIEW";
|
|
74
|
+
function getAddonsStore() {
|
|
75
|
+
return global[KEY] || (global[KEY] = new AddonStore()), global[KEY];
|
|
76
|
+
}
|
|
77
|
+
var addons = getAddonsStore();
|
|
78
|
+
|
|
79
|
+
// src/preview-api/modules/addons/hooks.ts
|
|
80
|
+
import { logger } from "storybook/internal/client-logger";
|
|
81
|
+
import {
|
|
82
|
+
FORCE_RE_RENDER,
|
|
83
|
+
RESET_STORY_ARGS,
|
|
84
|
+
STORY_RENDERED,
|
|
85
|
+
UPDATE_GLOBALS,
|
|
86
|
+
UPDATE_STORY_ARGS
|
|
87
|
+
} from "storybook/internal/core-events";
|
|
88
|
+
import { global as global2 } from "@storybook/global";
|
|
89
|
+
var HooksContext = class {
|
|
90
|
+
constructor() {
|
|
91
|
+
this.hookListsMap = void 0;
|
|
92
|
+
this.mountedDecorators = void 0;
|
|
93
|
+
this.prevMountedDecorators = void 0;
|
|
94
|
+
this.currentHooks = void 0;
|
|
95
|
+
this.nextHookIndex = void 0;
|
|
96
|
+
this.currentPhase = void 0;
|
|
97
|
+
this.currentEffects = void 0;
|
|
98
|
+
this.prevEffects = void 0;
|
|
99
|
+
this.currentDecoratorName = void 0;
|
|
100
|
+
this.hasUpdates = void 0;
|
|
101
|
+
this.currentContext = void 0;
|
|
102
|
+
this.renderListener = (storyId) => {
|
|
103
|
+
storyId === this.currentContext?.id && (this.triggerEffects(), this.currentContext = null, this.removeRenderListeners());
|
|
104
|
+
};
|
|
105
|
+
this.init();
|
|
106
|
+
}
|
|
107
|
+
init() {
|
|
108
|
+
this.hookListsMap = /* @__PURE__ */ new WeakMap(), this.mountedDecorators = /* @__PURE__ */ new Set(), this.prevMountedDecorators = /* @__PURE__ */ new Set(), this.currentHooks = [], this.nextHookIndex = 0, this.currentPhase = "NONE", this.currentEffects = [], this.prevEffects = [], this.currentDecoratorName = null, this.hasUpdates = !1, this.currentContext = null;
|
|
109
|
+
}
|
|
110
|
+
clean() {
|
|
111
|
+
this.prevEffects.forEach((effect) => {
|
|
112
|
+
effect.destroy && effect.destroy();
|
|
113
|
+
}), this.init(), this.removeRenderListeners();
|
|
114
|
+
}
|
|
115
|
+
getNextHook() {
|
|
116
|
+
let hook = this.currentHooks[this.nextHookIndex];
|
|
117
|
+
return this.nextHookIndex += 1, hook;
|
|
118
|
+
}
|
|
119
|
+
triggerEffects() {
|
|
120
|
+
this.prevEffects.forEach((effect) => {
|
|
121
|
+
!this.currentEffects.includes(effect) && effect.destroy && effect.destroy();
|
|
122
|
+
}), this.currentEffects.forEach((effect) => {
|
|
123
|
+
this.prevEffects.includes(effect) || (effect.destroy = effect.create());
|
|
124
|
+
}), this.prevEffects = this.currentEffects, this.currentEffects = [];
|
|
125
|
+
}
|
|
126
|
+
addRenderListeners() {
|
|
127
|
+
this.removeRenderListeners(), addons.getChannel().on(STORY_RENDERED, this.renderListener);
|
|
128
|
+
}
|
|
129
|
+
removeRenderListeners() {
|
|
130
|
+
addons.getChannel().removeListener(STORY_RENDERED, this.renderListener);
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
function hookify(fn) {
|
|
134
|
+
let hookified = (...args) => {
|
|
135
|
+
let { hooks } = typeof args[0] == "function" ? args[1] : args[0], prevPhase = hooks.currentPhase, prevHooks = hooks.currentHooks, prevNextHookIndex = hooks.nextHookIndex, prevDecoratorName = hooks.currentDecoratorName;
|
|
136
|
+
hooks.currentDecoratorName = fn.name, hooks.prevMountedDecorators.has(fn) ? (hooks.currentPhase = "UPDATE", hooks.currentHooks = hooks.hookListsMap.get(fn) || []) : (hooks.currentPhase = "MOUNT", hooks.currentHooks = [], hooks.hookListsMap.set(fn, hooks.currentHooks), hooks.prevMountedDecorators.add(fn)), hooks.nextHookIndex = 0;
|
|
137
|
+
let prevContext = global2.STORYBOOK_HOOKS_CONTEXT;
|
|
138
|
+
global2.STORYBOOK_HOOKS_CONTEXT = hooks;
|
|
139
|
+
let result = fn(...args);
|
|
140
|
+
if (global2.STORYBOOK_HOOKS_CONTEXT = prevContext, hooks.currentPhase === "UPDATE" && hooks.getNextHook() != null)
|
|
141
|
+
throw new Error(
|
|
142
|
+
"Rendered fewer hooks than expected. This may be caused by an accidental early return statement."
|
|
143
|
+
);
|
|
144
|
+
return hooks.currentPhase = prevPhase, hooks.currentHooks = prevHooks, hooks.nextHookIndex = prevNextHookIndex, hooks.currentDecoratorName = prevDecoratorName, result;
|
|
145
|
+
};
|
|
146
|
+
return hookified.originalFn = fn, hookified;
|
|
147
|
+
}
|
|
148
|
+
var numberOfRenders = 0, RENDER_LIMIT = 25, applyHooks = (applyDecorators) => (storyFn, decorators) => {
|
|
149
|
+
let decorated = applyDecorators(
|
|
150
|
+
hookify(storyFn),
|
|
151
|
+
decorators.map((decorator) => hookify(decorator))
|
|
152
|
+
);
|
|
153
|
+
return (context) => {
|
|
154
|
+
let { hooks } = context;
|
|
155
|
+
hooks.prevMountedDecorators ??= /* @__PURE__ */ new Set(), hooks.mountedDecorators = /* @__PURE__ */ new Set([storyFn, ...decorators]), hooks.currentContext = context, hooks.hasUpdates = !1;
|
|
156
|
+
let result = decorated(context);
|
|
157
|
+
for (numberOfRenders = 1; hooks.hasUpdates; )
|
|
158
|
+
if (hooks.hasUpdates = !1, hooks.currentEffects = [], result = decorated(context), numberOfRenders += 1, numberOfRenders > RENDER_LIMIT)
|
|
159
|
+
throw new Error(
|
|
160
|
+
"Too many re-renders. Storybook limits the number of renders to prevent an infinite loop."
|
|
161
|
+
);
|
|
162
|
+
return hooks.addRenderListeners(), result;
|
|
163
|
+
};
|
|
164
|
+
}, areDepsEqual = (deps, nextDeps) => deps.length === nextDeps.length && deps.every((dep, i) => dep === nextDeps[i]), invalidHooksError = () => new Error("Storybook preview hooks can only be called inside decorators and story functions.");
|
|
165
|
+
function getHooksContextOrNull() {
|
|
166
|
+
return global2.STORYBOOK_HOOKS_CONTEXT || null;
|
|
167
|
+
}
|
|
168
|
+
function getHooksContextOrThrow() {
|
|
169
|
+
let hooks = getHooksContextOrNull();
|
|
170
|
+
if (hooks == null)
|
|
171
|
+
throw invalidHooksError();
|
|
172
|
+
return hooks;
|
|
173
|
+
}
|
|
174
|
+
function useHook(name, callback, deps) {
|
|
175
|
+
let hooks = getHooksContextOrThrow();
|
|
176
|
+
if (hooks.currentPhase === "MOUNT") {
|
|
177
|
+
deps != null && !Array.isArray(deps) && logger.warn(
|
|
178
|
+
`${name} received a final argument that is not an array (instead, received ${deps}). When specified, the final argument must be an array.`
|
|
179
|
+
);
|
|
180
|
+
let hook = { name, deps };
|
|
181
|
+
return hooks.currentHooks.push(hook), callback(hook), hook;
|
|
182
|
+
}
|
|
183
|
+
if (hooks.currentPhase === "UPDATE") {
|
|
184
|
+
let hook = hooks.getNextHook();
|
|
185
|
+
if (hook == null)
|
|
186
|
+
throw new Error("Rendered more hooks than during the previous render.");
|
|
187
|
+
return hook.name !== name && logger.warn(
|
|
188
|
+
`Storybook has detected a change in the order of Hooks${hooks.currentDecoratorName ? ` called by ${hooks.currentDecoratorName}` : ""}. This will lead to bugs and errors if not fixed.`
|
|
189
|
+
), deps != null && hook.deps == null && logger.warn(
|
|
190
|
+
`${name} received a final argument during this render, but not during the previous render. Even though the final argument is optional, its type cannot change between renders.`
|
|
191
|
+
), deps != null && hook.deps != null && deps.length !== hook.deps.length && logger.warn(`The final argument passed to ${name} changed size between renders. The order and size of this array must remain constant.
|
|
192
|
+
Previous: ${hook.deps}
|
|
193
|
+
Incoming: ${deps}`), (deps == null || hook.deps == null || !areDepsEqual(deps, hook.deps)) && (callback(hook), hook.deps = deps), hook;
|
|
194
|
+
}
|
|
195
|
+
throw invalidHooksError();
|
|
196
|
+
}
|
|
197
|
+
function useMemoLike(name, nextCreate, deps) {
|
|
198
|
+
let { memoizedState } = useHook(
|
|
199
|
+
name,
|
|
200
|
+
(hook) => {
|
|
201
|
+
hook.memoizedState = nextCreate();
|
|
202
|
+
},
|
|
203
|
+
deps
|
|
204
|
+
);
|
|
205
|
+
return memoizedState;
|
|
206
|
+
}
|
|
207
|
+
function useMemo(nextCreate, deps) {
|
|
208
|
+
return useMemoLike("useMemo", nextCreate, deps);
|
|
209
|
+
}
|
|
210
|
+
function useCallback(callback, deps) {
|
|
211
|
+
return useMemoLike("useCallback", () => callback, deps);
|
|
212
|
+
}
|
|
213
|
+
function useRefLike(name, initialValue) {
|
|
214
|
+
return useMemoLike(name, () => ({ current: initialValue }), []);
|
|
215
|
+
}
|
|
216
|
+
function useRef(initialValue) {
|
|
217
|
+
return useRefLike("useRef", initialValue);
|
|
218
|
+
}
|
|
219
|
+
function triggerUpdate() {
|
|
220
|
+
let hooks = getHooksContextOrNull();
|
|
221
|
+
if (hooks != null && hooks.currentPhase !== "NONE")
|
|
222
|
+
hooks.hasUpdates = !0;
|
|
223
|
+
else
|
|
224
|
+
try {
|
|
225
|
+
addons.getChannel().emit(FORCE_RE_RENDER);
|
|
226
|
+
} catch {
|
|
227
|
+
logger.warn("State updates of Storybook preview hooks work only in browser");
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
function useStateLike(name, initialState) {
|
|
231
|
+
let stateRef = useRefLike(
|
|
232
|
+
name,
|
|
233
|
+
// @ts-expect-error S type should never be function, but there's no way to tell that to TypeScript
|
|
234
|
+
typeof initialState == "function" ? initialState() : initialState
|
|
235
|
+
), setState = (update) => {
|
|
236
|
+
stateRef.current = typeof update == "function" ? update(stateRef.current) : update, triggerUpdate();
|
|
237
|
+
};
|
|
238
|
+
return [stateRef.current, setState];
|
|
239
|
+
}
|
|
240
|
+
function useState(initialState) {
|
|
241
|
+
return useStateLike("useState", initialState);
|
|
242
|
+
}
|
|
243
|
+
function useReducer(reducer, initialArg, init) {
|
|
244
|
+
let initialState = init != null ? () => init(initialArg) : initialArg, [state, setState] = useStateLike("useReducer", initialState);
|
|
245
|
+
return [state, (action) => setState((prevState) => reducer(prevState, action))];
|
|
246
|
+
}
|
|
247
|
+
function useEffect(create, deps) {
|
|
248
|
+
let hooks = getHooksContextOrThrow(), effect = useMemoLike("useEffect", () => ({ create }), deps);
|
|
249
|
+
hooks.currentEffects.includes(effect) || hooks.currentEffects.push(effect);
|
|
250
|
+
}
|
|
251
|
+
function useChannel(eventMap, deps = []) {
|
|
252
|
+
let channel = addons.getChannel();
|
|
253
|
+
return useEffect(() => (Object.entries(eventMap).forEach(([type, listener]) => channel.on(type, listener)), () => {
|
|
254
|
+
Object.entries(eventMap).forEach(
|
|
255
|
+
([type, listener]) => channel.removeListener(type, listener)
|
|
256
|
+
);
|
|
257
|
+
}), [...Object.keys(eventMap), ...deps]), useCallback(channel.emit.bind(channel), [channel]);
|
|
258
|
+
}
|
|
259
|
+
function useStoryContext() {
|
|
260
|
+
let { currentContext } = getHooksContextOrThrow();
|
|
261
|
+
if (currentContext == null)
|
|
262
|
+
throw invalidHooksError();
|
|
263
|
+
return currentContext;
|
|
264
|
+
}
|
|
265
|
+
function useParameter(parameterKey, defaultValue) {
|
|
266
|
+
let { parameters } = useStoryContext();
|
|
267
|
+
if (parameterKey)
|
|
268
|
+
return parameters[parameterKey] ?? defaultValue;
|
|
269
|
+
}
|
|
270
|
+
function useArgs() {
|
|
271
|
+
let channel = addons.getChannel(), { id: storyId, args } = useStoryContext(), updateArgs = useCallback(
|
|
272
|
+
(updatedArgs) => channel.emit(UPDATE_STORY_ARGS, { storyId, updatedArgs }),
|
|
273
|
+
[channel, storyId]
|
|
274
|
+
), resetArgs = useCallback(
|
|
275
|
+
(argNames) => channel.emit(RESET_STORY_ARGS, { storyId, argNames }),
|
|
276
|
+
[channel, storyId]
|
|
277
|
+
);
|
|
278
|
+
return [args, updateArgs, resetArgs];
|
|
279
|
+
}
|
|
280
|
+
function useGlobals() {
|
|
281
|
+
let channel = addons.getChannel(), { globals } = useStoryContext(), updateGlobals = useCallback(
|
|
282
|
+
(newGlobals) => channel.emit(UPDATE_GLOBALS, { globals: newGlobals }),
|
|
283
|
+
[channel]
|
|
284
|
+
);
|
|
285
|
+
return [globals, updateGlobals];
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/preview-api/modules/addons/make-decorator.ts
|
|
289
|
+
var makeDecorator = ({
|
|
290
|
+
name,
|
|
291
|
+
parameterName,
|
|
292
|
+
wrapper,
|
|
293
|
+
skipIfNoParametersOrOptions = !1
|
|
294
|
+
}) => {
|
|
295
|
+
let decorator = (options) => (storyFn, context) => {
|
|
296
|
+
let parameters = context.parameters && context.parameters[parameterName];
|
|
297
|
+
return parameters && parameters.disable || skipIfNoParametersOrOptions && !options && !parameters ? storyFn(context) : wrapper(storyFn, context, {
|
|
298
|
+
options,
|
|
299
|
+
parameters
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
return (...args) => typeof args[0] == "function" ? decorator()(...args) : (...innerArgs) => {
|
|
303
|
+
if (innerArgs.length > 1)
|
|
304
|
+
return args.length > 1 ? decorator(args)(...innerArgs) : decorator(...args)(...innerArgs);
|
|
305
|
+
throw new Error(
|
|
306
|
+
`Passing stories directly into ${name}() is not allowed,
|
|
307
|
+
instead use addDecorator(${name}) and pass options with the '${parameterName}' parameter`
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
|
|
312
|
+
// src/preview-api/modules/store/StoryStore.ts
|
|
313
|
+
import { getCoreAnnotations as getCoreAnnotations2 } from "storybook/internal/csf";
|
|
314
|
+
import {
|
|
315
|
+
CalledExtractOnStoreError,
|
|
316
|
+
MissingStoryFromCsfFileError
|
|
317
|
+
} from "storybook/internal/preview-errors";
|
|
318
|
+
var import_memoizerific2 = __toESM(require_memoizerific(), 1);
|
|
319
|
+
|
|
320
|
+
// src/preview-api/modules/store/args.ts
|
|
321
|
+
import { once } from "storybook/internal/client-logger";
|
|
322
|
+
var INCOMPATIBLE = Symbol("incompatible"), map = (arg, argType) => {
|
|
323
|
+
let type = argType.type;
|
|
324
|
+
if (arg == null || !type || argType.mapping)
|
|
325
|
+
return arg;
|
|
326
|
+
switch (type.name) {
|
|
327
|
+
case "string":
|
|
328
|
+
return String(arg);
|
|
329
|
+
case "enum":
|
|
330
|
+
return arg;
|
|
331
|
+
case "number":
|
|
332
|
+
return Number(arg);
|
|
333
|
+
case "boolean":
|
|
334
|
+
return String(arg) === "true";
|
|
335
|
+
case "array":
|
|
336
|
+
return !type.value || !Array.isArray(arg) ? INCOMPATIBLE : arg.reduce((acc, item, index) => {
|
|
337
|
+
let mapped = map(item, { type: type.value });
|
|
338
|
+
return mapped !== INCOMPATIBLE && (acc[index] = mapped), acc;
|
|
339
|
+
}, new Array(arg.length));
|
|
340
|
+
case "object":
|
|
341
|
+
return typeof arg == "string" || typeof arg == "number" ? arg : !type.value || typeof arg != "object" ? INCOMPATIBLE : Object.entries(arg).reduce((acc, [key, val]) => {
|
|
342
|
+
let mapped = map(val, { type: type.value[key] });
|
|
343
|
+
return mapped === INCOMPATIBLE ? acc : Object.assign(acc, { [key]: mapped });
|
|
344
|
+
}, {});
|
|
345
|
+
case "other": {
|
|
346
|
+
let isPrimitiveArg = typeof arg == "string" || typeof arg == "number" || typeof arg == "boolean";
|
|
347
|
+
return type.value === "ReactNode" && isPrimitiveArg ? arg : INCOMPATIBLE;
|
|
348
|
+
}
|
|
349
|
+
default:
|
|
350
|
+
return INCOMPATIBLE;
|
|
351
|
+
}
|
|
352
|
+
}, mapArgsToTypes = (args, argTypes) => Object.entries(args).reduce((acc, [key, value]) => {
|
|
353
|
+
if (!argTypes[key])
|
|
354
|
+
return acc;
|
|
355
|
+
let mapped = map(value, argTypes[key]);
|
|
356
|
+
return mapped === INCOMPATIBLE ? acc : Object.assign(acc, { [key]: mapped });
|
|
357
|
+
}, {}), combineArgs = (value, update) => Array.isArray(value) && Array.isArray(update) ? update.reduce(
|
|
358
|
+
(acc, upd, index) => (acc[index] = combineArgs(value[index], update[index]), acc),
|
|
359
|
+
[...value]
|
|
360
|
+
).filter((v) => v !== void 0) : !isPlainObject(value) || !isPlainObject(update) ? update : Object.keys({ ...value, ...update }).reduce((acc, key) => {
|
|
361
|
+
if (key in update) {
|
|
362
|
+
let combined = combineArgs(value[key], update[key]);
|
|
363
|
+
combined !== void 0 && (acc[key] = combined);
|
|
364
|
+
} else
|
|
365
|
+
acc[key] = value[key];
|
|
366
|
+
return acc;
|
|
367
|
+
}, {}), validateOptions = (args, argTypes) => Object.entries(argTypes).reduce((acc, [key, { options }]) => {
|
|
368
|
+
function allowArg() {
|
|
369
|
+
return key in args && (acc[key] = args[key]), acc;
|
|
370
|
+
}
|
|
371
|
+
if (!options)
|
|
372
|
+
return allowArg();
|
|
373
|
+
if (!Array.isArray(options))
|
|
374
|
+
return once.error(dedent`
|
|
375
|
+
Invalid argType: '${key}.options' should be an array.
|
|
376
|
+
|
|
377
|
+
More info: https://storybook.js.org/docs/api/arg-types?ref=error
|
|
378
|
+
`), allowArg();
|
|
379
|
+
if (options.some((opt) => opt && ["object", "function"].includes(typeof opt)))
|
|
380
|
+
return once.error(dedent`
|
|
381
|
+
Invalid argType: '${key}.options' should only contain primitives. Use a 'mapping' for complex values.
|
|
382
|
+
|
|
383
|
+
More info: https://storybook.js.org/docs/writing-stories/args?ref=error#mapping-to-complex-arg-values
|
|
384
|
+
`), allowArg();
|
|
385
|
+
let isArray = Array.isArray(args[key]), invalidIndex = isArray && args[key].findIndex((val) => !options.includes(val)), isValidArray = isArray && invalidIndex === -1;
|
|
386
|
+
if (args[key] === void 0 || options.includes(args[key]) || isValidArray)
|
|
387
|
+
return allowArg();
|
|
388
|
+
let field = isArray ? `${key}[${invalidIndex}]` : key, supportedOptions = options.map((opt) => typeof opt == "string" ? `'${opt}'` : String(opt)).join(", ");
|
|
389
|
+
return once.warn(`Received illegal value for '${field}'. Supported options: ${supportedOptions}`), acc;
|
|
390
|
+
}, {}), DEEPLY_EQUAL = Symbol("Deeply equal"), deepDiff = (value, update) => {
|
|
391
|
+
if (typeof value != typeof update)
|
|
392
|
+
return update;
|
|
393
|
+
if (isEqual(value, update))
|
|
394
|
+
return DEEPLY_EQUAL;
|
|
395
|
+
if (Array.isArray(value) && Array.isArray(update)) {
|
|
396
|
+
let res = update.reduce((acc, upd, index) => {
|
|
397
|
+
let diff = deepDiff(value[index], upd);
|
|
398
|
+
return diff !== DEEPLY_EQUAL && (acc[index] = diff), acc;
|
|
399
|
+
}, new Array(update.length));
|
|
400
|
+
return update.length >= value.length ? res : res.concat(new Array(value.length - update.length).fill(void 0));
|
|
401
|
+
}
|
|
402
|
+
return isPlainObject(value) && isPlainObject(update) ? Object.keys({ ...value, ...update }).reduce((acc, key) => {
|
|
403
|
+
let diff = deepDiff(value?.[key], update?.[key]);
|
|
404
|
+
return diff === DEEPLY_EQUAL ? acc : Object.assign(acc, { [key]: diff });
|
|
405
|
+
}, {}) : update;
|
|
406
|
+
}, UNTARGETED = "UNTARGETED";
|
|
407
|
+
function groupArgsByTarget({
|
|
408
|
+
args,
|
|
409
|
+
argTypes
|
|
410
|
+
}) {
|
|
411
|
+
let groupedArgs = {};
|
|
412
|
+
return Object.entries(args).forEach(([name, value]) => {
|
|
413
|
+
let { target = UNTARGETED } = argTypes[name] || {};
|
|
414
|
+
groupedArgs[target] = groupedArgs[target] || {}, groupedArgs[target][name] = value;
|
|
415
|
+
}), groupedArgs;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
// src/preview-api/modules/store/ArgsStore.ts
|
|
419
|
+
function deleteUndefined(obj) {
|
|
420
|
+
return Object.keys(obj).forEach((key) => obj[key] === void 0 && delete obj[key]), obj;
|
|
421
|
+
}
|
|
422
|
+
var ArgsStore = class {
|
|
423
|
+
constructor() {
|
|
424
|
+
this.initialArgsByStoryId = {};
|
|
425
|
+
this.argsByStoryId = {};
|
|
426
|
+
}
|
|
427
|
+
get(storyId) {
|
|
428
|
+
if (!(storyId in this.argsByStoryId))
|
|
429
|
+
throw new Error(`No args known for ${storyId} -- has it been rendered yet?`);
|
|
430
|
+
return this.argsByStoryId[storyId];
|
|
431
|
+
}
|
|
432
|
+
setInitial(story) {
|
|
433
|
+
if (!this.initialArgsByStoryId[story.id])
|
|
434
|
+
this.initialArgsByStoryId[story.id] = story.initialArgs, this.argsByStoryId[story.id] = story.initialArgs;
|
|
435
|
+
else if (this.initialArgsByStoryId[story.id] !== story.initialArgs) {
|
|
436
|
+
let delta = deepDiff(this.initialArgsByStoryId[story.id], this.argsByStoryId[story.id]);
|
|
437
|
+
this.initialArgsByStoryId[story.id] = story.initialArgs, this.argsByStoryId[story.id] = story.initialArgs, delta !== DEEPLY_EQUAL && this.updateFromDelta(story, delta);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
updateFromDelta(story, delta) {
|
|
441
|
+
let validatedDelta = validateOptions(delta, story.argTypes);
|
|
442
|
+
this.argsByStoryId[story.id] = combineArgs(this.argsByStoryId[story.id], validatedDelta);
|
|
443
|
+
}
|
|
444
|
+
updateFromPersisted(story, persisted) {
|
|
445
|
+
let mappedPersisted = mapArgsToTypes(persisted, story.argTypes);
|
|
446
|
+
return this.updateFromDelta(story, mappedPersisted);
|
|
447
|
+
}
|
|
448
|
+
update(storyId, argsUpdate) {
|
|
449
|
+
if (!(storyId in this.argsByStoryId))
|
|
450
|
+
throw new Error(`No args known for ${storyId} -- has it been rendered yet?`);
|
|
451
|
+
this.argsByStoryId[storyId] = deleteUndefined({
|
|
452
|
+
...this.argsByStoryId[storyId],
|
|
453
|
+
...argsUpdate
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
// src/preview-api/modules/store/GlobalsStore.ts
|
|
459
|
+
import { logger as logger2 } from "storybook/internal/client-logger";
|
|
460
|
+
|
|
461
|
+
// src/preview-api/modules/store/csf/getValuesFromArgTypes.ts
|
|
462
|
+
var getValuesFromArgTypes = (argTypes = {}) => Object.entries(argTypes).reduce((acc, [arg, { defaultValue }]) => (typeof defaultValue < "u" && (acc[arg] = defaultValue), acc), {});
|
|
463
|
+
|
|
464
|
+
// src/preview-api/modules/store/GlobalsStore.ts
|
|
465
|
+
var GlobalsStore = class {
|
|
466
|
+
constructor({
|
|
467
|
+
globals = {},
|
|
468
|
+
globalTypes = {}
|
|
469
|
+
}) {
|
|
470
|
+
this.set({ globals, globalTypes });
|
|
471
|
+
}
|
|
472
|
+
set({ globals = {}, globalTypes = {} }) {
|
|
473
|
+
let delta = this.initialGlobals && deepDiff(this.initialGlobals, this.globals);
|
|
474
|
+
this.allowedGlobalNames = /* @__PURE__ */ new Set([...Object.keys(globals), ...Object.keys(globalTypes)]);
|
|
475
|
+
let defaultGlobals = getValuesFromArgTypes(globalTypes);
|
|
476
|
+
this.initialGlobals = { ...defaultGlobals, ...globals }, this.globals = this.initialGlobals, delta && delta !== DEEPLY_EQUAL && this.updateFromPersisted(delta);
|
|
477
|
+
}
|
|
478
|
+
filterAllowedGlobals(globals) {
|
|
479
|
+
return Object.entries(globals).reduce((acc, [key, value]) => (this.allowedGlobalNames.has(key) ? acc[key] = value : logger2.warn(
|
|
480
|
+
`Attempted to set a global (${key}) that is not defined in initial globals or globalTypes`
|
|
481
|
+
), acc), {});
|
|
482
|
+
}
|
|
483
|
+
updateFromPersisted(persisted) {
|
|
484
|
+
let allowedUrlGlobals = this.filterAllowedGlobals(persisted);
|
|
485
|
+
this.globals = { ...this.globals, ...allowedUrlGlobals };
|
|
486
|
+
}
|
|
487
|
+
get() {
|
|
488
|
+
return this.globals;
|
|
489
|
+
}
|
|
490
|
+
update(newGlobals) {
|
|
491
|
+
this.globals = { ...this.globals, ...this.filterAllowedGlobals(newGlobals) };
|
|
492
|
+
for (let key in newGlobals)
|
|
493
|
+
newGlobals[key] === void 0 && (this.globals[key] = this.initialGlobals[key]);
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
// src/preview-api/modules/store/StoryIndexStore.ts
|
|
498
|
+
var import_memoizerific = __toESM(require_memoizerific(), 1);
|
|
499
|
+
import { MissingStoryAfterHmrError } from "storybook/internal/preview-errors";
|
|
500
|
+
var getImportPathMap = (0, import_memoizerific.default)(1)(
|
|
501
|
+
(entries) => Object.values(entries).reduce(
|
|
502
|
+
(acc, entry) => (acc[entry.importPath] = acc[entry.importPath] || entry, acc),
|
|
503
|
+
{}
|
|
504
|
+
)
|
|
505
|
+
), StoryIndexStore = class {
|
|
506
|
+
constructor({ entries } = { v: 5, entries: {} }) {
|
|
507
|
+
this.entries = entries;
|
|
508
|
+
}
|
|
509
|
+
entryFromSpecifier(specifier) {
|
|
510
|
+
let entries = Object.values(this.entries);
|
|
511
|
+
if (specifier === "*")
|
|
512
|
+
return entries[0];
|
|
513
|
+
if (typeof specifier == "string")
|
|
514
|
+
return this.entries[specifier] ? this.entries[specifier] : entries.find((entry) => entry.id.startsWith(specifier));
|
|
515
|
+
let { name, title } = specifier;
|
|
516
|
+
return entries.find((entry) => entry.name === name && entry.title === title);
|
|
517
|
+
}
|
|
518
|
+
storyIdToEntry(storyId) {
|
|
519
|
+
let storyEntry = this.entries[storyId];
|
|
520
|
+
if (!storyEntry)
|
|
521
|
+
throw new MissingStoryAfterHmrError({ storyId });
|
|
522
|
+
return storyEntry;
|
|
523
|
+
}
|
|
524
|
+
importPathToEntry(importPath) {
|
|
525
|
+
return getImportPathMap(this.entries)[importPath];
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
|
|
529
|
+
// src/preview-api/modules/store/csf/normalizeInputTypes.ts
|
|
530
|
+
var normalizeType = (type) => typeof type == "string" ? { name: type } : type, normalizeControl = (control) => typeof control == "string" ? { type: control } : control, normalizeInputType = (inputType, key) => {
|
|
531
|
+
let { type, control, ...rest } = inputType, normalized = {
|
|
532
|
+
name: key,
|
|
533
|
+
...rest
|
|
534
|
+
};
|
|
535
|
+
return type && (normalized.type = normalizeType(type)), control ? normalized.control = normalizeControl(control) : control === !1 && (normalized.control = { disable: !0 }), normalized;
|
|
536
|
+
}, normalizeInputTypes = (inputTypes) => mapValues(inputTypes, normalizeInputType);
|
|
537
|
+
|
|
538
|
+
// src/preview-api/modules/store/csf/normalizeStory.ts
|
|
539
|
+
import { deprecate, logger as logger3 } from "storybook/internal/client-logger";
|
|
540
|
+
import { storyNameFromExport, toId } from "storybook/internal/csf";
|
|
541
|
+
|
|
542
|
+
// src/preview-api/modules/store/csf/normalizeArrays.ts
|
|
543
|
+
var normalizeArrays = (array) => Array.isArray(array) ? array : array ? [array] : [];
|
|
544
|
+
|
|
545
|
+
// src/preview-api/modules/store/csf/normalizeStory.ts
|
|
546
|
+
var deprecatedStoryAnnotation = dedent`
|
|
547
|
+
CSF .story annotations deprecated; annotate story functions directly:
|
|
548
|
+
- StoryFn.story.name => StoryFn.storyName
|
|
549
|
+
- StoryFn.story.(parameters|decorators) => StoryFn.(parameters|decorators)
|
|
550
|
+
See https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#hoisted-csf-annotations for details and codemod.
|
|
551
|
+
`;
|
|
552
|
+
function normalizeStory(key, storyAnnotations, meta) {
|
|
553
|
+
let storyObject = storyAnnotations, userStoryFn = typeof storyAnnotations == "function" ? storyAnnotations : null, { story } = storyObject;
|
|
554
|
+
story && (logger3.debug("deprecated story", story), deprecate(deprecatedStoryAnnotation));
|
|
555
|
+
let exportName = storyNameFromExport(key), name = typeof storyObject != "function" && storyObject.name || storyObject.storyName || story?.name || exportName, decorators = [
|
|
556
|
+
...normalizeArrays(storyObject.decorators),
|
|
557
|
+
...normalizeArrays(story?.decorators)
|
|
558
|
+
], parameters = { ...story?.parameters, ...storyObject.parameters }, args = { ...story?.args, ...storyObject.args }, argTypes = { ...story?.argTypes, ...storyObject.argTypes }, loaders = [...normalizeArrays(storyObject.loaders), ...normalizeArrays(story?.loaders)], beforeEach = [
|
|
559
|
+
...normalizeArrays(storyObject.beforeEach),
|
|
560
|
+
...normalizeArrays(story?.beforeEach)
|
|
561
|
+
], afterEach = [
|
|
562
|
+
...normalizeArrays(storyObject.afterEach),
|
|
563
|
+
...normalizeArrays(story?.afterEach)
|
|
564
|
+
], { render, play, tags = [], globals = {} } = storyObject, id = parameters.__id || toId(meta.id, exportName);
|
|
565
|
+
return {
|
|
566
|
+
moduleExport: storyAnnotations,
|
|
567
|
+
id,
|
|
568
|
+
name,
|
|
569
|
+
tags,
|
|
570
|
+
decorators,
|
|
571
|
+
parameters,
|
|
572
|
+
args,
|
|
573
|
+
argTypes: normalizeInputTypes(argTypes),
|
|
574
|
+
loaders,
|
|
575
|
+
beforeEach,
|
|
576
|
+
afterEach,
|
|
577
|
+
globals,
|
|
578
|
+
...render && { render },
|
|
579
|
+
...userStoryFn && { userStoryFn },
|
|
580
|
+
...play && { play }
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
// src/preview-api/modules/store/csf/processCSFFile.ts
|
|
585
|
+
import { logger as logger4 } from "storybook/internal/client-logger";
|
|
586
|
+
import { getStoryChildren, isExportStory, isStory, toTestId } from "storybook/internal/csf";
|
|
587
|
+
|
|
588
|
+
// src/preview-api/modules/store/csf/normalizeComponentAnnotations.ts
|
|
589
|
+
import { sanitize } from "storybook/internal/csf";
|
|
590
|
+
function normalizeComponentAnnotations(defaultExport, title = defaultExport.title, importPath) {
|
|
591
|
+
let { id, argTypes } = defaultExport;
|
|
592
|
+
return {
|
|
593
|
+
id: sanitize(id || title),
|
|
594
|
+
...defaultExport,
|
|
595
|
+
title,
|
|
596
|
+
...argTypes && { argTypes: normalizeInputTypes(argTypes) },
|
|
597
|
+
parameters: {
|
|
598
|
+
fileName: importPath,
|
|
599
|
+
...defaultExport.parameters
|
|
600
|
+
}
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
|
|
604
|
+
// src/preview-api/modules/store/csf/processCSFFile.ts
|
|
605
|
+
var checkGlobals = (parameters) => {
|
|
606
|
+
let { globals, globalTypes } = parameters;
|
|
607
|
+
(globals || globalTypes) && logger4.error(
|
|
608
|
+
"Global args/argTypes can only be set globally",
|
|
609
|
+
JSON.stringify({
|
|
610
|
+
globals,
|
|
611
|
+
globalTypes
|
|
612
|
+
})
|
|
613
|
+
);
|
|
614
|
+
}, checkStorySort = (parameters) => {
|
|
615
|
+
let { options } = parameters;
|
|
616
|
+
options?.storySort && logger4.error("The storySort option parameter can only be set globally");
|
|
617
|
+
}, checkDisallowedParameters = (parameters) => {
|
|
618
|
+
parameters && (checkGlobals(parameters), checkStorySort(parameters));
|
|
619
|
+
};
|
|
620
|
+
function processCSFFile(moduleExports, importPath, title) {
|
|
621
|
+
let { default: defaultExport, __namedExportsOrder, ...namedExports } = moduleExports, firstStory = Object.values(namedExports)[0];
|
|
622
|
+
if (isStory(firstStory)) {
|
|
623
|
+
let meta2 = normalizeComponentAnnotations(firstStory.meta.input, title, importPath);
|
|
624
|
+
checkDisallowedParameters(meta2.parameters);
|
|
625
|
+
let csfFile2 = { meta: meta2, stories: {}, moduleExports };
|
|
626
|
+
return Object.keys(namedExports).forEach((key) => {
|
|
627
|
+
if (isExportStory(key, meta2)) {
|
|
628
|
+
let story = namedExports[key], storyMeta = normalizeStory(key, story.input, meta2);
|
|
629
|
+
checkDisallowedParameters(storyMeta.parameters), csfFile2.stories[storyMeta.id] = storyMeta, getStoryChildren(story).forEach((child) => {
|
|
630
|
+
let name = child.input.name, childId = toTestId(storyMeta.id, name);
|
|
631
|
+
child.input.parameters ??= {}, child.input.parameters.__id = childId, csfFile2.stories[childId] = normalizeStory(name, child.input, meta2);
|
|
632
|
+
});
|
|
633
|
+
}
|
|
634
|
+
}), csfFile2.projectAnnotations = firstStory.meta.preview.composed, csfFile2;
|
|
635
|
+
}
|
|
636
|
+
let meta = normalizeComponentAnnotations(
|
|
637
|
+
defaultExport,
|
|
638
|
+
title,
|
|
639
|
+
importPath
|
|
640
|
+
);
|
|
641
|
+
checkDisallowedParameters(meta.parameters);
|
|
642
|
+
let csfFile = { meta, stories: {}, moduleExports };
|
|
643
|
+
return Object.keys(namedExports).forEach((key) => {
|
|
644
|
+
if (isExportStory(key, meta)) {
|
|
645
|
+
let storyMeta = normalizeStory(key, namedExports[key], meta);
|
|
646
|
+
checkDisallowedParameters(storyMeta.parameters), csfFile.stories[storyMeta.id] = storyMeta;
|
|
647
|
+
}
|
|
648
|
+
}), csfFile;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/preview-api/modules/store/csf/prepareStory.ts
|
|
652
|
+
import { combineTags, includeConditionalArg } from "storybook/internal/csf";
|
|
653
|
+
import { NoRenderFunctionError } from "storybook/internal/preview-errors";
|
|
654
|
+
import { global as global3 } from "@storybook/global";
|
|
655
|
+
import { global as globalThis2 } from "@storybook/global";
|
|
656
|
+
|
|
657
|
+
// src/preview-api/modules/preview-web/render/mount-utils.ts
|
|
658
|
+
function mountDestructured(playFunction) {
|
|
659
|
+
return playFunction != null && getUsedProps(playFunction).includes("mount");
|
|
660
|
+
}
|
|
661
|
+
function getUsedProps(fn) {
|
|
662
|
+
let match = fn.toString().match(/[^(]*\(([^)]*)/);
|
|
663
|
+
if (!match)
|
|
664
|
+
return [];
|
|
665
|
+
let args = splitByComma(match[1]);
|
|
666
|
+
if (!args.length)
|
|
667
|
+
return [];
|
|
668
|
+
let first = args[0];
|
|
669
|
+
return first.startsWith("{") && first.endsWith("}") ? splitByComma(first.slice(1, -1).replace(/\s/g, "")).map((prop) => prop.replace(/:.*|=.*/g, "")) : [];
|
|
670
|
+
}
|
|
671
|
+
function splitByComma(s) {
|
|
672
|
+
let result = [], stack = [], start = 0;
|
|
673
|
+
for (let i = 0; i < s.length; i++)
|
|
674
|
+
if (s[i] === "{" || s[i] === "[")
|
|
675
|
+
stack.push(s[i] === "{" ? "}" : "]");
|
|
676
|
+
else if (s[i] === stack[stack.length - 1])
|
|
677
|
+
stack.pop();
|
|
678
|
+
else if (!stack.length && s[i] === ",") {
|
|
679
|
+
let token = s.substring(start, i).trim();
|
|
680
|
+
token && result.push(token), start = i + 1;
|
|
681
|
+
}
|
|
682
|
+
let lastToken = s.substring(start).trim();
|
|
683
|
+
return lastToken && result.push(lastToken), result;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
// src/preview-api/modules/store/decorators.ts
|
|
687
|
+
function decorateStory(storyFn, decorator, bindWithContext) {
|
|
688
|
+
let boundStoryFunction = bindWithContext(storyFn);
|
|
689
|
+
return (context) => decorator(boundStoryFunction, context);
|
|
690
|
+
}
|
|
691
|
+
function sanitizeStoryContextUpdate({
|
|
692
|
+
componentId,
|
|
693
|
+
title,
|
|
694
|
+
kind,
|
|
695
|
+
id,
|
|
696
|
+
name,
|
|
697
|
+
story,
|
|
698
|
+
parameters,
|
|
699
|
+
initialArgs,
|
|
700
|
+
argTypes,
|
|
701
|
+
...update
|
|
702
|
+
} = {}) {
|
|
703
|
+
return update;
|
|
704
|
+
}
|
|
705
|
+
function defaultDecorateStory(storyFn, decorators) {
|
|
706
|
+
let contextStore = {}, bindWithContext = (decoratedStoryFn) => (update) => {
|
|
707
|
+
if (!contextStore.value)
|
|
708
|
+
throw new Error("Decorated function called without init");
|
|
709
|
+
return contextStore.value = {
|
|
710
|
+
...contextStore.value,
|
|
711
|
+
...sanitizeStoryContextUpdate(update)
|
|
712
|
+
}, decoratedStoryFn(contextStore.value);
|
|
713
|
+
}, decoratedWithContextStore = decorators.reduce(
|
|
714
|
+
(story, decorator) => decorateStory(story, decorator, bindWithContext),
|
|
715
|
+
storyFn
|
|
716
|
+
);
|
|
717
|
+
return (context) => (contextStore.value = context, decoratedWithContextStore(context));
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
// src/preview-api/modules/store/csf/prepareStory.ts
|
|
721
|
+
function prepareStory(storyAnnotations, componentAnnotations, projectAnnotations) {
|
|
722
|
+
let { moduleExport, id, name } = storyAnnotations || {}, partialAnnotations = preparePartialAnnotations(
|
|
723
|
+
storyAnnotations,
|
|
724
|
+
componentAnnotations,
|
|
725
|
+
projectAnnotations
|
|
726
|
+
), applyLoaders = async (context) => {
|
|
727
|
+
let loaded = {};
|
|
728
|
+
for (let loaders of [
|
|
729
|
+
normalizeArrays(projectAnnotations.loaders),
|
|
730
|
+
normalizeArrays(componentAnnotations.loaders),
|
|
731
|
+
normalizeArrays(storyAnnotations.loaders)
|
|
732
|
+
]) {
|
|
733
|
+
if (context.abortSignal.aborted)
|
|
734
|
+
return loaded;
|
|
735
|
+
let loadResults = await Promise.all(loaders.map((loader) => loader(context)));
|
|
736
|
+
Object.assign(loaded, ...loadResults);
|
|
737
|
+
}
|
|
738
|
+
return loaded;
|
|
739
|
+
}, applyBeforeEach = async (context) => {
|
|
740
|
+
let cleanupCallbacks = new Array();
|
|
741
|
+
for (let beforeEach of [
|
|
742
|
+
...normalizeArrays(projectAnnotations.beforeEach),
|
|
743
|
+
...normalizeArrays(componentAnnotations.beforeEach),
|
|
744
|
+
...normalizeArrays(storyAnnotations.beforeEach)
|
|
745
|
+
]) {
|
|
746
|
+
if (context.abortSignal.aborted)
|
|
747
|
+
return cleanupCallbacks;
|
|
748
|
+
let cleanup = await beforeEach(context);
|
|
749
|
+
cleanup && cleanupCallbacks.push(cleanup);
|
|
750
|
+
}
|
|
751
|
+
return cleanupCallbacks;
|
|
752
|
+
}, applyAfterEach = async (context) => {
|
|
753
|
+
let reversedFinalizers = [
|
|
754
|
+
...normalizeArrays(projectAnnotations.afterEach),
|
|
755
|
+
...normalizeArrays(componentAnnotations.afterEach),
|
|
756
|
+
...normalizeArrays(storyAnnotations.afterEach)
|
|
757
|
+
].reverse();
|
|
758
|
+
for (let finalizer of reversedFinalizers) {
|
|
759
|
+
if (context.abortSignal.aborted)
|
|
760
|
+
return;
|
|
761
|
+
await finalizer(context);
|
|
762
|
+
}
|
|
763
|
+
}, undecoratedStoryFn = (context) => context.originalStoryFn(context.args, context), { applyDecorators = defaultDecorateStory, runStep } = projectAnnotations, decorators = [
|
|
764
|
+
...normalizeArrays(storyAnnotations?.decorators),
|
|
765
|
+
...normalizeArrays(componentAnnotations?.decorators),
|
|
766
|
+
...normalizeArrays(projectAnnotations?.decorators)
|
|
767
|
+
], render = storyAnnotations?.userStoryFn || storyAnnotations?.render || componentAnnotations.render || projectAnnotations.render, decoratedStoryFn = applyHooks(applyDecorators)(undecoratedStoryFn, decorators), unboundStoryFn = (context) => decoratedStoryFn(context), playFunction = storyAnnotations?.play ?? componentAnnotations?.play, usesMount = mountDestructured(playFunction);
|
|
768
|
+
if (!render && !usesMount)
|
|
769
|
+
throw new NoRenderFunctionError({ id });
|
|
770
|
+
let defaultMount = (context) => async () => (await context.renderToCanvas(), context.canvas), mount = storyAnnotations.mount ?? componentAnnotations.mount ?? projectAnnotations.mount ?? defaultMount, testingLibraryRender = projectAnnotations.testingLibraryRender;
|
|
771
|
+
return {
|
|
772
|
+
storyGlobals: {},
|
|
773
|
+
...partialAnnotations,
|
|
774
|
+
moduleExport,
|
|
775
|
+
id,
|
|
776
|
+
name,
|
|
777
|
+
story: name,
|
|
778
|
+
originalStoryFn: render,
|
|
779
|
+
undecoratedStoryFn,
|
|
780
|
+
unboundStoryFn,
|
|
781
|
+
applyLoaders,
|
|
782
|
+
applyBeforeEach,
|
|
783
|
+
applyAfterEach,
|
|
784
|
+
playFunction,
|
|
785
|
+
runStep,
|
|
786
|
+
mount,
|
|
787
|
+
testingLibraryRender,
|
|
788
|
+
renderToCanvas: projectAnnotations.renderToCanvas,
|
|
789
|
+
usesMount
|
|
790
|
+
};
|
|
791
|
+
}
|
|
792
|
+
function prepareMeta(componentAnnotations, projectAnnotations, moduleExport) {
|
|
793
|
+
return {
|
|
794
|
+
...preparePartialAnnotations(void 0, componentAnnotations, projectAnnotations),
|
|
795
|
+
moduleExport
|
|
796
|
+
};
|
|
797
|
+
}
|
|
798
|
+
function preparePartialAnnotations(storyAnnotations, componentAnnotations, projectAnnotations) {
|
|
799
|
+
let defaultTags = ["dev", "test"], extraTags = globalThis2.DOCS_OPTIONS?.autodocs === !0 ? ["autodocs"] : [], overrideTags = storyAnnotations?.tags?.includes("test-fn") ? ["!autodocs"] : [], tags = combineTags(
|
|
800
|
+
...defaultTags,
|
|
801
|
+
...extraTags,
|
|
802
|
+
...projectAnnotations.tags ?? [],
|
|
803
|
+
...componentAnnotations.tags ?? [],
|
|
804
|
+
...overrideTags,
|
|
805
|
+
...storyAnnotations?.tags ?? []
|
|
806
|
+
), parameters = combineParameters(
|
|
807
|
+
projectAnnotations.parameters,
|
|
808
|
+
componentAnnotations.parameters,
|
|
809
|
+
storyAnnotations?.parameters
|
|
810
|
+
), { argTypesEnhancers = [], argsEnhancers = [] } = projectAnnotations, passedArgTypes = combineParameters(
|
|
811
|
+
projectAnnotations.argTypes,
|
|
812
|
+
componentAnnotations.argTypes,
|
|
813
|
+
storyAnnotations?.argTypes
|
|
814
|
+
);
|
|
815
|
+
if (storyAnnotations) {
|
|
816
|
+
let render = storyAnnotations?.userStoryFn || storyAnnotations?.render || componentAnnotations.render || projectAnnotations.render;
|
|
817
|
+
parameters.__isArgsStory = render && render.length > 0;
|
|
818
|
+
}
|
|
819
|
+
let passedArgs = {
|
|
820
|
+
...projectAnnotations.args,
|
|
821
|
+
...componentAnnotations.args,
|
|
822
|
+
...storyAnnotations?.args
|
|
823
|
+
}, storyGlobals = {
|
|
824
|
+
...componentAnnotations.globals,
|
|
825
|
+
...storyAnnotations?.globals
|
|
826
|
+
}, contextForEnhancers = {
|
|
827
|
+
componentId: componentAnnotations.id,
|
|
828
|
+
title: componentAnnotations.title,
|
|
829
|
+
kind: componentAnnotations.title,
|
|
830
|
+
// Back compat
|
|
831
|
+
id: storyAnnotations?.id || componentAnnotations.id,
|
|
832
|
+
// if there's no story name, we create a fake one since enhancers expect a name
|
|
833
|
+
name: storyAnnotations?.name || "__meta",
|
|
834
|
+
story: storyAnnotations?.name || "__meta",
|
|
835
|
+
// Back compat
|
|
836
|
+
component: componentAnnotations.component,
|
|
837
|
+
subcomponents: componentAnnotations.subcomponents,
|
|
838
|
+
tags,
|
|
839
|
+
parameters,
|
|
840
|
+
initialArgs: passedArgs,
|
|
841
|
+
argTypes: passedArgTypes,
|
|
842
|
+
storyGlobals
|
|
843
|
+
};
|
|
844
|
+
contextForEnhancers.argTypes = argTypesEnhancers.reduce(
|
|
845
|
+
(accumulatedArgTypes, enhancer) => enhancer({ ...contextForEnhancers, argTypes: accumulatedArgTypes }),
|
|
846
|
+
contextForEnhancers.argTypes
|
|
847
|
+
);
|
|
848
|
+
let initialArgsBeforeEnhancers = { ...passedArgs };
|
|
849
|
+
contextForEnhancers.initialArgs = [...argsEnhancers].reduce(
|
|
850
|
+
(accumulatedArgs, enhancer) => ({
|
|
851
|
+
...accumulatedArgs,
|
|
852
|
+
...enhancer({
|
|
853
|
+
...contextForEnhancers,
|
|
854
|
+
initialArgs: accumulatedArgs
|
|
855
|
+
})
|
|
856
|
+
}),
|
|
857
|
+
initialArgsBeforeEnhancers
|
|
858
|
+
);
|
|
859
|
+
let { name, story, ...withoutStoryIdentifiers } = contextForEnhancers;
|
|
860
|
+
return withoutStoryIdentifiers;
|
|
861
|
+
}
|
|
862
|
+
function prepareContext(context) {
|
|
863
|
+
let { args: unmappedArgs } = context, targetedContext = {
|
|
864
|
+
...context,
|
|
865
|
+
allArgs: void 0,
|
|
866
|
+
argsByTarget: void 0
|
|
867
|
+
};
|
|
868
|
+
if (global3.FEATURES?.argTypeTargetsV7) {
|
|
869
|
+
let argsByTarget = groupArgsByTarget(context);
|
|
870
|
+
targetedContext = {
|
|
871
|
+
...context,
|
|
872
|
+
allArgs: context.args,
|
|
873
|
+
argsByTarget,
|
|
874
|
+
args: argsByTarget[UNTARGETED] || {}
|
|
875
|
+
};
|
|
876
|
+
}
|
|
877
|
+
let mappedArgs = Object.entries(targetedContext.args).reduce((acc, [key, val]) => {
|
|
878
|
+
if (!targetedContext.argTypes[key]?.mapping)
|
|
879
|
+
return acc[key] = val, acc;
|
|
880
|
+
let mappingFn = (originalValue) => {
|
|
881
|
+
let mapping = targetedContext.argTypes[key].mapping;
|
|
882
|
+
return mapping && originalValue in mapping ? mapping[originalValue] : originalValue;
|
|
883
|
+
};
|
|
884
|
+
return acc[key] = Array.isArray(val) ? val.map(mappingFn) : mappingFn(val), acc;
|
|
885
|
+
}, {}), includedArgs = Object.entries(mappedArgs).reduce((acc, [key, val]) => {
|
|
886
|
+
let argType = targetedContext.argTypes[key] || {};
|
|
887
|
+
return includeConditionalArg(argType, mappedArgs, targetedContext.globals) && (acc[key] = val), acc;
|
|
888
|
+
}, {});
|
|
889
|
+
return { ...targetedContext, unmappedArgs, args: includedArgs };
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
// src/preview-api/modules/store/inferArgTypes.ts
|
|
893
|
+
import { logger as logger5 } from "storybook/internal/client-logger";
|
|
894
|
+
var inferType = (value, name, visited) => {
|
|
895
|
+
let type = typeof value;
|
|
896
|
+
switch (type) {
|
|
897
|
+
case "boolean":
|
|
898
|
+
case "string":
|
|
899
|
+
case "number":
|
|
900
|
+
case "function":
|
|
901
|
+
case "symbol":
|
|
902
|
+
return { name: type };
|
|
903
|
+
default:
|
|
904
|
+
break;
|
|
905
|
+
}
|
|
906
|
+
return value ? visited.has(value) ? (logger5.warn(dedent`
|
|
907
|
+
We've detected a cycle in arg '${name}'. Args should be JSON-serializable.
|
|
908
|
+
|
|
909
|
+
Consider using the mapping feature or fully custom args:
|
|
910
|
+
- Mapping: https://storybook.js.org/docs/writing-stories/args#mapping-to-complex-arg-values
|
|
911
|
+
- Custom args: https://storybook.js.org/docs/essentials/controls#fully-custom-args
|
|
912
|
+
`), { name: "other", value: "cyclic object" }) : (visited.add(value), Array.isArray(value) ? { name: "array", value: value.length > 0 ? inferType(value[0], name, new Set(visited)) : { name: "other", value: "unknown" } } : { name: "object", value: mapValues(value, (field) => inferType(field, name, new Set(visited))) }) : { name: "object", value: {} };
|
|
913
|
+
}, inferArgTypes = (context) => {
|
|
914
|
+
let { id, argTypes: userArgTypes = {}, initialArgs = {} } = context, argTypes = mapValues(initialArgs, (arg, key) => ({
|
|
915
|
+
name: key,
|
|
916
|
+
type: inferType(arg, `${id}.${key}`, /* @__PURE__ */ new Set())
|
|
917
|
+
})), userArgTypesNames = mapValues(userArgTypes, (argType, key) => ({
|
|
918
|
+
name: key
|
|
919
|
+
}));
|
|
920
|
+
return combineParameters(argTypes, userArgTypesNames, userArgTypes);
|
|
921
|
+
};
|
|
922
|
+
inferArgTypes.secondPass = !0;
|
|
923
|
+
|
|
924
|
+
// src/preview-api/modules/store/inferControls.ts
|
|
925
|
+
import { logger as logger6 } from "storybook/internal/client-logger";
|
|
926
|
+
|
|
927
|
+
// src/preview-api/modules/store/filterArgTypes.ts
|
|
928
|
+
var matches = (name, descriptor) => Array.isArray(descriptor) ? descriptor.includes(name) : name.match(descriptor), filterArgTypes = (argTypes, include, exclude) => !include && !exclude ? argTypes : argTypes && pickBy(argTypes, (argType, key) => {
|
|
929
|
+
let name = argType.name || key.toString();
|
|
930
|
+
return !!(!include || matches(name, include)) && (!exclude || !matches(name, exclude));
|
|
931
|
+
});
|
|
932
|
+
|
|
933
|
+
// src/preview-api/modules/store/inferControls.ts
|
|
934
|
+
var inferControl = (argType, name, matchers) => {
|
|
935
|
+
let { type, options } = argType;
|
|
936
|
+
if (type) {
|
|
937
|
+
if (matchers.color && matchers.color.test(name)) {
|
|
938
|
+
let controlType = type.name;
|
|
939
|
+
if (controlType === "string")
|
|
940
|
+
return { control: { type: "color" } };
|
|
941
|
+
controlType !== "enum" && logger6.warn(
|
|
942
|
+
`Addon controls: Control of type color only supports string, received "${controlType}" instead`
|
|
943
|
+
);
|
|
944
|
+
}
|
|
945
|
+
if (matchers.date && matchers.date.test(name))
|
|
946
|
+
return { control: { type: "date" } };
|
|
947
|
+
switch (type.name) {
|
|
948
|
+
case "array":
|
|
949
|
+
return { control: { type: "object" } };
|
|
950
|
+
case "boolean":
|
|
951
|
+
return { control: { type: "boolean" } };
|
|
952
|
+
case "string":
|
|
953
|
+
return { control: { type: "text" } };
|
|
954
|
+
case "number":
|
|
955
|
+
return { control: { type: "number" } };
|
|
956
|
+
case "enum": {
|
|
957
|
+
let { value } = type;
|
|
958
|
+
return { control: { type: value?.length <= 5 ? "radio" : "select" }, options: value };
|
|
959
|
+
}
|
|
960
|
+
case "function":
|
|
961
|
+
case "symbol":
|
|
962
|
+
return null;
|
|
963
|
+
default:
|
|
964
|
+
return { control: { type: options ? "select" : "object" } };
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
}, inferControls = (context) => {
|
|
968
|
+
let {
|
|
969
|
+
argTypes,
|
|
970
|
+
parameters: { __isArgsStory, controls: { include = null, exclude = null, matchers = {} } = {} }
|
|
971
|
+
} = context;
|
|
972
|
+
if (!__isArgsStory)
|
|
973
|
+
return argTypes;
|
|
974
|
+
let filteredArgTypes = filterArgTypes(argTypes, include, exclude), withControls = mapValues(filteredArgTypes, (argType, name) => argType?.type && inferControl(argType, name.toString(), matchers));
|
|
975
|
+
return combineParameters(withControls, filteredArgTypes);
|
|
976
|
+
};
|
|
977
|
+
inferControls.secondPass = !0;
|
|
978
|
+
|
|
979
|
+
// src/preview-api/modules/store/csf/normalizeProjectAnnotations.ts
|
|
980
|
+
function normalizeProjectAnnotations({
|
|
981
|
+
argTypes,
|
|
982
|
+
globalTypes,
|
|
983
|
+
argTypesEnhancers,
|
|
984
|
+
decorators,
|
|
985
|
+
loaders,
|
|
986
|
+
beforeEach,
|
|
987
|
+
afterEach,
|
|
988
|
+
initialGlobals,
|
|
989
|
+
...annotations
|
|
990
|
+
}) {
|
|
991
|
+
return {
|
|
992
|
+
...argTypes && { argTypes: normalizeInputTypes(argTypes) },
|
|
993
|
+
...globalTypes && { globalTypes: normalizeInputTypes(globalTypes) },
|
|
994
|
+
decorators: normalizeArrays(decorators),
|
|
995
|
+
loaders: normalizeArrays(loaders),
|
|
996
|
+
beforeEach: normalizeArrays(beforeEach),
|
|
997
|
+
afterEach: normalizeArrays(afterEach),
|
|
998
|
+
argTypesEnhancers: [
|
|
999
|
+
...argTypesEnhancers || [],
|
|
1000
|
+
inferArgTypes,
|
|
1001
|
+
// There's an architectural decision to be made regarding embedded addons in core:
|
|
1002
|
+
//
|
|
1003
|
+
// Option 1: Keep embedded addons but ensure consistency by moving addon-specific code
|
|
1004
|
+
// (like inferControls) to live alongside the addon code itself. This maintains the
|
|
1005
|
+
// concept of core addons while improving code organization.
|
|
1006
|
+
//
|
|
1007
|
+
// Option 2: Fully integrate these addons into core, potentially moving UI components
|
|
1008
|
+
// into the manager and treating them as core features rather than addons. This is a
|
|
1009
|
+
// bigger architectural change requiring careful consideration.
|
|
1010
|
+
//
|
|
1011
|
+
// For now, we're keeping inferControls here as we need time to properly evaluate
|
|
1012
|
+
// these options and their implications. Some features (like Angular's cleanArgsDecorator)
|
|
1013
|
+
// currently rely on this behavior.
|
|
1014
|
+
//
|
|
1015
|
+
// TODO: Make an architectural decision on the handling of core addons
|
|
1016
|
+
inferControls
|
|
1017
|
+
],
|
|
1018
|
+
initialGlobals,
|
|
1019
|
+
...annotations
|
|
1020
|
+
};
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// src/preview-api/modules/store/csf/composeConfigs.ts
|
|
1024
|
+
import { global as global4 } from "@storybook/global";
|
|
1025
|
+
|
|
1026
|
+
// src/preview-api/modules/store/csf/beforeAll.ts
|
|
1027
|
+
var composeBeforeAllHooks = (hooks) => async () => {
|
|
1028
|
+
let cleanups2 = [];
|
|
1029
|
+
for (let hook of hooks) {
|
|
1030
|
+
let cleanup = await hook();
|
|
1031
|
+
cleanup && cleanups2.unshift(cleanup);
|
|
1032
|
+
}
|
|
1033
|
+
return async () => {
|
|
1034
|
+
for (let cleanup of cleanups2)
|
|
1035
|
+
await cleanup();
|
|
1036
|
+
};
|
|
1037
|
+
};
|
|
1038
|
+
|
|
1039
|
+
// src/preview-api/modules/store/csf/stepRunners.ts
|
|
1040
|
+
function composeStepRunners(stepRunners) {
|
|
1041
|
+
return async (label, play, playContext) => {
|
|
1042
|
+
await stepRunners.reduceRight(
|
|
1043
|
+
(innerPlay, stepRunner) => async () => stepRunner(label, innerPlay, playContext),
|
|
1044
|
+
async () => play(playContext)
|
|
1045
|
+
)();
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
// src/preview-api/modules/store/csf/composeConfigs.ts
|
|
1050
|
+
function getField(moduleExportList, field) {
|
|
1051
|
+
return moduleExportList.map((xs) => xs.default?.[field] ?? xs[field]).filter(Boolean);
|
|
1052
|
+
}
|
|
1053
|
+
function getArrayField(moduleExportList, field, options = {}) {
|
|
1054
|
+
return getField(moduleExportList, field).reduce((prev, cur) => {
|
|
1055
|
+
let normalized = normalizeArrays(cur);
|
|
1056
|
+
return options.reverseFileOrder ? [...normalized, ...prev] : [...prev, ...normalized];
|
|
1057
|
+
}, []);
|
|
1058
|
+
}
|
|
1059
|
+
function getObjectField(moduleExportList, field) {
|
|
1060
|
+
return Object.assign({}, ...getField(moduleExportList, field));
|
|
1061
|
+
}
|
|
1062
|
+
function getSingletonField(moduleExportList, field) {
|
|
1063
|
+
return getField(moduleExportList, field).pop();
|
|
1064
|
+
}
|
|
1065
|
+
function composeConfigs(moduleExportList) {
|
|
1066
|
+
let allArgTypeEnhancers = getArrayField(moduleExportList, "argTypesEnhancers"), stepRunners = getField(moduleExportList, "runStep"), beforeAllHooks = getArrayField(moduleExportList, "beforeAll");
|
|
1067
|
+
return {
|
|
1068
|
+
parameters: combineParameters(...getField(moduleExportList, "parameters")),
|
|
1069
|
+
decorators: getArrayField(moduleExportList, "decorators", {
|
|
1070
|
+
reverseFileOrder: !(global4.FEATURES?.legacyDecoratorFileOrder ?? !1)
|
|
1071
|
+
}),
|
|
1072
|
+
args: getObjectField(moduleExportList, "args"),
|
|
1073
|
+
argsEnhancers: getArrayField(moduleExportList, "argsEnhancers"),
|
|
1074
|
+
argTypes: getObjectField(moduleExportList, "argTypes"),
|
|
1075
|
+
argTypesEnhancers: [
|
|
1076
|
+
...allArgTypeEnhancers.filter((e) => !e.secondPass),
|
|
1077
|
+
...allArgTypeEnhancers.filter((e) => e.secondPass)
|
|
1078
|
+
],
|
|
1079
|
+
initialGlobals: getObjectField(moduleExportList, "initialGlobals"),
|
|
1080
|
+
globalTypes: getObjectField(moduleExportList, "globalTypes"),
|
|
1081
|
+
loaders: getArrayField(moduleExportList, "loaders"),
|
|
1082
|
+
beforeAll: composeBeforeAllHooks(beforeAllHooks),
|
|
1083
|
+
beforeEach: getArrayField(moduleExportList, "beforeEach"),
|
|
1084
|
+
afterEach: getArrayField(moduleExportList, "afterEach"),
|
|
1085
|
+
render: getSingletonField(moduleExportList, "render"),
|
|
1086
|
+
renderToCanvas: getSingletonField(moduleExportList, "renderToCanvas"),
|
|
1087
|
+
applyDecorators: getSingletonField(moduleExportList, "applyDecorators"),
|
|
1088
|
+
runStep: composeStepRunners(stepRunners),
|
|
1089
|
+
tags: getArrayField(moduleExportList, "tags"),
|
|
1090
|
+
mount: getSingletonField(moduleExportList, "mount"),
|
|
1091
|
+
testingLibraryRender: getSingletonField(moduleExportList, "testingLibraryRender")
|
|
1092
|
+
};
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
// src/preview-api/modules/store/csf/portable-stories.ts
|
|
1096
|
+
import { isExportStory as isExportStory2 } from "storybook/internal/csf";
|
|
1097
|
+
import { getCoreAnnotations } from "storybook/internal/csf";
|
|
1098
|
+
import { MountMustBeDestructuredError } from "storybook/internal/preview-errors";
|
|
1099
|
+
|
|
1100
|
+
// src/preview-api/modules/store/reporter-api.ts
|
|
1101
|
+
var ReporterAPI = class {
|
|
1102
|
+
constructor() {
|
|
1103
|
+
this.reports = [];
|
|
1104
|
+
}
|
|
1105
|
+
async addReport(report) {
|
|
1106
|
+
this.reports.push(report);
|
|
1107
|
+
}
|
|
1108
|
+
};
|
|
1109
|
+
|
|
1110
|
+
// src/preview-api/modules/store/csf/csf-factory-utils.ts
|
|
1111
|
+
import { isMeta, isStory as isStory2 } from "storybook/internal/csf";
|
|
1112
|
+
function getCsfFactoryAnnotations(story, meta, projectAnnotations) {
|
|
1113
|
+
return isStory2(story) ? {
|
|
1114
|
+
story: story.input,
|
|
1115
|
+
meta: story.meta.input,
|
|
1116
|
+
preview: story.meta.preview.composed
|
|
1117
|
+
} : { story, meta: isMeta(meta) ? meta.input : meta, preview: projectAnnotations };
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
// src/preview-api/modules/store/csf/portable-stories.ts
|
|
1121
|
+
function setDefaultProjectAnnotations(_defaultProjectAnnotations) {
|
|
1122
|
+
globalThis.defaultProjectAnnotations = _defaultProjectAnnotations;
|
|
1123
|
+
}
|
|
1124
|
+
var DEFAULT_STORY_TITLE = "ComposedStory", DEFAULT_STORY_NAME = "Unnamed Story";
|
|
1125
|
+
function extractAnnotation(annotation) {
|
|
1126
|
+
return annotation ? composeConfigs([annotation]) : {};
|
|
1127
|
+
}
|
|
1128
|
+
function setProjectAnnotations(projectAnnotations) {
|
|
1129
|
+
let annotations = Array.isArray(projectAnnotations) ? projectAnnotations : [projectAnnotations];
|
|
1130
|
+
return globalThis.globalProjectAnnotations = composeConfigs([
|
|
1131
|
+
...getCoreAnnotations(),
|
|
1132
|
+
globalThis.defaultProjectAnnotations ?? {},
|
|
1133
|
+
composeConfigs(annotations.map(extractAnnotation))
|
|
1134
|
+
]), globalThis.globalProjectAnnotations ?? {};
|
|
1135
|
+
}
|
|
1136
|
+
var cleanups = [];
|
|
1137
|
+
function composeStory(storyAnnotations, componentAnnotations, projectAnnotations, defaultConfig, exportsName) {
|
|
1138
|
+
if (storyAnnotations === void 0)
|
|
1139
|
+
throw new Error("Expected a story but received undefined.");
|
|
1140
|
+
componentAnnotations.title = componentAnnotations.title ?? DEFAULT_STORY_TITLE;
|
|
1141
|
+
let normalizedComponentAnnotations = normalizeComponentAnnotations(componentAnnotations), storyName = exportsName || storyAnnotations.storyName || storyAnnotations.story?.name || storyAnnotations.name || DEFAULT_STORY_NAME, normalizedStory = normalizeStory(
|
|
1142
|
+
storyName,
|
|
1143
|
+
storyAnnotations,
|
|
1144
|
+
normalizedComponentAnnotations
|
|
1145
|
+
), normalizedProjectAnnotations = normalizeProjectAnnotations(
|
|
1146
|
+
composeConfigs([
|
|
1147
|
+
defaultConfig ?? globalThis.globalProjectAnnotations ?? {},
|
|
1148
|
+
projectAnnotations ?? {}
|
|
1149
|
+
])
|
|
1150
|
+
), story = prepareStory(
|
|
1151
|
+
normalizedStory,
|
|
1152
|
+
normalizedComponentAnnotations,
|
|
1153
|
+
normalizedProjectAnnotations
|
|
1154
|
+
), globals = {
|
|
1155
|
+
...getValuesFromArgTypes(normalizedProjectAnnotations.globalTypes),
|
|
1156
|
+
...normalizedProjectAnnotations.initialGlobals,
|
|
1157
|
+
...story.storyGlobals
|
|
1158
|
+
}, reporting = new ReporterAPI(), initializeContext = () => {
|
|
1159
|
+
let context = prepareContext({
|
|
1160
|
+
hooks: new HooksContext(),
|
|
1161
|
+
globals,
|
|
1162
|
+
args: { ...story.initialArgs },
|
|
1163
|
+
viewMode: "story",
|
|
1164
|
+
reporting,
|
|
1165
|
+
loaded: {},
|
|
1166
|
+
abortSignal: new AbortController().signal,
|
|
1167
|
+
step: (label, play2) => story.runStep(label, play2, context),
|
|
1168
|
+
canvasElement: null,
|
|
1169
|
+
canvas: {},
|
|
1170
|
+
userEvent: {},
|
|
1171
|
+
globalTypes: normalizedProjectAnnotations.globalTypes,
|
|
1172
|
+
...story,
|
|
1173
|
+
context: null,
|
|
1174
|
+
mount: null
|
|
1175
|
+
});
|
|
1176
|
+
return context.parameters.__isPortableStory = !0, context.context = context, story.renderToCanvas && (context.renderToCanvas = async () => {
|
|
1177
|
+
let unmount = await story.renderToCanvas?.(
|
|
1178
|
+
{
|
|
1179
|
+
componentId: story.componentId,
|
|
1180
|
+
title: story.title,
|
|
1181
|
+
id: story.id,
|
|
1182
|
+
name: story.name,
|
|
1183
|
+
tags: story.tags,
|
|
1184
|
+
showMain: () => {
|
|
1185
|
+
},
|
|
1186
|
+
showError: (error) => {
|
|
1187
|
+
throw new Error(`${error.title}
|
|
1188
|
+
${error.description}`);
|
|
1189
|
+
},
|
|
1190
|
+
showException: (error) => {
|
|
1191
|
+
throw error;
|
|
1192
|
+
},
|
|
1193
|
+
forceRemount: !0,
|
|
1194
|
+
storyContext: context,
|
|
1195
|
+
storyFn: () => story.unboundStoryFn(context),
|
|
1196
|
+
unboundStoryFn: story.unboundStoryFn
|
|
1197
|
+
},
|
|
1198
|
+
context.canvasElement
|
|
1199
|
+
);
|
|
1200
|
+
unmount && cleanups.push(unmount);
|
|
1201
|
+
}), context.mount = story.mount(context), context;
|
|
1202
|
+
}, loadedContext, play = async (extraContext) => {
|
|
1203
|
+
let context = initializeContext();
|
|
1204
|
+
return context.canvasElement ??= globalThis?.document?.body, loadedContext && (context.loaded = loadedContext.loaded), Object.assign(context, extraContext), story.playFunction(context);
|
|
1205
|
+
}, run = (extraContext) => {
|
|
1206
|
+
let context = initializeContext();
|
|
1207
|
+
return Object.assign(context, extraContext), runStory(story, context);
|
|
1208
|
+
}, playFunction = story.playFunction ? play : void 0;
|
|
1209
|
+
return Object.assign(
|
|
1210
|
+
function(extraArgs) {
|
|
1211
|
+
let context = initializeContext();
|
|
1212
|
+
return loadedContext && (context.loaded = loadedContext.loaded), context.args = {
|
|
1213
|
+
...context.initialArgs,
|
|
1214
|
+
...extraArgs
|
|
1215
|
+
}, story.unboundStoryFn(context);
|
|
1216
|
+
},
|
|
1217
|
+
{
|
|
1218
|
+
id: story.id,
|
|
1219
|
+
storyName,
|
|
1220
|
+
load: async () => {
|
|
1221
|
+
for (let callback of [...cleanups].reverse())
|
|
1222
|
+
await callback();
|
|
1223
|
+
cleanups.length = 0;
|
|
1224
|
+
let context = initializeContext();
|
|
1225
|
+
context.loaded = await story.applyLoaders(context), cleanups.push(...(await story.applyBeforeEach(context)).filter(Boolean)), loadedContext = context;
|
|
1226
|
+
},
|
|
1227
|
+
globals,
|
|
1228
|
+
args: story.initialArgs,
|
|
1229
|
+
parameters: story.parameters,
|
|
1230
|
+
argTypes: story.argTypes,
|
|
1231
|
+
play: playFunction,
|
|
1232
|
+
run,
|
|
1233
|
+
reporting,
|
|
1234
|
+
tags: story.tags
|
|
1235
|
+
}
|
|
1236
|
+
);
|
|
1237
|
+
}
|
|
1238
|
+
var defaultComposeStory = (story, component, project, exportsName) => composeStory(story, component, project, {}, exportsName);
|
|
1239
|
+
function composeStories(storiesImport, globalConfig, composeStoryFn = defaultComposeStory) {
|
|
1240
|
+
let { default: metaExport, __esModule, __namedExportsOrder, ...stories } = storiesImport, meta = metaExport;
|
|
1241
|
+
return Object.entries(stories).reduce(
|
|
1242
|
+
(storiesMap, [exportsName, story]) => {
|
|
1243
|
+
let { story: storyAnnotations, meta: componentAnnotations } = getCsfFactoryAnnotations(story);
|
|
1244
|
+
return !meta && componentAnnotations && (meta = componentAnnotations), isExportStory2(exportsName, meta) ? Object.assign(storiesMap, {
|
|
1245
|
+
[exportsName]: composeStoryFn(storyAnnotations, meta, globalConfig, exportsName)
|
|
1246
|
+
}) : storiesMap;
|
|
1247
|
+
},
|
|
1248
|
+
{}
|
|
1249
|
+
);
|
|
1250
|
+
}
|
|
1251
|
+
function createPlaywrightTest(baseTest) {
|
|
1252
|
+
return baseTest.extend({
|
|
1253
|
+
mount: async ({ mount, page }, use) => {
|
|
1254
|
+
await use(async (storyRef, ...restArgs) => {
|
|
1255
|
+
if (!("__pw_type" in storyRef) || "__pw_type" in storyRef && storyRef.__pw_type !== "jsx")
|
|
1256
|
+
throw new Error(dedent`
|
|
1257
|
+
Portable stories in Playwright CT only work when referencing JSX elements.
|
|
1258
|
+
Please use JSX format for your components such as:
|
|
1259
|
+
|
|
1260
|
+
instead of:
|
|
1261
|
+
await mount(MyComponent, { props: { foo: 'bar' } })
|
|
1262
|
+
|
|
1263
|
+
do:
|
|
1264
|
+
await mount(<MyComponent foo="bar"/>)
|
|
1265
|
+
|
|
1266
|
+
More info: https://storybook.js.org/docs/api/portable-stories/portable-stories-playwright?ref=error
|
|
1267
|
+
`);
|
|
1268
|
+
let { props, ...storyRefWithoutProps } = storyRef;
|
|
1269
|
+
await page.evaluate(async (wrappedStoryRef) => {
|
|
1270
|
+
let unwrappedStoryRef = await globalThis.__pwUnwrapObject?.(wrappedStoryRef);
|
|
1271
|
+
return ("__pw_type" in unwrappedStoryRef ? unwrappedStoryRef.type : unwrappedStoryRef)?.load?.();
|
|
1272
|
+
}, storyRefWithoutProps);
|
|
1273
|
+
let mountResult = await mount(storyRef, ...restArgs);
|
|
1274
|
+
return await page.evaluate(async (wrappedStoryRef) => {
|
|
1275
|
+
let unwrappedStoryRef = await globalThis.__pwUnwrapObject?.(wrappedStoryRef), story = "__pw_type" in unwrappedStoryRef ? unwrappedStoryRef.type : unwrappedStoryRef, canvasElement = document.querySelector("#root");
|
|
1276
|
+
return story?.play?.({ canvasElement });
|
|
1277
|
+
}, storyRefWithoutProps), mountResult;
|
|
1278
|
+
});
|
|
1279
|
+
}
|
|
1280
|
+
});
|
|
1281
|
+
}
|
|
1282
|
+
async function runStory(story, context) {
|
|
1283
|
+
for (let callback of [...cleanups].reverse())
|
|
1284
|
+
await callback();
|
|
1285
|
+
if (cleanups.length = 0, !context.canvasElement) {
|
|
1286
|
+
let container = document.createElement("div");
|
|
1287
|
+
globalThis?.document?.body?.appendChild(container), context.canvasElement = container, cleanups.push(() => {
|
|
1288
|
+
globalThis?.document?.body?.contains(container) && globalThis?.document?.body?.removeChild(container);
|
|
1289
|
+
});
|
|
1290
|
+
}
|
|
1291
|
+
if (context.loaded = await story.applyLoaders(context), context.abortSignal.aborted)
|
|
1292
|
+
return;
|
|
1293
|
+
cleanups.push(...(await story.applyBeforeEach(context)).filter(Boolean));
|
|
1294
|
+
let playFunction = story.playFunction, isMountDestructured = story.usesMount;
|
|
1295
|
+
if (isMountDestructured || await context.mount(), context.abortSignal.aborted)
|
|
1296
|
+
return;
|
|
1297
|
+
playFunction && (isMountDestructured || (context.mount = async () => {
|
|
1298
|
+
throw new MountMustBeDestructuredError({ playFunction: playFunction.toString() });
|
|
1299
|
+
}), await playFunction(context));
|
|
1300
|
+
let cleanUp;
|
|
1301
|
+
isTestEnvironment() ? cleanUp = pauseAnimations() : await waitForAnimations(context.abortSignal), await story.applyAfterEach(context), await cleanUp?.();
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
// src/preview-api/modules/store/StoryStore.ts
|
|
1305
|
+
var CSF_CACHE_SIZE = 1e3, STORY_CACHE_SIZE = 1e4, StoryStore = class {
|
|
1306
|
+
constructor(storyIndex, importFn, projectAnnotations) {
|
|
1307
|
+
this.importFn = importFn;
|
|
1308
|
+
this.storyIndex = new StoryIndexStore(storyIndex), this.projectAnnotations = normalizeProjectAnnotations(
|
|
1309
|
+
composeConfigs([...getCoreAnnotations2(), projectAnnotations])
|
|
1310
|
+
);
|
|
1311
|
+
let { initialGlobals, globalTypes } = this.projectAnnotations;
|
|
1312
|
+
this.args = new ArgsStore(), this.userGlobals = new GlobalsStore({ globals: initialGlobals, globalTypes }), this.hooks = {}, this.cleanupCallbacks = {}, this.processCSFFileWithCache = (0, import_memoizerific2.default)(CSF_CACHE_SIZE)(processCSFFile), this.prepareMetaWithCache = (0, import_memoizerific2.default)(CSF_CACHE_SIZE)(prepareMeta), this.prepareStoryWithCache = (0, import_memoizerific2.default)(STORY_CACHE_SIZE)(prepareStory);
|
|
1313
|
+
}
|
|
1314
|
+
setProjectAnnotations(projectAnnotations) {
|
|
1315
|
+
this.projectAnnotations = normalizeProjectAnnotations(projectAnnotations);
|
|
1316
|
+
let { initialGlobals, globalTypes } = projectAnnotations;
|
|
1317
|
+
this.userGlobals.set({ globals: initialGlobals, globalTypes });
|
|
1318
|
+
}
|
|
1319
|
+
// This means that one of the CSF files has changed.
|
|
1320
|
+
// If the `importFn` has changed, we will invalidate both caches.
|
|
1321
|
+
// If the `storyIndex` data has changed, we may or may not invalidate the caches, depending
|
|
1322
|
+
// on whether we've loaded the relevant files yet.
|
|
1323
|
+
async onStoriesChanged({
|
|
1324
|
+
importFn,
|
|
1325
|
+
storyIndex
|
|
1326
|
+
}) {
|
|
1327
|
+
importFn && (this.importFn = importFn), storyIndex && (this.storyIndex.entries = storyIndex.entries), this.cachedCSFFiles && await this.cacheAllCSFFiles();
|
|
1328
|
+
}
|
|
1329
|
+
// Get an entry from the index, waiting on initialization if necessary
|
|
1330
|
+
async storyIdToEntry(storyId) {
|
|
1331
|
+
return this.storyIndex.storyIdToEntry(storyId);
|
|
1332
|
+
}
|
|
1333
|
+
// To load a single CSF file to service a story we need to look up the importPath in the index
|
|
1334
|
+
async loadCSFFileByStoryId(storyId) {
|
|
1335
|
+
let { importPath, title } = this.storyIndex.storyIdToEntry(storyId), moduleExports = await this.importFn(importPath);
|
|
1336
|
+
return this.processCSFFileWithCache(moduleExports, importPath, title);
|
|
1337
|
+
}
|
|
1338
|
+
async loadAllCSFFiles() {
|
|
1339
|
+
let importPaths = {};
|
|
1340
|
+
return Object.entries(this.storyIndex.entries).forEach(([storyId, { importPath }]) => {
|
|
1341
|
+
importPaths[importPath] = storyId;
|
|
1342
|
+
}), (await Promise.all(
|
|
1343
|
+
Object.entries(importPaths).map(async ([importPath, storyId]) => ({
|
|
1344
|
+
importPath,
|
|
1345
|
+
csfFile: await this.loadCSFFileByStoryId(storyId)
|
|
1346
|
+
}))
|
|
1347
|
+
)).reduce(
|
|
1348
|
+
(acc, { importPath, csfFile }) => (acc[importPath] = csfFile, acc),
|
|
1349
|
+
{}
|
|
1350
|
+
);
|
|
1351
|
+
}
|
|
1352
|
+
async cacheAllCSFFiles() {
|
|
1353
|
+
this.cachedCSFFiles = await this.loadAllCSFFiles();
|
|
1354
|
+
}
|
|
1355
|
+
preparedMetaFromCSFFile({ csfFile }) {
|
|
1356
|
+
let componentAnnotations = csfFile.meta;
|
|
1357
|
+
return this.prepareMetaWithCache(
|
|
1358
|
+
componentAnnotations,
|
|
1359
|
+
this.projectAnnotations,
|
|
1360
|
+
csfFile.moduleExports.default
|
|
1361
|
+
);
|
|
1362
|
+
}
|
|
1363
|
+
// Load the CSF file for a story and prepare the story from it and the project annotations.
|
|
1364
|
+
async loadStory({ storyId }) {
|
|
1365
|
+
let csfFile = await this.loadCSFFileByStoryId(storyId);
|
|
1366
|
+
return this.storyFromCSFFile({ storyId, csfFile });
|
|
1367
|
+
}
|
|
1368
|
+
// This function is synchronous for convenience -- often times if you have a CSF file already
|
|
1369
|
+
// it is easier not to have to await `loadStory`.
|
|
1370
|
+
storyFromCSFFile({
|
|
1371
|
+
storyId,
|
|
1372
|
+
csfFile
|
|
1373
|
+
}) {
|
|
1374
|
+
let storyAnnotations = csfFile.stories[storyId];
|
|
1375
|
+
if (!storyAnnotations)
|
|
1376
|
+
throw new MissingStoryFromCsfFileError({ storyId });
|
|
1377
|
+
let componentAnnotations = csfFile.meta, story = this.prepareStoryWithCache(
|
|
1378
|
+
storyAnnotations,
|
|
1379
|
+
componentAnnotations,
|
|
1380
|
+
csfFile.projectAnnotations ?? this.projectAnnotations
|
|
1381
|
+
);
|
|
1382
|
+
return this.args.setInitial(story), this.hooks[story.id] = this.hooks[story.id] || new HooksContext(), story;
|
|
1383
|
+
}
|
|
1384
|
+
// If we have a CSF file we can get all the stories from it synchronously
|
|
1385
|
+
componentStoriesFromCSFFile({
|
|
1386
|
+
csfFile
|
|
1387
|
+
}) {
|
|
1388
|
+
return Object.keys(this.storyIndex.entries).filter((storyId) => !!csfFile.stories[storyId]).map((storyId) => this.storyFromCSFFile({ storyId, csfFile }));
|
|
1389
|
+
}
|
|
1390
|
+
async loadEntry(id) {
|
|
1391
|
+
let entry = await this.storyIdToEntry(id), storyImports = entry.type === "docs" ? entry.storiesImports : [], [entryExports, ...csfFiles] = await Promise.all([
|
|
1392
|
+
this.importFn(entry.importPath),
|
|
1393
|
+
...storyImports.map((storyImportPath) => {
|
|
1394
|
+
let firstStoryEntry = this.storyIndex.importPathToEntry(storyImportPath);
|
|
1395
|
+
return this.loadCSFFileByStoryId(firstStoryEntry.id);
|
|
1396
|
+
})
|
|
1397
|
+
]);
|
|
1398
|
+
return { entryExports, csfFiles };
|
|
1399
|
+
}
|
|
1400
|
+
// A prepared story does not include args, globals or hooks. These are stored in the story store
|
|
1401
|
+
// and updated separately to the (immutable) story.
|
|
1402
|
+
getStoryContext(story, { forceInitialArgs = !1 } = {}) {
|
|
1403
|
+
let userGlobals = this.userGlobals.get(), { initialGlobals } = this.userGlobals, reporting = new ReporterAPI();
|
|
1404
|
+
return prepareContext({
|
|
1405
|
+
...story,
|
|
1406
|
+
args: forceInitialArgs ? story.initialArgs : this.args.get(story.id),
|
|
1407
|
+
initialGlobals,
|
|
1408
|
+
globalTypes: this.projectAnnotations.globalTypes,
|
|
1409
|
+
userGlobals,
|
|
1410
|
+
reporting,
|
|
1411
|
+
globals: {
|
|
1412
|
+
...userGlobals,
|
|
1413
|
+
...story.storyGlobals
|
|
1414
|
+
},
|
|
1415
|
+
hooks: this.hooks[story.id]
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
addCleanupCallbacks(story, ...callbacks) {
|
|
1419
|
+
this.cleanupCallbacks[story.id] = (this.cleanupCallbacks[story.id] || []).concat(callbacks);
|
|
1420
|
+
}
|
|
1421
|
+
async cleanupStory(story) {
|
|
1422
|
+
this.hooks[story.id].clean();
|
|
1423
|
+
let callbacks = this.cleanupCallbacks[story.id];
|
|
1424
|
+
if (callbacks)
|
|
1425
|
+
for (let callback of [...callbacks].reverse())
|
|
1426
|
+
await callback();
|
|
1427
|
+
delete this.cleanupCallbacks[story.id];
|
|
1428
|
+
}
|
|
1429
|
+
extract(options = { includeDocsOnly: !1 }) {
|
|
1430
|
+
let { cachedCSFFiles } = this;
|
|
1431
|
+
if (console.log("extract: extracting stories", cachedCSFFiles), !cachedCSFFiles)
|
|
1432
|
+
throw new CalledExtractOnStoreError();
|
|
1433
|
+
let stories = Object.entries(this.storyIndex.entries).reduce(
|
|
1434
|
+
(acc, [storyId, entry]) => {
|
|
1435
|
+
if (entry.type === "docs")
|
|
1436
|
+
return acc;
|
|
1437
|
+
let csfFile = cachedCSFFiles[entry.importPath], story = this.storyFromCSFFile({ storyId, csfFile });
|
|
1438
|
+
return !options.includeDocsOnly && story.parameters.docsOnly || (acc[storyId] = Object.entries(story).reduce(
|
|
1439
|
+
(storyAcc, [key, value]) => key === "story" && entry.subtype === "test" ? { ...storyAcc, story: entry.parentName } : key === "moduleExport" || typeof value == "function" ? storyAcc : Array.isArray(value) ? Object.assign(storyAcc, { [key]: value.slice().sort() }) : Object.assign(storyAcc, { [key]: value }),
|
|
1440
|
+
{
|
|
1441
|
+
args: story.initialArgs,
|
|
1442
|
+
globals: {
|
|
1443
|
+
...this.userGlobals.initialGlobals,
|
|
1444
|
+
...this.userGlobals.globals,
|
|
1445
|
+
...story.storyGlobals
|
|
1446
|
+
},
|
|
1447
|
+
storyId: entry.parent ? entry.parent : storyId
|
|
1448
|
+
}
|
|
1449
|
+
)), acc;
|
|
1450
|
+
},
|
|
1451
|
+
{}
|
|
1452
|
+
);
|
|
1453
|
+
return console.log("extract: stories", stories), stories;
|
|
1454
|
+
}
|
|
1455
|
+
};
|
|
1456
|
+
|
|
1457
|
+
// src/preview-api/modules/store/autoTitle.ts
|
|
1458
|
+
import { once as once2 } from "storybook/internal/client-logger";
|
|
1459
|
+
|
|
1460
|
+
// ../node_modules/slash/index.js
|
|
1461
|
+
function slash(path) {
|
|
1462
|
+
return path.startsWith("\\\\?\\") ? path : path.replace(/\\/g, "/");
|
|
1463
|
+
}
|
|
1464
|
+
|
|
1465
|
+
// src/preview-api/modules/store/autoTitle.ts
|
|
1466
|
+
var sanitize2 = (parts) => {
|
|
1467
|
+
if (parts.length === 0)
|
|
1468
|
+
return parts;
|
|
1469
|
+
let last = parts[parts.length - 1], lastStripped = last?.replace(/(?:[.](?:story|stories))?([.][^.]+)$/i, "");
|
|
1470
|
+
if (parts.length === 1)
|
|
1471
|
+
return [lastStripped];
|
|
1472
|
+
let nextToLast = parts[parts.length - 2];
|
|
1473
|
+
return lastStripped && nextToLast && lastStripped.toLowerCase() === nextToLast.toLowerCase() ? [...parts.slice(0, -2), lastStripped] : lastStripped && (/^(story|stories)([.][^.]+)$/i.test(last) || /^index$/i.test(lastStripped)) ? parts.slice(0, -1) : [...parts.slice(0, -1), lastStripped];
|
|
1474
|
+
};
|
|
1475
|
+
function pathJoin(paths) {
|
|
1476
|
+
return paths.flatMap((p) => p.split("/")).filter(Boolean).join("/");
|
|
1477
|
+
}
|
|
1478
|
+
var userOrAutoTitleFromSpecifier = (fileName, entry, userTitle) => {
|
|
1479
|
+
let { directory, importPathMatcher, titlePrefix = "" } = entry || {};
|
|
1480
|
+
typeof fileName == "number" && once2.warn(dedent`
|
|
1481
|
+
CSF Auto-title received a numeric fileName. This typically happens when
|
|
1482
|
+
webpack is mis-configured in production mode. To force webpack to produce
|
|
1483
|
+
filenames, set optimization.moduleIds = "named" in your webpack config.
|
|
1484
|
+
`);
|
|
1485
|
+
let normalizedFileName = slash(String(fileName));
|
|
1486
|
+
if (importPathMatcher.exec(normalizedFileName)) {
|
|
1487
|
+
if (!userTitle) {
|
|
1488
|
+
let suffix = normalizedFileName.replace(directory, ""), parts = pathJoin([titlePrefix, suffix]).split("/");
|
|
1489
|
+
return parts = sanitize2(parts), parts.join("/");
|
|
1490
|
+
}
|
|
1491
|
+
return titlePrefix ? pathJoin([titlePrefix, userTitle]) : userTitle;
|
|
1492
|
+
}
|
|
1493
|
+
}, userOrAutoTitle = (fileName, storiesEntries, userTitle) => {
|
|
1494
|
+
for (let i = 0; i < storiesEntries.length; i += 1) {
|
|
1495
|
+
let title = userOrAutoTitleFromSpecifier(fileName, storiesEntries[i], userTitle);
|
|
1496
|
+
if (title)
|
|
1497
|
+
return title;
|
|
1498
|
+
}
|
|
1499
|
+
return userTitle || void 0;
|
|
1500
|
+
};
|
|
1501
|
+
|
|
1502
|
+
// src/preview-api/modules/store/storySort.ts
|
|
1503
|
+
var STORY_KIND_PATH_SEPARATOR = /\s*\/\s*/, storySort = (options = {}) => (a, b) => {
|
|
1504
|
+
if (a.title === b.title && !options.includeNames)
|
|
1505
|
+
return 0;
|
|
1506
|
+
let method = options.method || "configure", order = options.order || [], storyTitleA = a.title.trim().split(STORY_KIND_PATH_SEPARATOR), storyTitleB = b.title.trim().split(STORY_KIND_PATH_SEPARATOR);
|
|
1507
|
+
options.includeNames && (storyTitleA.push(a.name), storyTitleB.push(b.name));
|
|
1508
|
+
let depth = 0;
|
|
1509
|
+
for (; storyTitleA[depth] || storyTitleB[depth]; ) {
|
|
1510
|
+
if (!storyTitleA[depth])
|
|
1511
|
+
return -1;
|
|
1512
|
+
if (!storyTitleB[depth])
|
|
1513
|
+
return 1;
|
|
1514
|
+
let nameA = storyTitleA[depth], nameB = storyTitleB[depth];
|
|
1515
|
+
if (nameA !== nameB) {
|
|
1516
|
+
let indexA = order.indexOf(nameA), indexB = order.indexOf(nameB), indexWildcard = order.indexOf("*");
|
|
1517
|
+
return indexA !== -1 || indexB !== -1 ? (indexA === -1 && (indexWildcard !== -1 ? indexA = indexWildcard : indexA = order.length), indexB === -1 && (indexWildcard !== -1 ? indexB = indexWildcard : indexB = order.length), indexA - indexB) : method === "configure" ? 0 : nameA.localeCompare(nameB, options.locales ? options.locales : void 0, {
|
|
1518
|
+
numeric: !0,
|
|
1519
|
+
sensitivity: "accent"
|
|
1520
|
+
});
|
|
1521
|
+
}
|
|
1522
|
+
let index = order.indexOf(nameA);
|
|
1523
|
+
index === -1 && (index = order.indexOf("*")), order = index !== -1 && Array.isArray(order[index + 1]) ? order[index + 1] : [], depth += 1;
|
|
1524
|
+
}
|
|
1525
|
+
return 0;
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1528
|
+
// src/preview-api/modules/store/sortStories.ts
|
|
1529
|
+
var sortStoriesCommon = (stories, storySortParameter, fileNameOrder) => {
|
|
1530
|
+
if (storySortParameter) {
|
|
1531
|
+
let sortFn;
|
|
1532
|
+
typeof storySortParameter == "function" ? sortFn = storySortParameter : sortFn = storySort(storySortParameter), stories.sort(sortFn);
|
|
1533
|
+
} else
|
|
1534
|
+
stories.sort(
|
|
1535
|
+
(s1, s2) => fileNameOrder.indexOf(s1.importPath) - fileNameOrder.indexOf(s2.importPath)
|
|
1536
|
+
);
|
|
1537
|
+
return stories;
|
|
1538
|
+
}, sortStoriesV7 = (stories, storySortParameter, fileNameOrder) => {
|
|
1539
|
+
try {
|
|
1540
|
+
return sortStoriesCommon(stories, storySortParameter, fileNameOrder);
|
|
1541
|
+
} catch (err) {
|
|
1542
|
+
throw new Error(dedent`
|
|
1543
|
+
Error sorting stories with sort parameter ${storySortParameter}:
|
|
1544
|
+
|
|
1545
|
+
> ${err.message}
|
|
1546
|
+
|
|
1547
|
+
Are you using a V6-style sort function in V7 mode?
|
|
1548
|
+
|
|
1549
|
+
More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#v7-style-story-sort
|
|
1550
|
+
`);
|
|
1551
|
+
}
|
|
1552
|
+
};
|
|
1553
|
+
|
|
1554
|
+
// src/preview-api/modules/preview-web/Preview.tsx
|
|
1555
|
+
import { deprecate as deprecate2, logger as logger7 } from "storybook/internal/client-logger";
|
|
1556
|
+
import {
|
|
1557
|
+
ARGTYPES_INFO_REQUEST,
|
|
1558
|
+
ARGTYPES_INFO_RESPONSE,
|
|
1559
|
+
CONFIG_ERROR,
|
|
1560
|
+
FORCE_REMOUNT,
|
|
1561
|
+
FORCE_RE_RENDER as FORCE_RE_RENDER2,
|
|
1562
|
+
GLOBALS_UPDATED,
|
|
1563
|
+
PREVIEW_INITIALIZED,
|
|
1564
|
+
RESET_STORY_ARGS as RESET_STORY_ARGS2,
|
|
1565
|
+
SET_GLOBALS,
|
|
1566
|
+
STORY_ARGS_UPDATED,
|
|
1567
|
+
STORY_HOT_UPDATED,
|
|
1568
|
+
STORY_INDEX_INVALIDATED,
|
|
1569
|
+
UPDATE_GLOBALS as UPDATE_GLOBALS2,
|
|
1570
|
+
UPDATE_STORY_ARGS as UPDATE_STORY_ARGS2
|
|
1571
|
+
} from "storybook/internal/core-events";
|
|
1572
|
+
import {
|
|
1573
|
+
CalledPreviewMethodBeforeInitializationError,
|
|
1574
|
+
MissingRenderToCanvasError,
|
|
1575
|
+
StoryIndexFetchError,
|
|
1576
|
+
StoryStoreAccessedBeforeInitializationError
|
|
1577
|
+
} from "storybook/internal/preview-errors";
|
|
1578
|
+
import { global as global5 } from "@storybook/global";
|
|
1579
|
+
|
|
1580
|
+
// src/preview-api/modules/preview-web/render/StoryRender.ts
|
|
1581
|
+
import {
|
|
1582
|
+
PLAY_FUNCTION_THREW_EXCEPTION,
|
|
1583
|
+
STORY_FINISHED,
|
|
1584
|
+
STORY_RENDERED as STORY_RENDERED2,
|
|
1585
|
+
STORY_RENDER_PHASE_CHANGED,
|
|
1586
|
+
UNHANDLED_ERRORS_WHILE_PLAYING
|
|
1587
|
+
} from "storybook/internal/core-events";
|
|
1588
|
+
import {
|
|
1589
|
+
MountMustBeDestructuredError as MountMustBeDestructuredError2,
|
|
1590
|
+
NoStoryMountedError
|
|
1591
|
+
} from "storybook/internal/preview-errors";
|
|
1592
|
+
|
|
1593
|
+
// src/preview-api/modules/preview-web/render/Render.ts
|
|
1594
|
+
var PREPARE_ABORTED = new Error("prepareAborted");
|
|
1595
|
+
|
|
1596
|
+
// src/preview-api/modules/preview-web/render/StoryRender.ts
|
|
1597
|
+
var { AbortController: AbortController2 } = globalThis;
|
|
1598
|
+
function serializeError(error) {
|
|
1599
|
+
try {
|
|
1600
|
+
let { name = "Error", message = String(error), stack } = error;
|
|
1601
|
+
return { name, message, stack };
|
|
1602
|
+
} catch {
|
|
1603
|
+
return { name: "Error", message: String(error) };
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
var StoryRender = class {
|
|
1607
|
+
constructor(channel, store, renderToScreen, callbacks, id, viewMode, renderOptions = { autoplay: !0, forceInitialArgs: !1 }, story) {
|
|
1608
|
+
this.channel = channel;
|
|
1609
|
+
this.store = store;
|
|
1610
|
+
this.renderToScreen = renderToScreen;
|
|
1611
|
+
this.callbacks = callbacks;
|
|
1612
|
+
this.id = id;
|
|
1613
|
+
this.viewMode = viewMode;
|
|
1614
|
+
this.renderOptions = renderOptions;
|
|
1615
|
+
this.type = "story";
|
|
1616
|
+
this.notYetRendered = !0;
|
|
1617
|
+
this.rerenderEnqueued = !1;
|
|
1618
|
+
this.disableKeyListeners = !1;
|
|
1619
|
+
this.teardownRender = () => {
|
|
1620
|
+
};
|
|
1621
|
+
this.torndown = !1;
|
|
1622
|
+
this.abortController = new AbortController2(), this.renderId = Date.now(), story && (this.story = story, this.phase = "preparing");
|
|
1623
|
+
}
|
|
1624
|
+
async runPhase(signal, phase, phaseFn) {
|
|
1625
|
+
this.phase = phase, this.channel.emit(STORY_RENDER_PHASE_CHANGED, {
|
|
1626
|
+
newPhase: this.phase,
|
|
1627
|
+
renderId: this.renderId,
|
|
1628
|
+
storyId: this.id
|
|
1629
|
+
}), phaseFn && (await phaseFn(), this.checkIfAborted(signal));
|
|
1630
|
+
}
|
|
1631
|
+
checkIfAborted(signal) {
|
|
1632
|
+
return signal.aborted && !["finished", "aborted", "errored"].includes(this.phase) && (this.phase = "aborted", this.channel.emit(STORY_RENDER_PHASE_CHANGED, {
|
|
1633
|
+
newPhase: this.phase,
|
|
1634
|
+
renderId: this.renderId,
|
|
1635
|
+
storyId: this.id
|
|
1636
|
+
})), signal.aborted;
|
|
1637
|
+
}
|
|
1638
|
+
async prepare() {
|
|
1639
|
+
if (await this.runPhase(this.abortController.signal, "preparing", async () => {
|
|
1640
|
+
this.story = await this.store.loadStory({ storyId: this.id });
|
|
1641
|
+
}), this.abortController.signal.aborted)
|
|
1642
|
+
throw await this.store.cleanupStory(this.story), PREPARE_ABORTED;
|
|
1643
|
+
}
|
|
1644
|
+
// The two story "renders" are equal and have both loaded the same story
|
|
1645
|
+
isEqual(other) {
|
|
1646
|
+
return !!(this.id === other.id && this.story && this.story === other.story);
|
|
1647
|
+
}
|
|
1648
|
+
isPreparing() {
|
|
1649
|
+
return ["preparing"].includes(this.phase);
|
|
1650
|
+
}
|
|
1651
|
+
isPending() {
|
|
1652
|
+
return ["loading", "beforeEach", "rendering", "playing", "afterEach"].includes(
|
|
1653
|
+
this.phase
|
|
1654
|
+
);
|
|
1655
|
+
}
|
|
1656
|
+
async renderToElement(canvasElement) {
|
|
1657
|
+
return this.canvasElement = canvasElement, this.render({ initial: !0, forceRemount: !0 });
|
|
1658
|
+
}
|
|
1659
|
+
storyContext() {
|
|
1660
|
+
if (!this.story)
|
|
1661
|
+
throw new Error("Cannot call storyContext before preparing");
|
|
1662
|
+
let { forceInitialArgs } = this.renderOptions;
|
|
1663
|
+
return this.store.getStoryContext(this.story, { forceInitialArgs });
|
|
1664
|
+
}
|
|
1665
|
+
async render({
|
|
1666
|
+
initial = !1,
|
|
1667
|
+
forceRemount = !1
|
|
1668
|
+
} = {}) {
|
|
1669
|
+
let { canvasElement } = this;
|
|
1670
|
+
if (!this.story)
|
|
1671
|
+
throw new Error("cannot render when not prepared");
|
|
1672
|
+
let story = this.story;
|
|
1673
|
+
if (!canvasElement)
|
|
1674
|
+
throw new Error("cannot render when canvasElement is unset");
|
|
1675
|
+
let {
|
|
1676
|
+
id,
|
|
1677
|
+
componentId,
|
|
1678
|
+
title,
|
|
1679
|
+
name,
|
|
1680
|
+
tags,
|
|
1681
|
+
applyLoaders,
|
|
1682
|
+
applyBeforeEach,
|
|
1683
|
+
applyAfterEach,
|
|
1684
|
+
unboundStoryFn,
|
|
1685
|
+
playFunction,
|
|
1686
|
+
runStep
|
|
1687
|
+
} = story;
|
|
1688
|
+
forceRemount && !initial && (this.cancelRender(), this.abortController = new AbortController2());
|
|
1689
|
+
let abortSignal = this.abortController.signal, mounted = !1, isMountDestructured = story.usesMount;
|
|
1690
|
+
try {
|
|
1691
|
+
let context = {
|
|
1692
|
+
...this.storyContext(),
|
|
1693
|
+
viewMode: this.viewMode,
|
|
1694
|
+
abortSignal,
|
|
1695
|
+
canvasElement,
|
|
1696
|
+
loaded: {},
|
|
1697
|
+
step: (label, play) => runStep(label, play, context),
|
|
1698
|
+
context: null,
|
|
1699
|
+
canvas: {},
|
|
1700
|
+
userEvent: {},
|
|
1701
|
+
renderToCanvas: async () => {
|
|
1702
|
+
let teardown = await this.renderToScreen(renderContext, canvasElement);
|
|
1703
|
+
this.teardownRender = teardown || (() => {
|
|
1704
|
+
}), mounted = !0;
|
|
1705
|
+
},
|
|
1706
|
+
// The story provides (set in a renderer) a mount function that is a higher order function
|
|
1707
|
+
// (context) => (...args) => Canvas
|
|
1708
|
+
//
|
|
1709
|
+
// Before assigning it to the context, we resolve the context dependency,
|
|
1710
|
+
// so that a user can just call it as await mount(...args) in their play function.
|
|
1711
|
+
mount: async (...args) => {
|
|
1712
|
+
this.callbacks.showStoryDuringRender?.();
|
|
1713
|
+
let mountReturn = null;
|
|
1714
|
+
return await this.runPhase(abortSignal, "rendering", async () => {
|
|
1715
|
+
mountReturn = await story.mount(context)(...args);
|
|
1716
|
+
}), isMountDestructured && await this.runPhase(abortSignal, "playing"), mountReturn;
|
|
1717
|
+
}
|
|
1718
|
+
};
|
|
1719
|
+
context.context = context;
|
|
1720
|
+
let renderContext = {
|
|
1721
|
+
componentId,
|
|
1722
|
+
title,
|
|
1723
|
+
kind: title,
|
|
1724
|
+
id,
|
|
1725
|
+
name,
|
|
1726
|
+
story: name,
|
|
1727
|
+
tags,
|
|
1728
|
+
...this.callbacks,
|
|
1729
|
+
showError: (error) => (this.phase = "errored", this.callbacks.showError(error)),
|
|
1730
|
+
showException: (error) => (this.phase = "errored", this.callbacks.showException(error)),
|
|
1731
|
+
forceRemount: forceRemount || this.notYetRendered,
|
|
1732
|
+
storyContext: context,
|
|
1733
|
+
storyFn: () => unboundStoryFn(context),
|
|
1734
|
+
unboundStoryFn
|
|
1735
|
+
};
|
|
1736
|
+
if (await this.runPhase(abortSignal, "loading", async () => {
|
|
1737
|
+
context.loaded = await applyLoaders(context);
|
|
1738
|
+
}), abortSignal.aborted)
|
|
1739
|
+
return;
|
|
1740
|
+
let cleanupCallbacks = await applyBeforeEach(context);
|
|
1741
|
+
if (this.store.addCleanupCallbacks(story, ...cleanupCallbacks), this.checkIfAborted(abortSignal) || (!mounted && !isMountDestructured && await context.mount(), this.notYetRendered = !1, abortSignal.aborted))
|
|
1742
|
+
return;
|
|
1743
|
+
let ignoreUnhandledErrors = this.story.parameters?.test?.dangerouslyIgnoreUnhandledErrors === !0, unhandledErrors = /* @__PURE__ */ new Set(), onError = (event) => {
|
|
1744
|
+
event.error && unhandledErrors.add(event.error);
|
|
1745
|
+
}, onUnhandledRejection = (event) => {
|
|
1746
|
+
event.reason && unhandledErrors.add(event.reason);
|
|
1747
|
+
};
|
|
1748
|
+
if (this.renderOptions.autoplay && forceRemount && playFunction && this.phase !== "errored") {
|
|
1749
|
+
window?.addEventListener?.("error", onError), window?.addEventListener?.("unhandledrejection", onUnhandledRejection), this.disableKeyListeners = !0;
|
|
1750
|
+
try {
|
|
1751
|
+
if (isMountDestructured ? await playFunction(context) : (context.mount = async () => {
|
|
1752
|
+
throw new MountMustBeDestructuredError2({ playFunction: playFunction.toString() });
|
|
1753
|
+
}, await this.runPhase(abortSignal, "playing", async () => playFunction(context))), !mounted)
|
|
1754
|
+
throw new NoStoryMountedError();
|
|
1755
|
+
this.checkIfAborted(abortSignal), !ignoreUnhandledErrors && unhandledErrors.size > 0 ? await this.runPhase(abortSignal, "errored") : await this.runPhase(abortSignal, "played");
|
|
1756
|
+
} catch (error) {
|
|
1757
|
+
if (this.callbacks.showStoryDuringRender?.(), await this.runPhase(abortSignal, "errored", async () => {
|
|
1758
|
+
this.channel.emit(PLAY_FUNCTION_THREW_EXCEPTION, serializeError(error));
|
|
1759
|
+
}), this.story.parameters.throwPlayFunctionExceptions !== !1)
|
|
1760
|
+
throw error;
|
|
1761
|
+
console.error(error);
|
|
1762
|
+
}
|
|
1763
|
+
if (!ignoreUnhandledErrors && unhandledErrors.size > 0 && this.channel.emit(
|
|
1764
|
+
UNHANDLED_ERRORS_WHILE_PLAYING,
|
|
1765
|
+
Array.from(unhandledErrors).map(serializeError)
|
|
1766
|
+
), this.disableKeyListeners = !1, window?.removeEventListener?.("unhandledrejection", onUnhandledRejection), window?.removeEventListener?.("error", onError), abortSignal.aborted)
|
|
1767
|
+
return;
|
|
1768
|
+
}
|
|
1769
|
+
await this.runPhase(abortSignal, "completing", async () => {
|
|
1770
|
+
isTestEnvironment() ? this.store.addCleanupCallbacks(story, pauseAnimations()) : await waitForAnimations(abortSignal);
|
|
1771
|
+
}), await this.runPhase(abortSignal, "completed", async () => {
|
|
1772
|
+
this.channel.emit(STORY_RENDERED2, id);
|
|
1773
|
+
}), this.phase !== "errored" && await this.runPhase(abortSignal, "afterEach", async () => {
|
|
1774
|
+
await applyAfterEach(context);
|
|
1775
|
+
});
|
|
1776
|
+
let hasUnhandledErrors = !ignoreUnhandledErrors && unhandledErrors.size > 0, hasSomeReportsFailed = context.reporting.reports.some(
|
|
1777
|
+
(report) => report.status === "failed"
|
|
1778
|
+
), hasStoryErrored = hasUnhandledErrors || hasSomeReportsFailed;
|
|
1779
|
+
await this.runPhase(
|
|
1780
|
+
abortSignal,
|
|
1781
|
+
"finished",
|
|
1782
|
+
async () => this.channel.emit(STORY_FINISHED, {
|
|
1783
|
+
storyId: id,
|
|
1784
|
+
status: hasStoryErrored ? "error" : "success",
|
|
1785
|
+
reporters: context.reporting.reports
|
|
1786
|
+
})
|
|
1787
|
+
);
|
|
1788
|
+
} catch (err) {
|
|
1789
|
+
this.phase = "errored", this.callbacks.showException(err), await this.runPhase(
|
|
1790
|
+
abortSignal,
|
|
1791
|
+
"finished",
|
|
1792
|
+
async () => this.channel.emit(STORY_FINISHED, {
|
|
1793
|
+
storyId: id,
|
|
1794
|
+
status: "error",
|
|
1795
|
+
reporters: []
|
|
1796
|
+
})
|
|
1797
|
+
);
|
|
1798
|
+
}
|
|
1799
|
+
this.rerenderEnqueued && (this.rerenderEnqueued = !1, this.render());
|
|
1800
|
+
}
|
|
1801
|
+
/**
|
|
1802
|
+
* Rerender the story. If the story is currently pending (loading/rendering), the rerender will be
|
|
1803
|
+
* enqueued, and will be executed after the current render is completed. Rerendering while playing
|
|
1804
|
+
* will not be enqueued, and will be executed immediately, to support rendering args changes while
|
|
1805
|
+
* playing.
|
|
1806
|
+
*/
|
|
1807
|
+
async rerender() {
|
|
1808
|
+
if (this.isPending() && this.phase !== "playing")
|
|
1809
|
+
this.rerenderEnqueued = !0;
|
|
1810
|
+
else
|
|
1811
|
+
return this.render();
|
|
1812
|
+
}
|
|
1813
|
+
async remount() {
|
|
1814
|
+
return await this.teardown(), this.render({ forceRemount: !0 });
|
|
1815
|
+
}
|
|
1816
|
+
// If the story is torn down (either a new story is rendered or the docs page removes it)
|
|
1817
|
+
// we need to consider the fact that the initial render may not be finished
|
|
1818
|
+
// (possibly the loaders or the play function are still running). We use the controller
|
|
1819
|
+
// as a method to abort them, ASAP, but this is not foolproof as we cannot control what
|
|
1820
|
+
// happens inside the user's code.
|
|
1821
|
+
cancelRender() {
|
|
1822
|
+
this.abortController.abort();
|
|
1823
|
+
}
|
|
1824
|
+
cancelPlayFunction() {
|
|
1825
|
+
this.phase === "playing" && (this.abortController.abort(), this.runPhase(this.abortController.signal, "aborted"));
|
|
1826
|
+
}
|
|
1827
|
+
async teardown() {
|
|
1828
|
+
this.torndown = !0, this.cancelRender(), this.story && await this.store.cleanupStory(this.story);
|
|
1829
|
+
for (let i = 0; i < 3; i += 1) {
|
|
1830
|
+
if (!this.isPending()) {
|
|
1831
|
+
await this.teardownRender();
|
|
1832
|
+
return;
|
|
1833
|
+
}
|
|
1834
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1835
|
+
}
|
|
1836
|
+
window?.location?.reload?.(), await new Promise(() => {
|
|
1837
|
+
});
|
|
1838
|
+
}
|
|
1839
|
+
};
|
|
1840
|
+
|
|
1841
|
+
// src/preview-api/modules/preview-web/Preview.tsx
|
|
1842
|
+
var { fetch } = global5, STORY_INDEX_PATH = "./index.json", Preview = class {
|
|
1843
|
+
constructor(importFn, getProjectAnnotations, channel = addons.getChannel(), shouldInitialize = !0) {
|
|
1844
|
+
this.importFn = importFn;
|
|
1845
|
+
this.getProjectAnnotations = getProjectAnnotations;
|
|
1846
|
+
this.channel = channel;
|
|
1847
|
+
this.storyRenders = [];
|
|
1848
|
+
this.storeInitializationPromise = new Promise((resolve, reject) => {
|
|
1849
|
+
this.resolveStoreInitializationPromise = resolve, this.rejectStoreInitializationPromise = reject;
|
|
1850
|
+
}), shouldInitialize && this.initialize();
|
|
1851
|
+
}
|
|
1852
|
+
// Create a proxy object for `__STORYBOOK_STORY_STORE__` and `__STORYBOOK_PREVIEW__.storyStore`
|
|
1853
|
+
// That proxies through to the store once ready, and errors beforehand. This means we can set
|
|
1854
|
+
// `__STORYBOOK_STORY_STORE__ = __STORYBOOK_PREVIEW__.storyStore` without having to wait, and
|
|
1855
|
+
// similarly integrators can access the `storyStore` on the preview at any time, although
|
|
1856
|
+
// it is considered deprecated and we will no longer allow access in 9.0
|
|
1857
|
+
get storyStore() {
|
|
1858
|
+
return new Proxy(
|
|
1859
|
+
{},
|
|
1860
|
+
{
|
|
1861
|
+
get: (_, method) => {
|
|
1862
|
+
if (this.storyStoreValue)
|
|
1863
|
+
return deprecate2("Accessing the Story Store is deprecated and will be removed in 9.0"), this.storyStoreValue[method];
|
|
1864
|
+
throw new StoryStoreAccessedBeforeInitializationError();
|
|
1865
|
+
}
|
|
1866
|
+
}
|
|
1867
|
+
);
|
|
1868
|
+
}
|
|
1869
|
+
// INITIALIZATION
|
|
1870
|
+
async initialize() {
|
|
1871
|
+
this.setupListeners();
|
|
1872
|
+
try {
|
|
1873
|
+
let projectAnnotations = await this.getProjectAnnotationsOrRenderError();
|
|
1874
|
+
await this.runBeforeAllHook(projectAnnotations), await this.initializeWithProjectAnnotations(projectAnnotations);
|
|
1875
|
+
let userAgent = globalThis?.navigator?.userAgent;
|
|
1876
|
+
await this.channel.emit(PREVIEW_INITIALIZED, { userAgent });
|
|
1877
|
+
} catch (err) {
|
|
1878
|
+
this.rejectStoreInitializationPromise(err);
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
ready() {
|
|
1882
|
+
return this.storeInitializationPromise;
|
|
1883
|
+
}
|
|
1884
|
+
setupListeners() {
|
|
1885
|
+
this.channel.on(STORY_INDEX_INVALIDATED, this.onStoryIndexChanged.bind(this)), this.channel.on(UPDATE_GLOBALS2, this.onUpdateGlobals.bind(this)), this.channel.on(UPDATE_STORY_ARGS2, this.onUpdateArgs.bind(this)), this.channel.on(ARGTYPES_INFO_REQUEST, this.onRequestArgTypesInfo.bind(this)), this.channel.on(RESET_STORY_ARGS2, this.onResetArgs.bind(this)), this.channel.on(FORCE_RE_RENDER2, this.onForceReRender.bind(this)), this.channel.on(FORCE_REMOUNT, this.onForceRemount.bind(this)), this.channel.on(STORY_HOT_UPDATED, this.onStoryHotUpdated.bind(this));
|
|
1886
|
+
}
|
|
1887
|
+
async getProjectAnnotationsOrRenderError() {
|
|
1888
|
+
try {
|
|
1889
|
+
let projectAnnotations = await this.getProjectAnnotations();
|
|
1890
|
+
if (this.renderToCanvas = projectAnnotations.renderToCanvas, !this.renderToCanvas)
|
|
1891
|
+
throw new MissingRenderToCanvasError();
|
|
1892
|
+
return projectAnnotations;
|
|
1893
|
+
} catch (err) {
|
|
1894
|
+
throw this.renderPreviewEntryError("Error reading preview.js:", err), err;
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
// If initialization gets as far as project annotations, this function runs.
|
|
1898
|
+
async initializeWithProjectAnnotations(projectAnnotations) {
|
|
1899
|
+
this.projectAnnotationsBeforeInitialization = projectAnnotations;
|
|
1900
|
+
try {
|
|
1901
|
+
let storyIndex = await this.getStoryIndexFromServer();
|
|
1902
|
+
return this.initializeWithStoryIndex(storyIndex);
|
|
1903
|
+
} catch (err) {
|
|
1904
|
+
throw this.renderPreviewEntryError("Error loading story index:", err), err;
|
|
1905
|
+
}
|
|
1906
|
+
}
|
|
1907
|
+
async runBeforeAllHook(projectAnnotations) {
|
|
1908
|
+
try {
|
|
1909
|
+
await this.beforeAllCleanup?.(), this.beforeAllCleanup = await projectAnnotations.beforeAll?.();
|
|
1910
|
+
} catch (err) {
|
|
1911
|
+
throw this.renderPreviewEntryError("Error in beforeAll hook:", err), err;
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
async getStoryIndexFromServer() {
|
|
1915
|
+
let result = await fetch(STORY_INDEX_PATH);
|
|
1916
|
+
if (result.status === 200)
|
|
1917
|
+
return result.json();
|
|
1918
|
+
throw new StoryIndexFetchError({ text: await result.text() });
|
|
1919
|
+
}
|
|
1920
|
+
// If initialization gets as far as the story index, this function runs.
|
|
1921
|
+
initializeWithStoryIndex(storyIndex) {
|
|
1922
|
+
if (!this.projectAnnotationsBeforeInitialization)
|
|
1923
|
+
throw new Error("Cannot call initializeWithStoryIndex until project annotations resolve");
|
|
1924
|
+
this.storyStoreValue = new StoryStore(
|
|
1925
|
+
storyIndex,
|
|
1926
|
+
this.importFn,
|
|
1927
|
+
this.projectAnnotationsBeforeInitialization
|
|
1928
|
+
), delete this.projectAnnotationsBeforeInitialization, this.setInitialGlobals(), this.resolveStoreInitializationPromise();
|
|
1929
|
+
}
|
|
1930
|
+
async setInitialGlobals() {
|
|
1931
|
+
this.emitGlobals();
|
|
1932
|
+
}
|
|
1933
|
+
emitGlobals() {
|
|
1934
|
+
if (!this.storyStoreValue)
|
|
1935
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "emitGlobals" });
|
|
1936
|
+
let payload = {
|
|
1937
|
+
globals: this.storyStoreValue.userGlobals.get() || {},
|
|
1938
|
+
globalTypes: this.storyStoreValue.projectAnnotations.globalTypes || {}
|
|
1939
|
+
};
|
|
1940
|
+
this.channel.emit(SET_GLOBALS, payload);
|
|
1941
|
+
}
|
|
1942
|
+
// EVENT HANDLERS
|
|
1943
|
+
// This happens when a config file gets reloaded
|
|
1944
|
+
async onGetProjectAnnotationsChanged({
|
|
1945
|
+
getProjectAnnotations
|
|
1946
|
+
}) {
|
|
1947
|
+
delete this.previewEntryError, this.getProjectAnnotations = getProjectAnnotations;
|
|
1948
|
+
let projectAnnotations = await this.getProjectAnnotationsOrRenderError();
|
|
1949
|
+
if (await this.runBeforeAllHook(projectAnnotations), !this.storyStoreValue) {
|
|
1950
|
+
await this.initializeWithProjectAnnotations(projectAnnotations);
|
|
1951
|
+
return;
|
|
1952
|
+
}
|
|
1953
|
+
this.storyStoreValue.setProjectAnnotations(projectAnnotations), this.emitGlobals();
|
|
1954
|
+
}
|
|
1955
|
+
async onStoryIndexChanged() {
|
|
1956
|
+
if (delete this.previewEntryError, !(!this.storyStoreValue && !this.projectAnnotationsBeforeInitialization))
|
|
1957
|
+
try {
|
|
1958
|
+
let storyIndex = await this.getStoryIndexFromServer();
|
|
1959
|
+
if (this.projectAnnotationsBeforeInitialization) {
|
|
1960
|
+
this.initializeWithStoryIndex(storyIndex);
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
await this.onStoriesChanged({ storyIndex });
|
|
1964
|
+
} catch (err) {
|
|
1965
|
+
throw this.renderPreviewEntryError("Error loading story index:", err), err;
|
|
1966
|
+
}
|
|
1967
|
+
}
|
|
1968
|
+
// This happens when a glob gets HMR-ed
|
|
1969
|
+
async onStoriesChanged({
|
|
1970
|
+
importFn,
|
|
1971
|
+
storyIndex
|
|
1972
|
+
}) {
|
|
1973
|
+
if (!this.storyStoreValue)
|
|
1974
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onStoriesChanged" });
|
|
1975
|
+
await this.storyStoreValue.onStoriesChanged({ importFn, storyIndex });
|
|
1976
|
+
}
|
|
1977
|
+
async onUpdateGlobals({
|
|
1978
|
+
globals: updatedGlobals,
|
|
1979
|
+
currentStory
|
|
1980
|
+
}) {
|
|
1981
|
+
if (this.storyStoreValue || await this.storeInitializationPromise, !this.storyStoreValue)
|
|
1982
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onUpdateGlobals" });
|
|
1983
|
+
if (this.storyStoreValue.userGlobals.update(updatedGlobals), currentStory) {
|
|
1984
|
+
let { initialGlobals, storyGlobals, userGlobals, globals } = this.storyStoreValue.getStoryContext(currentStory);
|
|
1985
|
+
this.channel.emit(GLOBALS_UPDATED, {
|
|
1986
|
+
initialGlobals,
|
|
1987
|
+
userGlobals,
|
|
1988
|
+
storyGlobals,
|
|
1989
|
+
globals
|
|
1990
|
+
});
|
|
1991
|
+
} else {
|
|
1992
|
+
let { initialGlobals, globals } = this.storyStoreValue.userGlobals;
|
|
1993
|
+
this.channel.emit(GLOBALS_UPDATED, {
|
|
1994
|
+
initialGlobals,
|
|
1995
|
+
userGlobals: globals,
|
|
1996
|
+
storyGlobals: {},
|
|
1997
|
+
globals
|
|
1998
|
+
});
|
|
1999
|
+
}
|
|
2000
|
+
await Promise.all(this.storyRenders.map((r) => r.rerender()));
|
|
2001
|
+
}
|
|
2002
|
+
async onUpdateArgs({ storyId, updatedArgs }) {
|
|
2003
|
+
if (!this.storyStoreValue)
|
|
2004
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onUpdateArgs" });
|
|
2005
|
+
this.storyStoreValue.args.update(storyId, updatedArgs), await Promise.all(
|
|
2006
|
+
this.storyRenders.filter((r) => r.id === storyId && !r.renderOptions.forceInitialArgs).map(
|
|
2007
|
+
(r) => (
|
|
2008
|
+
// We only run the play function, with in a force remount.
|
|
2009
|
+
// But when mount is destructured, the rendering happens inside of the play function.
|
|
2010
|
+
r.story && r.story.usesMount ? r.remount() : r.rerender()
|
|
2011
|
+
)
|
|
2012
|
+
)
|
|
2013
|
+
), this.channel.emit(STORY_ARGS_UPDATED, {
|
|
2014
|
+
storyId,
|
|
2015
|
+
args: this.storyStoreValue.args.get(storyId)
|
|
2016
|
+
});
|
|
2017
|
+
}
|
|
2018
|
+
async onRequestArgTypesInfo({ id, payload }) {
|
|
2019
|
+
try {
|
|
2020
|
+
await this.storeInitializationPromise;
|
|
2021
|
+
let story = await this.storyStoreValue?.loadStory(payload);
|
|
2022
|
+
this.channel.emit(ARGTYPES_INFO_RESPONSE, {
|
|
2023
|
+
id,
|
|
2024
|
+
success: !0,
|
|
2025
|
+
payload: { argTypes: story?.argTypes || {} },
|
|
2026
|
+
error: null
|
|
2027
|
+
});
|
|
2028
|
+
} catch (e) {
|
|
2029
|
+
this.channel.emit(ARGTYPES_INFO_RESPONSE, {
|
|
2030
|
+
id,
|
|
2031
|
+
success: !1,
|
|
2032
|
+
error: e?.message
|
|
2033
|
+
});
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
async onResetArgs({ storyId, argNames }) {
|
|
2037
|
+
if (!this.storyStoreValue)
|
|
2038
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "onResetArgs" });
|
|
2039
|
+
let story = this.storyRenders.find((r) => r.id === storyId)?.story || await this.storyStoreValue.loadStory({ storyId }), updatedArgs = (argNames || [
|
|
2040
|
+
.../* @__PURE__ */ new Set([
|
|
2041
|
+
...Object.keys(story.initialArgs),
|
|
2042
|
+
...Object.keys(this.storyStoreValue.args.get(storyId))
|
|
2043
|
+
])
|
|
2044
|
+
]).reduce((acc, argName) => (acc[argName] = story.initialArgs[argName], acc), {});
|
|
2045
|
+
await this.onUpdateArgs({ storyId, updatedArgs });
|
|
2046
|
+
}
|
|
2047
|
+
// ForceReRender does not include a story id, so we simply must
|
|
2048
|
+
// re-render all stories in case they are relevant
|
|
2049
|
+
async onForceReRender() {
|
|
2050
|
+
await Promise.all(this.storyRenders.map((r) => r.rerender()));
|
|
2051
|
+
}
|
|
2052
|
+
async onForceRemount({ storyId }) {
|
|
2053
|
+
await Promise.all(this.storyRenders.filter((r) => r.id === storyId).map((r) => r.remount()));
|
|
2054
|
+
}
|
|
2055
|
+
async onStoryHotUpdated() {
|
|
2056
|
+
await Promise.all(this.storyRenders.map((r) => r.cancelPlayFunction()));
|
|
2057
|
+
}
|
|
2058
|
+
// Used by docs to render a story to a given element
|
|
2059
|
+
// Note this short-circuits the `prepare()` phase of the StoryRender,
|
|
2060
|
+
// main to be consistent with the previous behaviour. In the future,
|
|
2061
|
+
// we will change it to go ahead and load the story, which will end up being
|
|
2062
|
+
// "instant", although async.
|
|
2063
|
+
renderStoryToElement(story, element, callbacks, options) {
|
|
2064
|
+
if (!this.renderToCanvas || !this.storyStoreValue)
|
|
2065
|
+
throw new CalledPreviewMethodBeforeInitializationError({
|
|
2066
|
+
methodName: "renderStoryToElement"
|
|
2067
|
+
});
|
|
2068
|
+
let render = new StoryRender(
|
|
2069
|
+
this.channel,
|
|
2070
|
+
this.storyStoreValue,
|
|
2071
|
+
this.renderToCanvas,
|
|
2072
|
+
callbacks,
|
|
2073
|
+
story.id,
|
|
2074
|
+
"docs",
|
|
2075
|
+
options,
|
|
2076
|
+
story
|
|
2077
|
+
);
|
|
2078
|
+
return render.renderToElement(element), this.storyRenders.push(render), async () => {
|
|
2079
|
+
await this.teardownRender(render);
|
|
2080
|
+
};
|
|
2081
|
+
}
|
|
2082
|
+
async teardownRender(render, { viewModeChanged } = {}) {
|
|
2083
|
+
this.storyRenders = this.storyRenders.filter((r) => r !== render), await render?.teardown?.({ viewModeChanged });
|
|
2084
|
+
}
|
|
2085
|
+
// API
|
|
2086
|
+
async loadStory({ storyId }) {
|
|
2087
|
+
if (!this.storyStoreValue)
|
|
2088
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "loadStory" });
|
|
2089
|
+
return this.storyStoreValue.loadStory({ storyId });
|
|
2090
|
+
}
|
|
2091
|
+
getStoryContext(story, { forceInitialArgs = !1 } = {}) {
|
|
2092
|
+
if (!this.storyStoreValue)
|
|
2093
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "getStoryContext" });
|
|
2094
|
+
return this.storyStoreValue.getStoryContext(story, { forceInitialArgs });
|
|
2095
|
+
}
|
|
2096
|
+
async extract(options) {
|
|
2097
|
+
if (!this.storyStoreValue)
|
|
2098
|
+
throw new CalledPreviewMethodBeforeInitializationError({ methodName: "extract" });
|
|
2099
|
+
if (this.previewEntryError)
|
|
2100
|
+
throw this.previewEntryError;
|
|
2101
|
+
return await this.storyStoreValue.cacheAllCSFFiles(), this.storyStoreValue.extract(options);
|
|
2102
|
+
}
|
|
2103
|
+
// UTILITIES
|
|
2104
|
+
renderPreviewEntryError(reason, err) {
|
|
2105
|
+
this.previewEntryError = err, logger7.error(reason), logger7.error(err), this.channel.emit(CONFIG_ERROR, err);
|
|
2106
|
+
}
|
|
2107
|
+
};
|
|
2108
|
+
|
|
2109
|
+
// src/preview-api/modules/preview-web/PreviewWeb.tsx
|
|
2110
|
+
import { global as global8 } from "@storybook/global";
|
|
2111
|
+
|
|
2112
|
+
// src/preview-api/modules/preview-web/PreviewWithSelection.tsx
|
|
2113
|
+
import { logger as logger8 } from "storybook/internal/client-logger";
|
|
2114
|
+
import {
|
|
2115
|
+
CURRENT_STORY_WAS_SET,
|
|
2116
|
+
DOCS_PREPARED,
|
|
2117
|
+
GLOBALS_UPDATED as GLOBALS_UPDATED2,
|
|
2118
|
+
PRELOAD_ENTRIES,
|
|
2119
|
+
PREVIEW_KEYDOWN,
|
|
2120
|
+
SET_CURRENT_STORY,
|
|
2121
|
+
STORY_CHANGED,
|
|
2122
|
+
STORY_ERRORED,
|
|
2123
|
+
STORY_MISSING,
|
|
2124
|
+
STORY_PREPARED,
|
|
2125
|
+
STORY_RENDER_PHASE_CHANGED as STORY_RENDER_PHASE_CHANGED2,
|
|
2126
|
+
STORY_SPECIFIED,
|
|
2127
|
+
STORY_THREW_EXCEPTION,
|
|
2128
|
+
STORY_UNCHANGED,
|
|
2129
|
+
UPDATE_QUERY_PARAMS
|
|
2130
|
+
} from "storybook/internal/core-events";
|
|
2131
|
+
import {
|
|
2132
|
+
CalledPreviewMethodBeforeInitializationError as CalledPreviewMethodBeforeInitializationError2,
|
|
2133
|
+
EmptyIndexError,
|
|
2134
|
+
MdxFileWithNoCsfReferencesError,
|
|
2135
|
+
NoStoryMatchError
|
|
2136
|
+
} from "storybook/internal/preview-errors";
|
|
2137
|
+
|
|
2138
|
+
// src/preview-api/modules/preview-web/render/CsfDocsRender.ts
|
|
2139
|
+
import { DOCS_RENDERED } from "storybook/internal/core-events";
|
|
2140
|
+
|
|
2141
|
+
// src/preview-api/modules/preview-web/docs-context/DocsContext.ts
|
|
2142
|
+
import { isStory as isStory3 } from "storybook/internal/csf";
|
|
2143
|
+
var DocsContext = class {
|
|
2144
|
+
constructor(channel, store, renderStoryToElement, csfFiles) {
|
|
2145
|
+
this.channel = channel;
|
|
2146
|
+
this.store = store;
|
|
2147
|
+
this.renderStoryToElement = renderStoryToElement;
|
|
2148
|
+
this.storyIdByName = (storyName) => {
|
|
2149
|
+
let storyId = this.nameToStoryId.get(storyName);
|
|
2150
|
+
if (storyId)
|
|
2151
|
+
return storyId;
|
|
2152
|
+
throw new Error(`No story found with that name: ${storyName}`);
|
|
2153
|
+
};
|
|
2154
|
+
this.componentStories = () => this.componentStoriesValue;
|
|
2155
|
+
this.componentStoriesFromCSFFile = (csfFile) => this.store.componentStoriesFromCSFFile({ csfFile });
|
|
2156
|
+
this.storyById = (storyId) => {
|
|
2157
|
+
if (!storyId) {
|
|
2158
|
+
if (!this.primaryStory)
|
|
2159
|
+
throw new Error(
|
|
2160
|
+
"No primary story defined for docs entry. Did you forget to use `<Meta>`?"
|
|
2161
|
+
);
|
|
2162
|
+
return this.primaryStory;
|
|
2163
|
+
}
|
|
2164
|
+
let csfFile = this.storyIdToCSFFile.get(storyId);
|
|
2165
|
+
if (!csfFile)
|
|
2166
|
+
throw new Error(`Called \`storyById\` for story that was never loaded: ${storyId}`);
|
|
2167
|
+
return this.store.storyFromCSFFile({ storyId, csfFile });
|
|
2168
|
+
};
|
|
2169
|
+
this.getStoryContext = (story) => ({
|
|
2170
|
+
...this.store.getStoryContext(story),
|
|
2171
|
+
loaded: {},
|
|
2172
|
+
viewMode: "docs"
|
|
2173
|
+
});
|
|
2174
|
+
this.loadStory = (id) => this.store.loadStory({ storyId: id });
|
|
2175
|
+
this.componentStoriesValue = [], this.storyIdToCSFFile = /* @__PURE__ */ new Map(), this.exportToStory = /* @__PURE__ */ new Map(), this.exportsToCSFFile = /* @__PURE__ */ new Map(), this.nameToStoryId = /* @__PURE__ */ new Map(), this.attachedCSFFiles = /* @__PURE__ */ new Set(), csfFiles.forEach((csfFile, index) => {
|
|
2176
|
+
this.referenceCSFFile(csfFile);
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
// This docs entry references this CSF file and can synchronously load the stories, as well
|
|
2180
|
+
// as reference them by module export. If the CSF is part of the "component" stories, they
|
|
2181
|
+
// can also be referenced by name and are in the componentStories list.
|
|
2182
|
+
referenceCSFFile(csfFile) {
|
|
2183
|
+
this.exportsToCSFFile.set(csfFile.moduleExports, csfFile), this.exportsToCSFFile.set(csfFile.moduleExports.default, csfFile), this.store.componentStoriesFromCSFFile({ csfFile }).forEach((story) => {
|
|
2184
|
+
let annotation = csfFile.stories[story.id];
|
|
2185
|
+
this.storyIdToCSFFile.set(annotation.id, csfFile), this.exportToStory.set(annotation.moduleExport, story);
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
attachCSFFile(csfFile) {
|
|
2189
|
+
if (!this.exportsToCSFFile.has(csfFile.moduleExports))
|
|
2190
|
+
throw new Error("Cannot attach a CSF file that has not been referenced");
|
|
2191
|
+
if (this.attachedCSFFiles.has(csfFile))
|
|
2192
|
+
return;
|
|
2193
|
+
this.attachedCSFFiles.add(csfFile), this.store.componentStoriesFromCSFFile({ csfFile }).forEach((story) => {
|
|
2194
|
+
this.nameToStoryId.set(story.name, story.id), this.componentStoriesValue.push(story), this.primaryStory || (this.primaryStory = story);
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2197
|
+
referenceMeta(metaExports, attach) {
|
|
2198
|
+
let resolved = this.resolveModuleExport(metaExports);
|
|
2199
|
+
if (resolved.type !== "meta")
|
|
2200
|
+
throw new Error(
|
|
2201
|
+
"<Meta of={} /> must reference a CSF file module export or meta export. Did you mistakenly reference your component instead of your CSF file?"
|
|
2202
|
+
);
|
|
2203
|
+
attach && this.attachCSFFile(resolved.csfFile);
|
|
2204
|
+
}
|
|
2205
|
+
get projectAnnotations() {
|
|
2206
|
+
let { projectAnnotations } = this.store;
|
|
2207
|
+
if (!projectAnnotations)
|
|
2208
|
+
throw new Error("Can't get projectAnnotations from DocsContext before they are initialized");
|
|
2209
|
+
return projectAnnotations;
|
|
2210
|
+
}
|
|
2211
|
+
resolveAttachedModuleExportType(moduleExportType) {
|
|
2212
|
+
if (moduleExportType === "story") {
|
|
2213
|
+
if (!this.primaryStory)
|
|
2214
|
+
throw new Error(
|
|
2215
|
+
"No primary story attached to this docs file, did you forget to use <Meta of={} />?"
|
|
2216
|
+
);
|
|
2217
|
+
return { type: "story", story: this.primaryStory };
|
|
2218
|
+
}
|
|
2219
|
+
if (this.attachedCSFFiles.size === 0)
|
|
2220
|
+
throw new Error(
|
|
2221
|
+
"No CSF file attached to this docs file, did you forget to use <Meta of={} />?"
|
|
2222
|
+
);
|
|
2223
|
+
let firstAttachedCSFFile = Array.from(this.attachedCSFFiles)[0];
|
|
2224
|
+
if (moduleExportType === "meta")
|
|
2225
|
+
return { type: "meta", csfFile: firstAttachedCSFFile };
|
|
2226
|
+
let { component } = firstAttachedCSFFile.meta;
|
|
2227
|
+
if (!component)
|
|
2228
|
+
throw new Error(
|
|
2229
|
+
"Attached CSF file does not defined a component, did you forget to export one?"
|
|
2230
|
+
);
|
|
2231
|
+
return { type: "component", component };
|
|
2232
|
+
}
|
|
2233
|
+
resolveModuleExport(moduleExportOrType) {
|
|
2234
|
+
let csfFile = this.exportsToCSFFile.get(moduleExportOrType);
|
|
2235
|
+
if (csfFile)
|
|
2236
|
+
return { type: "meta", csfFile };
|
|
2237
|
+
let story = this.exportToStory.get(
|
|
2238
|
+
isStory3(moduleExportOrType) ? moduleExportOrType.input : moduleExportOrType
|
|
2239
|
+
);
|
|
2240
|
+
return story ? { type: "story", story } : { type: "component", component: moduleExportOrType };
|
|
2241
|
+
}
|
|
2242
|
+
resolveOf(moduleExportOrType, validTypes = []) {
|
|
2243
|
+
let resolved;
|
|
2244
|
+
if (["component", "meta", "story"].includes(moduleExportOrType)) {
|
|
2245
|
+
let type = moduleExportOrType;
|
|
2246
|
+
resolved = this.resolveAttachedModuleExportType(type);
|
|
2247
|
+
} else
|
|
2248
|
+
resolved = this.resolveModuleExport(moduleExportOrType);
|
|
2249
|
+
if (validTypes.length && !validTypes.includes(resolved.type)) {
|
|
2250
|
+
let prettyType = resolved.type === "component" ? "component or unknown" : resolved.type;
|
|
2251
|
+
throw new Error(dedent`Invalid value passed to the 'of' prop. The value was resolved to a '${prettyType}' type but the only types for this block are: ${validTypes.join(
|
|
2252
|
+
", "
|
|
2253
|
+
)}.
|
|
2254
|
+
- Did you pass a component to the 'of' prop when the block only supports a story or a meta?
|
|
2255
|
+
- ... or vice versa?
|
|
2256
|
+
- Did you pass a story, CSF file or meta to the 'of' prop that is not indexed, ie. is not targeted by the 'stories' globs in the main configuration?`);
|
|
2257
|
+
}
|
|
2258
|
+
switch (resolved.type) {
|
|
2259
|
+
case "component":
|
|
2260
|
+
return {
|
|
2261
|
+
...resolved,
|
|
2262
|
+
projectAnnotations: this.projectAnnotations
|
|
2263
|
+
};
|
|
2264
|
+
case "meta":
|
|
2265
|
+
return {
|
|
2266
|
+
...resolved,
|
|
2267
|
+
preparedMeta: this.store.preparedMetaFromCSFFile({ csfFile: resolved.csfFile })
|
|
2268
|
+
};
|
|
2269
|
+
case "story":
|
|
2270
|
+
default:
|
|
2271
|
+
return resolved;
|
|
2272
|
+
}
|
|
2273
|
+
}
|
|
2274
|
+
};
|
|
2275
|
+
|
|
2276
|
+
// src/preview-api/modules/preview-web/render/CsfDocsRender.ts
|
|
2277
|
+
var CsfDocsRender = class {
|
|
2278
|
+
constructor(channel, store, entry, callbacks) {
|
|
2279
|
+
this.channel = channel;
|
|
2280
|
+
this.store = store;
|
|
2281
|
+
this.entry = entry;
|
|
2282
|
+
this.callbacks = callbacks;
|
|
2283
|
+
this.type = "docs";
|
|
2284
|
+
this.subtype = "csf";
|
|
2285
|
+
this.torndown = !1;
|
|
2286
|
+
this.disableKeyListeners = !1;
|
|
2287
|
+
this.preparing = !1;
|
|
2288
|
+
this.id = entry.id, this.renderId = Date.now();
|
|
2289
|
+
}
|
|
2290
|
+
isPreparing() {
|
|
2291
|
+
return this.preparing;
|
|
2292
|
+
}
|
|
2293
|
+
async prepare() {
|
|
2294
|
+
this.preparing = !0;
|
|
2295
|
+
let { entryExports, csfFiles = [] } = await this.store.loadEntry(this.id);
|
|
2296
|
+
if (this.torndown)
|
|
2297
|
+
throw PREPARE_ABORTED;
|
|
2298
|
+
let { importPath, title } = this.entry, primaryCsfFile = this.store.processCSFFileWithCache(
|
|
2299
|
+
entryExports,
|
|
2300
|
+
importPath,
|
|
2301
|
+
title
|
|
2302
|
+
), primaryStoryId = Object.keys(primaryCsfFile.stories)[0];
|
|
2303
|
+
this.story = this.store.storyFromCSFFile({ storyId: primaryStoryId, csfFile: primaryCsfFile }), this.csfFiles = [primaryCsfFile, ...csfFiles], this.preparing = !1;
|
|
2304
|
+
}
|
|
2305
|
+
isEqual(other) {
|
|
2306
|
+
return !!(this.id === other.id && this.story && this.story === other.story);
|
|
2307
|
+
}
|
|
2308
|
+
docsContext(renderStoryToElement) {
|
|
2309
|
+
if (!this.csfFiles)
|
|
2310
|
+
throw new Error("Cannot render docs before preparing");
|
|
2311
|
+
let docsContext = new DocsContext(
|
|
2312
|
+
this.channel,
|
|
2313
|
+
this.store,
|
|
2314
|
+
renderStoryToElement,
|
|
2315
|
+
this.csfFiles
|
|
2316
|
+
);
|
|
2317
|
+
return this.csfFiles.forEach((csfFile) => docsContext.attachCSFFile(csfFile)), docsContext;
|
|
2318
|
+
}
|
|
2319
|
+
async renderToElement(canvasElement, renderStoryToElement) {
|
|
2320
|
+
if (!this.story || !this.csfFiles)
|
|
2321
|
+
throw new Error("Cannot render docs before preparing");
|
|
2322
|
+
let docsContext = this.docsContext(renderStoryToElement), { docs: docsParameter } = this.story.parameters || {};
|
|
2323
|
+
if (!docsParameter)
|
|
2324
|
+
throw new Error(
|
|
2325
|
+
"Cannot render a story in viewMode=docs if `@storybook/addon-docs` is not installed"
|
|
2326
|
+
);
|
|
2327
|
+
let renderer = await docsParameter.renderer(), { render } = renderer, renderDocs = async () => {
|
|
2328
|
+
try {
|
|
2329
|
+
await render(docsContext, docsParameter, canvasElement), this.channel.emit(DOCS_RENDERED, this.id);
|
|
2330
|
+
} catch (err) {
|
|
2331
|
+
this.callbacks.showException(err);
|
|
2332
|
+
}
|
|
2333
|
+
};
|
|
2334
|
+
return this.rerender = async () => renderDocs(), this.teardownRender = async ({ viewModeChanged }) => {
|
|
2335
|
+
!viewModeChanged || !canvasElement || renderer.unmount(canvasElement);
|
|
2336
|
+
}, renderDocs();
|
|
2337
|
+
}
|
|
2338
|
+
async teardown({ viewModeChanged } = {}) {
|
|
2339
|
+
this.teardownRender?.({ viewModeChanged }), this.torndown = !0;
|
|
2340
|
+
}
|
|
2341
|
+
};
|
|
2342
|
+
|
|
2343
|
+
// src/preview-api/modules/preview-web/render/MdxDocsRender.ts
|
|
2344
|
+
import { DOCS_RENDERED as DOCS_RENDERED2 } from "storybook/internal/core-events";
|
|
2345
|
+
var MdxDocsRender = class {
|
|
2346
|
+
constructor(channel, store, entry, callbacks) {
|
|
2347
|
+
this.channel = channel;
|
|
2348
|
+
this.store = store;
|
|
2349
|
+
this.entry = entry;
|
|
2350
|
+
this.callbacks = callbacks;
|
|
2351
|
+
this.type = "docs";
|
|
2352
|
+
this.subtype = "mdx";
|
|
2353
|
+
this.torndown = !1;
|
|
2354
|
+
this.disableKeyListeners = !1;
|
|
2355
|
+
this.preparing = !1;
|
|
2356
|
+
this.id = entry.id, this.renderId = Date.now();
|
|
2357
|
+
}
|
|
2358
|
+
isPreparing() {
|
|
2359
|
+
return this.preparing;
|
|
2360
|
+
}
|
|
2361
|
+
async prepare() {
|
|
2362
|
+
this.preparing = !0;
|
|
2363
|
+
let { entryExports, csfFiles = [] } = await this.store.loadEntry(this.id);
|
|
2364
|
+
if (this.torndown)
|
|
2365
|
+
throw PREPARE_ABORTED;
|
|
2366
|
+
this.csfFiles = csfFiles, this.exports = entryExports, this.preparing = !1;
|
|
2367
|
+
}
|
|
2368
|
+
isEqual(other) {
|
|
2369
|
+
return !!(this.id === other.id && this.exports && this.exports === other.exports);
|
|
2370
|
+
}
|
|
2371
|
+
docsContext(renderStoryToElement) {
|
|
2372
|
+
if (!this.csfFiles)
|
|
2373
|
+
throw new Error("Cannot render docs before preparing");
|
|
2374
|
+
return new DocsContext(
|
|
2375
|
+
this.channel,
|
|
2376
|
+
this.store,
|
|
2377
|
+
renderStoryToElement,
|
|
2378
|
+
this.csfFiles
|
|
2379
|
+
);
|
|
2380
|
+
}
|
|
2381
|
+
async renderToElement(canvasElement, renderStoryToElement) {
|
|
2382
|
+
if (!this.exports || !this.csfFiles || !this.store.projectAnnotations)
|
|
2383
|
+
throw new Error("Cannot render docs before preparing");
|
|
2384
|
+
let docsContext = this.docsContext(renderStoryToElement), { docs } = this.store.projectAnnotations.parameters ?? {};
|
|
2385
|
+
if (!docs)
|
|
2386
|
+
throw new Error(
|
|
2387
|
+
"Cannot render a story in viewMode=docs if `@storybook/addon-docs` is not installed"
|
|
2388
|
+
);
|
|
2389
|
+
let docsParameter = { ...docs, page: this.exports.default }, renderer = await docs.renderer(), { render } = renderer, renderDocs = async () => {
|
|
2390
|
+
try {
|
|
2391
|
+
await render(docsContext, docsParameter, canvasElement), this.channel.emit(DOCS_RENDERED2, this.id);
|
|
2392
|
+
} catch (err) {
|
|
2393
|
+
this.callbacks.showException(err);
|
|
2394
|
+
}
|
|
2395
|
+
};
|
|
2396
|
+
return this.rerender = async () => renderDocs(), this.teardownRender = async ({ viewModeChanged } = {}) => {
|
|
2397
|
+
!viewModeChanged || !canvasElement || (renderer.unmount(canvasElement), this.torndown = !0);
|
|
2398
|
+
}, renderDocs();
|
|
2399
|
+
}
|
|
2400
|
+
async teardown({ viewModeChanged } = {}) {
|
|
2401
|
+
this.teardownRender?.({ viewModeChanged }), this.torndown = !0;
|
|
2402
|
+
}
|
|
2403
|
+
};
|
|
2404
|
+
|
|
2405
|
+
// src/preview-api/modules/preview-web/PreviewWithSelection.tsx
|
|
2406
|
+
var globalWindow = globalThis;
|
|
2407
|
+
function focusInInput(event) {
|
|
2408
|
+
let target = event.composedPath && event.composedPath()[0] || event.target;
|
|
2409
|
+
return /input|textarea/i.test(target.tagName) || target.getAttribute("contenteditable") !== null;
|
|
2410
|
+
}
|
|
2411
|
+
var ATTACHED_MDX_TAG = "attached-mdx", UNATTACHED_MDX_TAG = "unattached-mdx";
|
|
2412
|
+
function isMdxEntry({ tags }) {
|
|
2413
|
+
return tags?.includes(UNATTACHED_MDX_TAG) || tags?.includes(ATTACHED_MDX_TAG);
|
|
2414
|
+
}
|
|
2415
|
+
function isStoryRender(r) {
|
|
2416
|
+
return r.type === "story";
|
|
2417
|
+
}
|
|
2418
|
+
function isDocsRender(r) {
|
|
2419
|
+
return r.type === "docs";
|
|
2420
|
+
}
|
|
2421
|
+
function isCsfDocsRender(r) {
|
|
2422
|
+
return isDocsRender(r) && r.subtype === "csf";
|
|
2423
|
+
}
|
|
2424
|
+
var PreviewWithSelection = class extends Preview {
|
|
2425
|
+
constructor(importFn, getProjectAnnotations, selectionStore, view) {
|
|
2426
|
+
super(importFn, getProjectAnnotations, void 0, !1);
|
|
2427
|
+
this.importFn = importFn;
|
|
2428
|
+
this.getProjectAnnotations = getProjectAnnotations;
|
|
2429
|
+
this.selectionStore = selectionStore;
|
|
2430
|
+
this.view = view;
|
|
2431
|
+
this.initialize();
|
|
2432
|
+
}
|
|
2433
|
+
setupListeners() {
|
|
2434
|
+
super.setupListeners(), globalWindow.onkeydown = this.onKeydown.bind(this), this.channel.on(SET_CURRENT_STORY, this.onSetCurrentStory.bind(this)), this.channel.on(UPDATE_QUERY_PARAMS, this.onUpdateQueryParams.bind(this)), this.channel.on(PRELOAD_ENTRIES, this.onPreloadStories.bind(this));
|
|
2435
|
+
}
|
|
2436
|
+
async setInitialGlobals() {
|
|
2437
|
+
if (!this.storyStoreValue)
|
|
2438
|
+
throw new CalledPreviewMethodBeforeInitializationError2({ methodName: "setInitialGlobals" });
|
|
2439
|
+
let { globals } = this.selectionStore.selectionSpecifier || {};
|
|
2440
|
+
globals && this.storyStoreValue.userGlobals.updateFromPersisted(globals), this.emitGlobals();
|
|
2441
|
+
}
|
|
2442
|
+
// If initialization gets as far as the story index, this function runs.
|
|
2443
|
+
async initializeWithStoryIndex(storyIndex) {
|
|
2444
|
+
return await super.initializeWithStoryIndex(storyIndex), this.selectSpecifiedStory();
|
|
2445
|
+
}
|
|
2446
|
+
// Use the selection specifier to choose a story, then render it
|
|
2447
|
+
async selectSpecifiedStory() {
|
|
2448
|
+
if (!this.storyStoreValue)
|
|
2449
|
+
throw new CalledPreviewMethodBeforeInitializationError2({
|
|
2450
|
+
methodName: "selectSpecifiedStory"
|
|
2451
|
+
});
|
|
2452
|
+
if (this.selectionStore.selection) {
|
|
2453
|
+
await this.renderSelection();
|
|
2454
|
+
return;
|
|
2455
|
+
}
|
|
2456
|
+
if (!this.selectionStore.selectionSpecifier) {
|
|
2457
|
+
this.renderMissingStory();
|
|
2458
|
+
return;
|
|
2459
|
+
}
|
|
2460
|
+
let { storySpecifier, args } = this.selectionStore.selectionSpecifier, entry = this.storyStoreValue.storyIndex.entryFromSpecifier(storySpecifier);
|
|
2461
|
+
if (!entry) {
|
|
2462
|
+
storySpecifier === "*" ? this.renderStoryLoadingException(storySpecifier, new EmptyIndexError()) : this.renderStoryLoadingException(
|
|
2463
|
+
storySpecifier,
|
|
2464
|
+
new NoStoryMatchError({ storySpecifier: storySpecifier.toString() })
|
|
2465
|
+
);
|
|
2466
|
+
return;
|
|
2467
|
+
}
|
|
2468
|
+
let { id: storyId, type: viewMode } = entry;
|
|
2469
|
+
this.selectionStore.setSelection({ storyId, viewMode }), this.channel.emit(STORY_SPECIFIED, this.selectionStore.selection), this.channel.emit(CURRENT_STORY_WAS_SET, this.selectionStore.selection), await this.renderSelection({ persistedArgs: args });
|
|
2470
|
+
}
|
|
2471
|
+
// EVENT HANDLERS
|
|
2472
|
+
// This happens when a config file gets reloaded
|
|
2473
|
+
async onGetProjectAnnotationsChanged({
|
|
2474
|
+
getProjectAnnotations
|
|
2475
|
+
}) {
|
|
2476
|
+
await super.onGetProjectAnnotationsChanged({ getProjectAnnotations }), this.selectionStore.selection && this.renderSelection();
|
|
2477
|
+
}
|
|
2478
|
+
// This happens when a glob gets HMR-ed
|
|
2479
|
+
async onStoriesChanged({
|
|
2480
|
+
importFn,
|
|
2481
|
+
storyIndex
|
|
2482
|
+
}) {
|
|
2483
|
+
await super.onStoriesChanged({ importFn, storyIndex }), this.selectionStore.selection ? await this.renderSelection() : await this.selectSpecifiedStory();
|
|
2484
|
+
}
|
|
2485
|
+
onKeydown(event) {
|
|
2486
|
+
if (!this.storyRenders.find((r) => r.disableKeyListeners) && !focusInInput(event)) {
|
|
2487
|
+
let { altKey, ctrlKey, metaKey, shiftKey, key, code, keyCode } = event;
|
|
2488
|
+
this.channel.emit(PREVIEW_KEYDOWN, {
|
|
2489
|
+
event: { altKey, ctrlKey, metaKey, shiftKey, key, code, keyCode }
|
|
2490
|
+
});
|
|
2491
|
+
}
|
|
2492
|
+
}
|
|
2493
|
+
async onSetCurrentStory(selection) {
|
|
2494
|
+
this.selectionStore.setSelection({ viewMode: "story", ...selection }), await this.storeInitializationPromise, this.channel.emit(CURRENT_STORY_WAS_SET, this.selectionStore.selection), this.renderSelection();
|
|
2495
|
+
}
|
|
2496
|
+
onUpdateQueryParams(queryParams) {
|
|
2497
|
+
this.selectionStore.setQueryParams(queryParams);
|
|
2498
|
+
}
|
|
2499
|
+
async onUpdateGlobals({ globals }) {
|
|
2500
|
+
let currentStory = this.currentRender instanceof StoryRender && this.currentRender.story || void 0;
|
|
2501
|
+
super.onUpdateGlobals({ globals, currentStory }), (this.currentRender instanceof MdxDocsRender || this.currentRender instanceof CsfDocsRender) && await this.currentRender.rerender?.();
|
|
2502
|
+
}
|
|
2503
|
+
async onUpdateArgs({ storyId, updatedArgs }) {
|
|
2504
|
+
super.onUpdateArgs({ storyId, updatedArgs });
|
|
2505
|
+
}
|
|
2506
|
+
async onPreloadStories({ ids }) {
|
|
2507
|
+
await this.storeInitializationPromise, this.storyStoreValue && await Promise.allSettled(ids.map((id) => this.storyStoreValue?.loadEntry(id)));
|
|
2508
|
+
}
|
|
2509
|
+
// RENDERING
|
|
2510
|
+
// We can either have:
|
|
2511
|
+
// - a story selected in "story" viewMode,
|
|
2512
|
+
// in which case we render it to the root element, OR
|
|
2513
|
+
// - a story selected in "docs" viewMode,
|
|
2514
|
+
// in which case we render the docsPage for that story
|
|
2515
|
+
async renderSelection({ persistedArgs } = {}) {
|
|
2516
|
+
let { renderToCanvas } = this;
|
|
2517
|
+
if (!this.storyStoreValue || !renderToCanvas)
|
|
2518
|
+
throw new CalledPreviewMethodBeforeInitializationError2({ methodName: "renderSelection" });
|
|
2519
|
+
let { selection } = this.selectionStore;
|
|
2520
|
+
if (!selection)
|
|
2521
|
+
throw new Error("Cannot call renderSelection as no selection was made");
|
|
2522
|
+
let { storyId } = selection, entry;
|
|
2523
|
+
try {
|
|
2524
|
+
entry = await this.storyStoreValue.storyIdToEntry(storyId);
|
|
2525
|
+
} catch (err) {
|
|
2526
|
+
this.currentRender && await this.teardownRender(this.currentRender), this.renderStoryLoadingException(storyId, err);
|
|
2527
|
+
return;
|
|
2528
|
+
}
|
|
2529
|
+
let storyIdChanged = this.currentSelection?.storyId !== storyId, viewModeChanged = this.currentRender?.type !== entry.type;
|
|
2530
|
+
entry.type === "story" ? this.view.showPreparingStory({ immediate: viewModeChanged }) : this.view.showPreparingDocs({ immediate: viewModeChanged }), this.currentRender?.isPreparing() && await this.teardownRender(this.currentRender);
|
|
2531
|
+
let render;
|
|
2532
|
+
entry.type === "story" ? render = new StoryRender(
|
|
2533
|
+
this.channel,
|
|
2534
|
+
this.storyStoreValue,
|
|
2535
|
+
renderToCanvas,
|
|
2536
|
+
this.mainStoryCallbacks(storyId),
|
|
2537
|
+
storyId,
|
|
2538
|
+
"story"
|
|
2539
|
+
) : isMdxEntry(entry) ? render = new MdxDocsRender(
|
|
2540
|
+
this.channel,
|
|
2541
|
+
this.storyStoreValue,
|
|
2542
|
+
entry,
|
|
2543
|
+
this.mainStoryCallbacks(storyId)
|
|
2544
|
+
) : render = new CsfDocsRender(
|
|
2545
|
+
this.channel,
|
|
2546
|
+
this.storyStoreValue,
|
|
2547
|
+
entry,
|
|
2548
|
+
this.mainStoryCallbacks(storyId)
|
|
2549
|
+
);
|
|
2550
|
+
let lastSelection = this.currentSelection;
|
|
2551
|
+
this.currentSelection = selection;
|
|
2552
|
+
let lastRender = this.currentRender;
|
|
2553
|
+
this.currentRender = render;
|
|
2554
|
+
try {
|
|
2555
|
+
await render.prepare();
|
|
2556
|
+
} catch (err) {
|
|
2557
|
+
lastRender && await this.teardownRender(lastRender), err !== PREPARE_ABORTED && this.renderStoryLoadingException(storyId, err);
|
|
2558
|
+
return;
|
|
2559
|
+
}
|
|
2560
|
+
let implementationChanged = !storyIdChanged && lastRender && !render.isEqual(lastRender);
|
|
2561
|
+
if (persistedArgs && isStoryRender(render) && (invariant(!!render.story), this.storyStoreValue.args.updateFromPersisted(render.story, persistedArgs)), lastRender && !lastRender.torndown && !storyIdChanged && !implementationChanged && !viewModeChanged) {
|
|
2562
|
+
this.currentRender = lastRender, this.channel.emit(STORY_UNCHANGED, storyId), this.view.showMain();
|
|
2563
|
+
return;
|
|
2564
|
+
}
|
|
2565
|
+
if (lastRender && await this.teardownRender(lastRender, { viewModeChanged }), lastSelection && (storyIdChanged || viewModeChanged) && this.channel.emit(STORY_CHANGED, storyId), isStoryRender(render)) {
|
|
2566
|
+
invariant(!!render.story);
|
|
2567
|
+
let {
|
|
2568
|
+
parameters,
|
|
2569
|
+
initialArgs,
|
|
2570
|
+
argTypes,
|
|
2571
|
+
unmappedArgs,
|
|
2572
|
+
initialGlobals,
|
|
2573
|
+
userGlobals,
|
|
2574
|
+
storyGlobals,
|
|
2575
|
+
globals
|
|
2576
|
+
} = this.storyStoreValue.getStoryContext(render.story);
|
|
2577
|
+
this.channel.emit(STORY_PREPARED, {
|
|
2578
|
+
id: storyId,
|
|
2579
|
+
parameters,
|
|
2580
|
+
initialArgs,
|
|
2581
|
+
argTypes,
|
|
2582
|
+
args: unmappedArgs
|
|
2583
|
+
}), this.channel.emit(GLOBALS_UPDATED2, { userGlobals, storyGlobals, globals, initialGlobals });
|
|
2584
|
+
} else {
|
|
2585
|
+
let { parameters } = this.storyStoreValue.projectAnnotations, { initialGlobals, globals } = this.storyStoreValue.userGlobals;
|
|
2586
|
+
if (this.channel.emit(GLOBALS_UPDATED2, {
|
|
2587
|
+
globals,
|
|
2588
|
+
initialGlobals,
|
|
2589
|
+
storyGlobals: {},
|
|
2590
|
+
userGlobals: globals
|
|
2591
|
+
}), isCsfDocsRender(render) || render.entry.tags?.includes(ATTACHED_MDX_TAG)) {
|
|
2592
|
+
if (!render.csfFiles)
|
|
2593
|
+
throw new MdxFileWithNoCsfReferencesError({ storyId });
|
|
2594
|
+
({ parameters } = this.storyStoreValue.preparedMetaFromCSFFile({
|
|
2595
|
+
csfFile: render.csfFiles[0]
|
|
2596
|
+
}));
|
|
2597
|
+
}
|
|
2598
|
+
this.channel.emit(DOCS_PREPARED, {
|
|
2599
|
+
id: storyId,
|
|
2600
|
+
parameters
|
|
2601
|
+
});
|
|
2602
|
+
}
|
|
2603
|
+
isStoryRender(render) ? (invariant(!!render.story), this.storyRenders.push(render), this.currentRender.renderToElement(
|
|
2604
|
+
this.view.prepareForStory(render.story)
|
|
2605
|
+
)) : this.currentRender.renderToElement(
|
|
2606
|
+
this.view.prepareForDocs(),
|
|
2607
|
+
// This argument is used for docs, which is currently only compatible with HTMLElements
|
|
2608
|
+
this.renderStoryToElement.bind(this)
|
|
2609
|
+
);
|
|
2610
|
+
}
|
|
2611
|
+
async teardownRender(render, { viewModeChanged = !1 } = {}) {
|
|
2612
|
+
this.storyRenders = this.storyRenders.filter((r) => r !== render), await render?.teardown?.({ viewModeChanged });
|
|
2613
|
+
}
|
|
2614
|
+
// UTILITIES
|
|
2615
|
+
mainStoryCallbacks(storyId) {
|
|
2616
|
+
return {
|
|
2617
|
+
showStoryDuringRender: () => this.view.showStoryDuringRender(),
|
|
2618
|
+
showMain: () => this.view.showMain(),
|
|
2619
|
+
showError: (err) => this.renderError(storyId, err),
|
|
2620
|
+
showException: (err) => this.renderException(storyId, err)
|
|
2621
|
+
};
|
|
2622
|
+
}
|
|
2623
|
+
renderPreviewEntryError(reason, err) {
|
|
2624
|
+
super.renderPreviewEntryError(reason, err), this.view.showErrorDisplay(err);
|
|
2625
|
+
}
|
|
2626
|
+
renderMissingStory() {
|
|
2627
|
+
this.view.showNoPreview(), this.channel.emit(STORY_MISSING);
|
|
2628
|
+
}
|
|
2629
|
+
renderStoryLoadingException(storySpecifier, err) {
|
|
2630
|
+
logger8.error(err), this.view.showErrorDisplay(err), this.channel.emit(STORY_MISSING, storySpecifier);
|
|
2631
|
+
}
|
|
2632
|
+
// renderException is used if we fail to render the story and it is uncaught by the app layer
|
|
2633
|
+
renderException(storyId, error) {
|
|
2634
|
+
let { name = "Error", message = String(error), stack } = error, renderId = this.currentRender?.renderId;
|
|
2635
|
+
this.channel.emit(STORY_THREW_EXCEPTION, { name, message, stack }), this.channel.emit(STORY_RENDER_PHASE_CHANGED2, { newPhase: "errored", renderId, storyId }), this.view.showErrorDisplay(error), logger8.error(`Error rendering story '${storyId}':`), logger8.error(error);
|
|
2636
|
+
}
|
|
2637
|
+
// renderError is used by the various app layers to inform the user they have done something
|
|
2638
|
+
// wrong -- for instance returned the wrong thing from a story
|
|
2639
|
+
renderError(storyId, { title, description }) {
|
|
2640
|
+
let renderId = this.currentRender?.renderId;
|
|
2641
|
+
this.channel.emit(STORY_ERRORED, { title, description }), this.channel.emit(STORY_RENDER_PHASE_CHANGED2, { newPhase: "errored", renderId, storyId }), this.view.showErrorDisplay({ message: title, stack: description }), logger8.error(`Error rendering story ${title}: ${description}`);
|
|
2642
|
+
}
|
|
2643
|
+
};
|
|
2644
|
+
|
|
2645
|
+
// src/preview-api/modules/preview-web/UrlStore.ts
|
|
2646
|
+
var import_picoquery2 = __toESM(require_main(), 1);
|
|
2647
|
+
import { global as global6 } from "@storybook/global";
|
|
2648
|
+
|
|
2649
|
+
// src/preview-api/modules/preview-web/parseArgsParam.ts
|
|
2650
|
+
import { once as once3 } from "storybook/internal/client-logger";
|
|
2651
|
+
var import_picoquery = __toESM(require_main(), 1);
|
|
2652
|
+
var VALIDATION_REGEXP = /^[a-zA-Z0-9 _-]*$/, NUMBER_REGEXP = /^-?[0-9]+(\.[0-9]+)?$/, HEX_REGEXP = /^#([a-f0-9]{3,4}|[a-f0-9]{6}|[a-f0-9]{8})$/i, COLOR_REGEXP = /^(rgba?|hsla?)\(([0-9]{1,3}),\s?([0-9]{1,3})%?,\s?([0-9]{1,3})%?,?\s?([0-9](\.[0-9]{1,2})?)?\)$/i, validateArgs = (key = "", value) => key === null || key === "" || !VALIDATION_REGEXP.test(key) ? !1 : value == null || value instanceof Date || typeof value == "number" || typeof value == "boolean" ? !0 : typeof value == "string" ? VALIDATION_REGEXP.test(value) || NUMBER_REGEXP.test(value) || HEX_REGEXP.test(value) || COLOR_REGEXP.test(value) : Array.isArray(value) ? value.every((v) => validateArgs(key, v)) : isPlainObject(value) ? Object.entries(value).every(([k, v]) => validateArgs(k, v)) : !1, QUERY_OPTIONS = {
|
|
2653
|
+
delimiter: ";",
|
|
2654
|
+
// we're parsing a single query param
|
|
2655
|
+
nesting: !0,
|
|
2656
|
+
arrayRepeat: !0,
|
|
2657
|
+
arrayRepeatSyntax: "bracket",
|
|
2658
|
+
nestingSyntax: "js",
|
|
2659
|
+
// objects are encoded using dot notation
|
|
2660
|
+
valueDeserializer(str) {
|
|
2661
|
+
if (str.startsWith("!")) {
|
|
2662
|
+
if (str === "!undefined")
|
|
2663
|
+
return;
|
|
2664
|
+
if (str === "!null")
|
|
2665
|
+
return null;
|
|
2666
|
+
if (str === "!true")
|
|
2667
|
+
return !0;
|
|
2668
|
+
if (str === "!false")
|
|
2669
|
+
return !1;
|
|
2670
|
+
if (str.startsWith("!date(") && str.endsWith(")"))
|
|
2671
|
+
return new Date(str.replaceAll(" ", "+").slice(6, -1));
|
|
2672
|
+
if (str.startsWith("!hex(") && str.endsWith(")"))
|
|
2673
|
+
return `#${str.slice(5, -1)}`;
|
|
2674
|
+
let color = str.slice(1).match(COLOR_REGEXP);
|
|
2675
|
+
if (color)
|
|
2676
|
+
return str.startsWith("!rgba") || str.startsWith("!RGBA") ? `${color[1]}(${color[2]}, ${color[3]}, ${color[4]}, ${color[5]})` : str.startsWith("!hsla") || str.startsWith("!HSLA") ? `${color[1]}(${color[2]}, ${color[3]}%, ${color[4]}%, ${color[5]})` : str.startsWith("!rgb") || str.startsWith("!RGB") ? `${color[1]}(${color[2]}, ${color[3]}, ${color[4]})` : `${color[1]}(${color[2]}, ${color[3]}%, ${color[4]}%)`;
|
|
2677
|
+
}
|
|
2678
|
+
return NUMBER_REGEXP.test(str) ? Number(str) : str;
|
|
2679
|
+
}
|
|
2680
|
+
}, parseArgsParam = (argsString) => {
|
|
2681
|
+
let parts = argsString.split(";").map((part) => part.replace("=", "~").replace(":", "="));
|
|
2682
|
+
return Object.entries((0, import_picoquery.parse)(parts.join(";"), QUERY_OPTIONS)).reduce((acc, [key, value]) => validateArgs(key, value) ? Object.assign(acc, { [key]: value }) : (once3.warn(dedent`
|
|
2683
|
+
Omitted potentially unsafe URL args.
|
|
2684
|
+
|
|
2685
|
+
More info: https://storybook.js.org/docs/writing-stories/args#setting-args-through-the-url?ref=error
|
|
2686
|
+
`), acc), {});
|
|
2687
|
+
};
|
|
2688
|
+
|
|
2689
|
+
// src/preview-api/modules/preview-web/UrlStore.ts
|
|
2690
|
+
var { history, document: document2 } = global6;
|
|
2691
|
+
function pathToId(path) {
|
|
2692
|
+
let match = (path || "").match(/^\/story\/(.+)/);
|
|
2693
|
+
if (!match)
|
|
2694
|
+
throw new Error(`Invalid path '${path}', must start with '/story/'`);
|
|
2695
|
+
return match[1];
|
|
2696
|
+
}
|
|
2697
|
+
var getQueryString = ({
|
|
2698
|
+
selection,
|
|
2699
|
+
extraParams
|
|
2700
|
+
}) => {
|
|
2701
|
+
let search = document2?.location.search.slice(1), { path, selectedKind, selectedStory, ...rest } = (0, import_picoquery2.parse)(search);
|
|
2702
|
+
return `?${(0, import_picoquery2.stringify)({
|
|
2703
|
+
...rest,
|
|
2704
|
+
...extraParams,
|
|
2705
|
+
...selection && { id: selection.storyId, viewMode: selection.viewMode }
|
|
2706
|
+
})}`;
|
|
2707
|
+
}, setPath = (selection) => {
|
|
2708
|
+
if (!selection)
|
|
2709
|
+
return;
|
|
2710
|
+
let query = getQueryString({ selection }), { hash = "" } = document2.location;
|
|
2711
|
+
document2.title = selection.storyId, history.replaceState({}, "", `${document2.location.pathname}${query}${hash}`);
|
|
2712
|
+
}, isObject = (val) => val != null && typeof val == "object" && Array.isArray(val) === !1, getFirstString = (v) => {
|
|
2713
|
+
if (v !== void 0) {
|
|
2714
|
+
if (typeof v == "string")
|
|
2715
|
+
return v;
|
|
2716
|
+
if (Array.isArray(v))
|
|
2717
|
+
return getFirstString(v[0]);
|
|
2718
|
+
if (isObject(v))
|
|
2719
|
+
return getFirstString(
|
|
2720
|
+
Object.values(v).filter(Boolean)
|
|
2721
|
+
);
|
|
2722
|
+
}
|
|
2723
|
+
}, getSelectionSpecifierFromPath = () => {
|
|
2724
|
+
if (typeof document2 < "u") {
|
|
2725
|
+
let queryStr = document2.location.search.slice(1), query = (0, import_picoquery2.parse)(queryStr), args = typeof query.args == "string" ? parseArgsParam(query.args) : void 0, globals = typeof query.globals == "string" ? parseArgsParam(query.globals) : void 0, viewMode = getFirstString(query.viewMode);
|
|
2726
|
+
if (typeof viewMode != "string" || !viewMode)
|
|
2727
|
+
viewMode = "story";
|
|
2728
|
+
else if (!viewMode.match(/docs|story/))
|
|
2729
|
+
return null;
|
|
2730
|
+
let path = getFirstString(query.path), storyId = path ? pathToId(path) : getFirstString(query.id);
|
|
2731
|
+
if (storyId)
|
|
2732
|
+
return { storySpecifier: storyId, args, globals, viewMode };
|
|
2733
|
+
}
|
|
2734
|
+
return null;
|
|
2735
|
+
}, UrlStore = class {
|
|
2736
|
+
constructor() {
|
|
2737
|
+
this.selectionSpecifier = getSelectionSpecifierFromPath();
|
|
2738
|
+
}
|
|
2739
|
+
setSelection(selection) {
|
|
2740
|
+
this.selection = selection, setPath(this.selection);
|
|
2741
|
+
}
|
|
2742
|
+
setQueryParams(queryParams) {
|
|
2743
|
+
let query = getQueryString({ extraParams: queryParams }), { hash = "" } = document2.location;
|
|
2744
|
+
history.replaceState({}, "", `${document2.location.pathname}${query}${hash}`);
|
|
2745
|
+
}
|
|
2746
|
+
};
|
|
2747
|
+
|
|
2748
|
+
// src/preview-api/modules/preview-web/WebView.ts
|
|
2749
|
+
var import_ansi_to_html = __toESM(require_ansi_to_html(), 1), import_picoquery3 = __toESM(require_main(), 1);
|
|
2750
|
+
import { logger as logger9 } from "storybook/internal/client-logger";
|
|
2751
|
+
import { global as global7 } from "@storybook/global";
|
|
2752
|
+
var { document: document3 } = global7, PREPARING_DELAY = 100, Mode = /* @__PURE__ */ ((Mode2) => (Mode2.MAIN = "MAIN", Mode2.NOPREVIEW = "NOPREVIEW", Mode2.PREPARING_STORY = "PREPARING_STORY", Mode2.PREPARING_DOCS = "PREPARING_DOCS", Mode2.ERROR = "ERROR", Mode2))(Mode || {}), classes = {
|
|
2753
|
+
PREPARING_STORY: "sb-show-preparing-story",
|
|
2754
|
+
PREPARING_DOCS: "sb-show-preparing-docs",
|
|
2755
|
+
MAIN: "sb-show-main",
|
|
2756
|
+
NOPREVIEW: "sb-show-nopreview",
|
|
2757
|
+
ERROR: "sb-show-errordisplay"
|
|
2758
|
+
}, layoutClassMap = {
|
|
2759
|
+
centered: "sb-main-centered",
|
|
2760
|
+
fullscreen: "sb-main-fullscreen",
|
|
2761
|
+
padded: "sb-main-padded"
|
|
2762
|
+
}, ansiConverter = new import_ansi_to_html.default({
|
|
2763
|
+
escapeXML: !0
|
|
2764
|
+
}), WebView = class {
|
|
2765
|
+
constructor() {
|
|
2766
|
+
this.testing = !1;
|
|
2767
|
+
if (typeof document3 < "u") {
|
|
2768
|
+
let { __SPECIAL_TEST_PARAMETER__ } = (0, import_picoquery3.parse)(document3.location.search.slice(1));
|
|
2769
|
+
switch (__SPECIAL_TEST_PARAMETER__) {
|
|
2770
|
+
case "preparing-story": {
|
|
2771
|
+
this.showPreparingStory(), this.testing = !0;
|
|
2772
|
+
break;
|
|
2773
|
+
}
|
|
2774
|
+
case "preparing-docs": {
|
|
2775
|
+
this.showPreparingDocs(), this.testing = !0;
|
|
2776
|
+
break;
|
|
2777
|
+
}
|
|
2778
|
+
default:
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
}
|
|
2782
|
+
// Get ready to render a story, returning the element to render to
|
|
2783
|
+
prepareForStory(story) {
|
|
2784
|
+
return this.showStory(), this.applyLayout(story.parameters.layout), document3.documentElement.scrollTop = 0, document3.documentElement.scrollLeft = 0, this.storyRoot();
|
|
2785
|
+
}
|
|
2786
|
+
storyRoot() {
|
|
2787
|
+
return document3.getElementById("storybook-root");
|
|
2788
|
+
}
|
|
2789
|
+
prepareForDocs() {
|
|
2790
|
+
return this.showMain(), this.showDocs(), this.applyLayout("fullscreen"), document3.documentElement.scrollTop = 0, document3.documentElement.scrollLeft = 0, this.docsRoot();
|
|
2791
|
+
}
|
|
2792
|
+
docsRoot() {
|
|
2793
|
+
return document3.getElementById("storybook-docs");
|
|
2794
|
+
}
|
|
2795
|
+
applyLayout(layout = "padded") {
|
|
2796
|
+
if (layout === "none") {
|
|
2797
|
+
document3.body.classList.remove(this.currentLayoutClass), this.currentLayoutClass = null;
|
|
2798
|
+
return;
|
|
2799
|
+
}
|
|
2800
|
+
this.checkIfLayoutExists(layout);
|
|
2801
|
+
let layoutClass = layoutClassMap[layout];
|
|
2802
|
+
document3.body.classList.remove(this.currentLayoutClass), document3.body.classList.add(layoutClass), this.currentLayoutClass = layoutClass;
|
|
2803
|
+
}
|
|
2804
|
+
checkIfLayoutExists(layout) {
|
|
2805
|
+
layoutClassMap[layout] || logger9.warn(
|
|
2806
|
+
dedent`
|
|
2807
|
+
The desired layout: ${layout} is not a valid option.
|
|
2808
|
+
The possible options are: ${Object.keys(layoutClassMap).join(", ")}, none.
|
|
2809
|
+
`
|
|
2810
|
+
);
|
|
2811
|
+
}
|
|
2812
|
+
showMode(mode) {
|
|
2813
|
+
clearTimeout(this.preparingTimeout), Object.keys(Mode).forEach((otherMode) => {
|
|
2814
|
+
otherMode === mode ? document3.body.classList.add(classes[otherMode]) : document3.body.classList.remove(classes[otherMode]);
|
|
2815
|
+
});
|
|
2816
|
+
}
|
|
2817
|
+
showErrorDisplay({ message = "", stack = "" }) {
|
|
2818
|
+
let header = message, detail = stack, parts = message.split(`
|
|
2819
|
+
`);
|
|
2820
|
+
parts.length > 1 && ([header] = parts, detail = parts.slice(1).join(`
|
|
2821
|
+
`).replace(/^\n/, "")), document3.getElementById("error-message").innerHTML = ansiConverter.toHtml(header), document3.getElementById("error-stack").innerHTML = ansiConverter.toHtml(detail), this.showMode("ERROR" /* ERROR */);
|
|
2822
|
+
}
|
|
2823
|
+
showNoPreview() {
|
|
2824
|
+
this.testing || (this.showMode("NOPREVIEW" /* NOPREVIEW */), this.storyRoot()?.setAttribute("hidden", "true"), this.docsRoot()?.setAttribute("hidden", "true"));
|
|
2825
|
+
}
|
|
2826
|
+
showPreparingStory({ immediate = !1 } = {}) {
|
|
2827
|
+
clearTimeout(this.preparingTimeout), immediate ? this.showMode("PREPARING_STORY" /* PREPARING_STORY */) : this.preparingTimeout = setTimeout(
|
|
2828
|
+
() => this.showMode("PREPARING_STORY" /* PREPARING_STORY */),
|
|
2829
|
+
PREPARING_DELAY
|
|
2830
|
+
);
|
|
2831
|
+
}
|
|
2832
|
+
showPreparingDocs({ immediate = !1 } = {}) {
|
|
2833
|
+
clearTimeout(this.preparingTimeout), immediate ? this.showMode("PREPARING_DOCS" /* PREPARING_DOCS */) : this.preparingTimeout = setTimeout(() => this.showMode("PREPARING_DOCS" /* PREPARING_DOCS */), PREPARING_DELAY);
|
|
2834
|
+
}
|
|
2835
|
+
showMain() {
|
|
2836
|
+
this.showMode("MAIN" /* MAIN */);
|
|
2837
|
+
}
|
|
2838
|
+
showDocs() {
|
|
2839
|
+
this.storyRoot().setAttribute("hidden", "true"), this.docsRoot().removeAttribute("hidden");
|
|
2840
|
+
}
|
|
2841
|
+
showStory() {
|
|
2842
|
+
this.docsRoot().setAttribute("hidden", "true"), this.storyRoot().removeAttribute("hidden");
|
|
2843
|
+
}
|
|
2844
|
+
showStoryDuringRender() {
|
|
2845
|
+
document3.body.classList.add(classes.MAIN);
|
|
2846
|
+
}
|
|
2847
|
+
};
|
|
2848
|
+
|
|
2849
|
+
// src/preview-api/modules/preview-web/PreviewWeb.tsx
|
|
2850
|
+
var PreviewWeb = class extends PreviewWithSelection {
|
|
2851
|
+
constructor(importFn, getProjectAnnotations) {
|
|
2852
|
+
super(importFn, getProjectAnnotations, new UrlStore(), new WebView());
|
|
2853
|
+
this.importFn = importFn;
|
|
2854
|
+
this.getProjectAnnotations = getProjectAnnotations;
|
|
2855
|
+
global8.__STORYBOOK_PREVIEW__ = this;
|
|
2856
|
+
}
|
|
2857
|
+
};
|
|
2858
|
+
|
|
2859
|
+
// src/preview-api/modules/preview-web/simulate-pageload.ts
|
|
2860
|
+
import { global as global9 } from "@storybook/global";
|
|
2861
|
+
var { document: document4 } = global9, runScriptTypes = [
|
|
2862
|
+
"application/javascript",
|
|
2863
|
+
"application/ecmascript",
|
|
2864
|
+
"application/x-ecmascript",
|
|
2865
|
+
"application/x-javascript",
|
|
2866
|
+
"text/ecmascript",
|
|
2867
|
+
"text/javascript",
|
|
2868
|
+
"text/javascript1.0",
|
|
2869
|
+
"text/javascript1.1",
|
|
2870
|
+
"text/javascript1.2",
|
|
2871
|
+
"text/javascript1.3",
|
|
2872
|
+
"text/javascript1.4",
|
|
2873
|
+
"text/javascript1.5",
|
|
2874
|
+
"text/jscript",
|
|
2875
|
+
"text/livescript",
|
|
2876
|
+
"text/x-ecmascript",
|
|
2877
|
+
"text/x-javascript",
|
|
2878
|
+
// Support modern javascript
|
|
2879
|
+
"module"
|
|
2880
|
+
], SCRIPT = "script", SCRIPTS_ROOT_ID = "scripts-root";
|
|
2881
|
+
function simulateDOMContentLoaded() {
|
|
2882
|
+
let DOMContentLoadedEvent = document4.createEvent("Event");
|
|
2883
|
+
DOMContentLoadedEvent.initEvent("DOMContentLoaded", !0, !0), document4.dispatchEvent(DOMContentLoadedEvent);
|
|
2884
|
+
}
|
|
2885
|
+
function insertScript($script, callback, $scriptRoot) {
|
|
2886
|
+
let scriptEl = document4.createElement("script");
|
|
2887
|
+
scriptEl.type = $script.type === "module" ? "module" : "text/javascript", $script.src ? (scriptEl.onload = callback, scriptEl.onerror = callback, scriptEl.src = $script.src) : scriptEl.textContent = $script.innerText, $scriptRoot ? $scriptRoot.appendChild(scriptEl) : document4.head.appendChild(scriptEl), $script.parentNode.removeChild($script), $script.src || callback();
|
|
2888
|
+
}
|
|
2889
|
+
function insertScriptsSequentially(scriptsToExecute, callback, index = 0) {
|
|
2890
|
+
scriptsToExecute[index](() => {
|
|
2891
|
+
index++, index === scriptsToExecute.length ? callback() : insertScriptsSequentially(scriptsToExecute, callback, index);
|
|
2892
|
+
});
|
|
2893
|
+
}
|
|
2894
|
+
function simulatePageLoad($container) {
|
|
2895
|
+
let $scriptsRoot = document4.getElementById(SCRIPTS_ROOT_ID);
|
|
2896
|
+
$scriptsRoot ? $scriptsRoot.innerHTML = "" : ($scriptsRoot = document4.createElement("div"), $scriptsRoot.id = SCRIPTS_ROOT_ID, document4.body.appendChild($scriptsRoot));
|
|
2897
|
+
let $scripts = Array.from($container.querySelectorAll(SCRIPT));
|
|
2898
|
+
if ($scripts.length) {
|
|
2899
|
+
let scriptsToExecute = [];
|
|
2900
|
+
$scripts.forEach(($script) => {
|
|
2901
|
+
let typeAttr = $script.getAttribute("type");
|
|
2902
|
+
(!typeAttr || runScriptTypes.includes(typeAttr)) && scriptsToExecute.push((callback) => insertScript($script, callback, $scriptsRoot));
|
|
2903
|
+
}), scriptsToExecute.length && insertScriptsSequentially(scriptsToExecute, simulateDOMContentLoaded, void 0);
|
|
2904
|
+
} else
|
|
2905
|
+
simulateDOMContentLoaded();
|
|
2906
|
+
}
|
|
2907
|
+
|
|
2908
|
+
// src/preview-api/modules/preview-web/emitTransformCode.ts
|
|
2909
|
+
async function emitTransformCode(source, context) {
|
|
2910
|
+
let transform = context.parameters?.docs?.source?.transform, { id, unmappedArgs } = context, transformed = transform && source ? transform?.(source, context) : source, result = transformed ? await transformed : void 0;
|
|
2911
|
+
addons.getChannel().emit(SNIPPET_RENDERED, {
|
|
2912
|
+
id,
|
|
2913
|
+
source: result,
|
|
2914
|
+
args: unmappedArgs
|
|
2915
|
+
});
|
|
2916
|
+
}
|
|
2917
|
+
|
|
2918
|
+
export {
|
|
2919
|
+
mockChannel,
|
|
2920
|
+
addons,
|
|
2921
|
+
HooksContext,
|
|
2922
|
+
applyHooks,
|
|
2923
|
+
useMemo,
|
|
2924
|
+
useCallback,
|
|
2925
|
+
useRef,
|
|
2926
|
+
useState,
|
|
2927
|
+
useReducer,
|
|
2928
|
+
useEffect,
|
|
2929
|
+
useChannel,
|
|
2930
|
+
useStoryContext,
|
|
2931
|
+
useParameter,
|
|
2932
|
+
useArgs,
|
|
2933
|
+
useGlobals,
|
|
2934
|
+
makeDecorator,
|
|
2935
|
+
combineArgs,
|
|
2936
|
+
normalizeArrays,
|
|
2937
|
+
normalizeStory,
|
|
2938
|
+
mountDestructured,
|
|
2939
|
+
decorateStory,
|
|
2940
|
+
sanitizeStoryContextUpdate,
|
|
2941
|
+
defaultDecorateStory,
|
|
2942
|
+
prepareStory,
|
|
2943
|
+
prepareMeta,
|
|
2944
|
+
filterArgTypes,
|
|
2945
|
+
inferControls,
|
|
2946
|
+
normalizeProjectAnnotations,
|
|
2947
|
+
composeStepRunners,
|
|
2948
|
+
composeConfigs,
|
|
2949
|
+
ReporterAPI,
|
|
2950
|
+
getCsfFactoryAnnotations,
|
|
2951
|
+
setDefaultProjectAnnotations,
|
|
2952
|
+
setProjectAnnotations,
|
|
2953
|
+
composeStory,
|
|
2954
|
+
composeStories,
|
|
2955
|
+
createPlaywrightTest,
|
|
2956
|
+
StoryStore,
|
|
2957
|
+
userOrAutoTitleFromSpecifier,
|
|
2958
|
+
userOrAutoTitle,
|
|
2959
|
+
sortStoriesV7,
|
|
2960
|
+
Preview,
|
|
2961
|
+
DocsContext,
|
|
2962
|
+
PreviewWithSelection,
|
|
2963
|
+
UrlStore,
|
|
2964
|
+
WebView,
|
|
2965
|
+
PreviewWeb,
|
|
2966
|
+
simulateDOMContentLoaded,
|
|
2967
|
+
simulatePageLoad,
|
|
2968
|
+
emitTransformCode
|
|
2969
|
+
};
|