@storybook/angular-vite 0.0.0-canary-test

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.
@@ -0,0 +1,723 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __export = (target, all) => {
4
+ for (var name in all)
5
+ __defProp(target, name, { get: all[name], enumerable: !0 });
6
+ };
7
+ var __decorateClass = (decorators, target, key, kind) => {
8
+ for (var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target, i = decorators.length - 1, decorator; i >= 0; i--)
9
+ (decorator = decorators[i]) && (result = (kind ? decorator(target, key, result) : decorator(result)) || result);
10
+ return kind && result && __defProp(target, key, result), result;
11
+ }, __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
12
+
13
+ // src/client/render.ts
14
+ var render_exports = {};
15
+ __export(render_exports, {
16
+ render: () => render,
17
+ renderToCanvas: () => renderToCanvas,
18
+ rendererFactory: () => rendererFactory
19
+ });
20
+ import "@angular/compiler";
21
+
22
+ // src/client/renderer/AbstractRenderer.ts
23
+ import { provideZonelessChangeDetection } from "@angular/core";
24
+ import { bootstrapApplication } from "@angular/platform-browser";
25
+ import { BehaviorSubject } from "rxjs";
26
+ import { stringify } from "telejson";
27
+
28
+ // src/client/renderer/utils/NgComponentAnalyzer.ts
29
+ import {
30
+ Component,
31
+ Directive,
32
+ Input,
33
+ Output,
34
+ Pipe,
35
+ \u0275ReflectionCapabilities as ReflectionCapabilities,
36
+ \u0275getComponentDef as getComponentDef
37
+ } from "@angular/core";
38
+ var reflectionCapabilities = new ReflectionCapabilities(), getComponentInputsOutputs = (component) => {
39
+ let componentMetadata = getComponentDecoratorMetadata(component), componentPropsMetadata = getComponentPropsDecoratorMetadata(component), initialValue = {
40
+ inputs: [],
41
+ outputs: []
42
+ };
43
+ componentMetadata && componentMetadata.inputs && initialValue.inputs.push(
44
+ ...componentMetadata.inputs.map((i) => ({
45
+ propName: typeof i == "string" ? i : i.name,
46
+ templateName: typeof i == "string" ? i : i.alias
47
+ }))
48
+ ), componentMetadata && componentMetadata.outputs && initialValue.outputs.push(
49
+ ...componentMetadata.outputs.map((i) => ({ propName: i, templateName: i }))
50
+ );
51
+ let decoratorDerived = componentPropsMetadata ? Object.entries(componentPropsMetadata).reduce((previousValue, [propertyName, values]) => {
52
+ let value = values.find((v) => v instanceof Input || v instanceof Output);
53
+ if (value instanceof Input) {
54
+ let inputToAdd = {
55
+ propName: propertyName,
56
+ templateName: value.bindingPropertyName ?? value.alias ?? propertyName
57
+ }, previousInputsFiltered = previousValue.inputs.filter(
58
+ (i) => i.templateName !== propertyName
59
+ );
60
+ return {
61
+ ...previousValue,
62
+ inputs: [...previousInputsFiltered, inputToAdd]
63
+ };
64
+ }
65
+ if (value instanceof Output) {
66
+ let outputToAdd = {
67
+ propName: propertyName,
68
+ templateName: value.bindingPropertyName ?? value.alias ?? propertyName
69
+ }, previousOutputsFiltered = previousValue.outputs.filter(
70
+ (i) => i.templateName !== propertyName
71
+ );
72
+ return {
73
+ ...previousValue,
74
+ outputs: [...previousOutputsFiltered, outputToAdd]
75
+ };
76
+ }
77
+ return previousValue;
78
+ }, initialValue) : initialValue;
79
+ return addSignalInputsOutputs(component, decoratorDerived);
80
+ }, hasEntry = (list, propName, templateName) => list.some((e) => e.propName === propName || e.templateName === templateName), addSignalInputsOutputs = (component, base) => {
81
+ let result = {
82
+ inputs: [...base.inputs],
83
+ outputs: [...base.outputs]
84
+ }, def;
85
+ try {
86
+ def = getComponentDef(component);
87
+ } catch {
88
+ return result;
89
+ }
90
+ if (!def)
91
+ return result;
92
+ for (let templateName of Object.keys(def.inputs ?? {})) {
93
+ let rawPropName = def.inputs[templateName], propName = Array.isArray(rawPropName) ? rawPropName[0] ?? templateName : rawPropName ?? templateName;
94
+ hasEntry(result.inputs, propName, templateName) || result.inputs.push({ propName, templateName });
95
+ }
96
+ for (let templateName of Object.keys(def.outputs ?? {})) {
97
+ let propName = def.outputs[templateName] ?? templateName;
98
+ hasEntry(result.outputs, propName, templateName) || result.outputs.push({ propName, templateName });
99
+ }
100
+ return result;
101
+ };
102
+ var isComponent = (component) => component ? (reflectionCapabilities.annotations(component) || []).some((d) => d instanceof Component) : !1;
103
+ var getComponentPropsDecoratorMetadata = (component) => reflectionCapabilities.propMetadata(component), getComponentDecoratorMetadata = (component) => reflectionCapabilities.annotations(component).reverse().find((d) => d instanceof Component);
104
+
105
+ // src/client/renderer/ComputesTemplateFromComponent.ts
106
+ var isValidIdentifier = (name) => /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name), formatPropInTemplate = (propertyName) => isValidIdentifier(propertyName) ? propertyName : `this['${propertyName}']`, separateInputsOutputsAttributes = (ngComponentInputsOutputs, props = {}) => {
107
+ let inputs = ngComponentInputsOutputs.inputs.filter((i) => i.templateName in props).map((i) => i.templateName), outputs = ngComponentInputsOutputs.outputs.filter((o) => o.templateName in props).map((o) => o.templateName);
108
+ return {
109
+ inputs,
110
+ outputs,
111
+ otherProps: Object.keys(props).filter((k) => ![...inputs, ...outputs].includes(k))
112
+ };
113
+ }, computesTemplateFromComponent = (component, initialProps, innerTemplate = "") => {
114
+ let ngComponentMetadata = getComponentDecoratorMetadata(component), ngComponentInputsOutputs = getComponentInputsOutputs(component);
115
+ if (!ngComponentMetadata.selector)
116
+ return '<ng-container *ngComponentOutlet="storyComponent"></ng-container>';
117
+ let { inputs: initialInputs, outputs: initialOutputs } = separateInputsOutputsAttributes(
118
+ ngComponentInputsOutputs,
119
+ initialProps
120
+ ), templateInputs = initialInputs.length > 0 ? ` ${initialInputs.map((i) => `[${i}]="${formatPropInTemplate(i)}"`).join(" ")}` : "", templateOutputs = initialOutputs.length > 0 ? ` ${initialOutputs.map((i) => `(${i})="${formatPropInTemplate(i)}($event)"`).join(" ")}` : "";
121
+ return buildTemplate(
122
+ ngComponentMetadata.selector,
123
+ innerTemplate,
124
+ templateInputs,
125
+ templateOutputs
126
+ );
127
+ };
128
+ function stringifyCircular(obj) {
129
+ let seen = /* @__PURE__ */ new Set();
130
+ return JSON.stringify(obj, (key, value) => {
131
+ if (typeof value == "object" && value !== null) {
132
+ if (seen.has(value))
133
+ return "[Circular]";
134
+ seen.add(value);
135
+ }
136
+ return value;
137
+ });
138
+ }
139
+ var createAngularInputProperty = ({
140
+ propertyName,
141
+ value,
142
+ argType
143
+ }) => {
144
+ let templateValue;
145
+ switch (typeof value) {
146
+ case "string":
147
+ templateValue = `'${value}'`;
148
+ break;
149
+ case "object":
150
+ templateValue = stringifyCircular(value).replace(/'/g, "\u2019").replace(/\\"/g, "\u201D").replace(/"([^-"]+)":/g, "$1: ").replace(/"/g, "'").replace(/\u2019/g, "\\'").replace(/\u201D/g, "\\'").split(",").join(", ");
151
+ break;
152
+ default:
153
+ templateValue = value;
154
+ }
155
+ return `[${propertyName}]="${templateValue}"`;
156
+ }, computesTemplateSourceFromComponent = (component, initialProps, argTypes) => {
157
+ let ngComponentMetadata = getComponentDecoratorMetadata(component);
158
+ if (!ngComponentMetadata)
159
+ return null;
160
+ if (!ngComponentMetadata.selector)
161
+ return `<ng-container *ngComponentOutlet="${component.name}"></ng-container>`;
162
+ let ngComponentInputsOutputs = getComponentInputsOutputs(component), { inputs: initialInputs, outputs: initialOutputs } = separateInputsOutputsAttributes(
163
+ ngComponentInputsOutputs,
164
+ initialProps
165
+ ), templateInputs = initialInputs.length > 0 ? ` ${initialInputs.map(
166
+ (propertyName) => createAngularInputProperty({
167
+ propertyName,
168
+ value: initialProps[propertyName],
169
+ argType: argTypes?.[propertyName]
170
+ })
171
+ ).join(" ")}` : "", templateOutputs = initialOutputs.length > 0 ? ` ${initialOutputs.map((i) => `(${i})="${formatPropInTemplate(i)}($event)"`).join(" ")}` : "";
172
+ return buildTemplate(ngComponentMetadata.selector, "", templateInputs, templateOutputs);
173
+ }, buildTemplate = (selector, innerTemplate, inputs, outputs) => {
174
+ let voidElements = [
175
+ "area",
176
+ "base",
177
+ "br",
178
+ "col",
179
+ "command",
180
+ "embed",
181
+ "hr",
182
+ "img",
183
+ "input",
184
+ "keygen",
185
+ "link",
186
+ "meta",
187
+ "param",
188
+ "source",
189
+ "track",
190
+ "wbr"
191
+ ], firstSelector = selector.split(",")[0];
192
+ return [
193
+ [/(^.*?)(?=[,])/, "$1"],
194
+ [/(^\..+)/, "div$1"],
195
+ [/(^\[.+?])/, "div$1"],
196
+ [/([\w[\]]+)(\s*,[\w\s-[\],]+)+/, "$1"],
197
+ [/#([\w-]+)/, ' id="$1"'],
198
+ [/((\.[\w-]+)+)/, (_, c) => ` class="${c.split`.`.join` `.trim()}"`],
199
+ [/(\[.+?])/g, (_, a) => ` ${a.slice(1, -1)}`],
200
+ [
201
+ /([\S]+)(.*)/,
202
+ (template, elementSelector) => voidElements.some((element) => elementSelector === element) ? template.replace(/([\S]+)(.*)/, `<$1$2${inputs}${outputs} />`) : template.replace(/([\S]+)(.*)/, `<$1$2${inputs}${outputs}>${innerTemplate}</$1>`)
203
+ ]
204
+ ].reduce(
205
+ (prevSelector, [searchValue, replacer]) => prevSelector.replace(searchValue, replacer),
206
+ firstSelector
207
+ );
208
+ };
209
+
210
+ // src/client/renderer/StorybookWrapperComponent.ts
211
+ import {
212
+ ChangeDetectorRef,
213
+ Component as Component3,
214
+ Inject,
215
+ NgModule as NgModule2,
216
+ ViewChild,
217
+ ViewContainerRef
218
+ } from "@angular/core";
219
+ import { map, skip } from "rxjs/operators";
220
+
221
+ // src/client/renderer/StorybookProvider.ts
222
+ import { InjectionToken, NgZone } from "@angular/core";
223
+ import { Observable } from "rxjs";
224
+ var STORY_PROPS = new InjectionToken("STORY_PROPS"), storyPropsProvider = (storyProps$) => ({
225
+ provide: STORY_PROPS,
226
+ useFactory: storyDataFactory(storyProps$.asObservable()),
227
+ deps: [NgZone]
228
+ });
229
+ function storyDataFactory(data) {
230
+ return (ngZone) => new Observable((subscriber) => {
231
+ let sub = data.subscribe(
232
+ (v) => {
233
+ ngZone.run(() => subscriber.next(v));
234
+ },
235
+ (err) => {
236
+ ngZone.run(() => subscriber.error(err));
237
+ },
238
+ () => {
239
+ ngZone.run(() => subscriber.complete());
240
+ }
241
+ );
242
+ return () => {
243
+ sub.unsubscribe();
244
+ };
245
+ });
246
+ }
247
+
248
+ // src/client/renderer/utils/PropertyExtractor.ts
249
+ import { CommonModule } from "@angular/common";
250
+ import {
251
+ Component as Component2,
252
+ Directive as Directive2,
253
+ Injectable,
254
+ InjectionToken as InjectionToken2,
255
+ Input as Input2,
256
+ Output as Output2,
257
+ Pipe as Pipe2,
258
+ \u0275ReflectionCapabilities as ReflectionCapabilities3
259
+ } from "@angular/core";
260
+ import { BrowserModule } from "@angular/platform-browser";
261
+ import {
262
+ BrowserAnimationsModule,
263
+ NoopAnimationsModule,
264
+ provideAnimations,
265
+ provideNoopAnimations
266
+ } from "@angular/platform-browser/animations";
267
+ import { dedent } from "ts-dedent";
268
+
269
+ // src/client/renderer/utils/NgModulesAnalyzer.ts
270
+ import { NgModule, \u0275ReflectionCapabilities as ReflectionCapabilities2 } from "@angular/core";
271
+ var reflectionCapabilities2 = new ReflectionCapabilities2(), isComponentAlreadyDeclared = (componentToFind, moduleDeclarations, moduleImports) => moduleDeclarations && moduleDeclarations.flat().some((declaration) => declaration === componentToFind) ? !0 : moduleImports ? moduleImports.flat().some((importItem) => {
272
+ let extractedNgModuleMetadata = extractNgModuleMetadata(importItem);
273
+ return extractedNgModuleMetadata ? isComponentAlreadyDeclared(
274
+ componentToFind,
275
+ extractedNgModuleMetadata.declarations,
276
+ extractedNgModuleMetadata.imports
277
+ ) : !1;
278
+ }) : !1, extractNgModuleMetadata = (importItem) => {
279
+ let target = importItem && importItem.ngModule ? importItem.ngModule : importItem, decorators = reflectionCapabilities2.annotations(target);
280
+ if (!decorators || decorators.length === 0)
281
+ return null;
282
+ let ngModuleDecorator = decorators.find(
283
+ (decorator) => decorator instanceof NgModule
284
+ );
285
+ return ngModuleDecorator || null;
286
+ };
287
+
288
+ // src/client/renderer/utils/PropertyExtractor.ts
289
+ var reflectionCapabilities3 = new ReflectionCapabilities3(), REMOVED_MODULES = new InjectionToken2("REMOVED_MODULES"), uniqueArray = (arr) => arr.flat(Number.MAX_VALUE).filter(Boolean).filter((value, index, self) => self.indexOf(value) === index), _PropertyExtractor = class _PropertyExtractor {
290
+ constructor(metadata, component) {
291
+ this.metadata = metadata;
292
+ this.component = component;
293
+ this.declarations = [];
294
+ /**
295
+ * Analyze NgModule Metadata
296
+ *
297
+ * - Removes Restricted Imports
298
+ * - Extracts providers from ModuleWithProviders
299
+ * - Returns a new NgModuleMetadata object
300
+ */
301
+ this.analyzeMetadata = async (metadata) => {
302
+ let declarations = [...metadata?.declarations || []], providers = [...metadata?.providers || []], applicationProviders = [], imports = await Promise.all(
303
+ [...metadata?.imports || []].map(async (imported) => {
304
+ let [isRestricted, restrictedProviders] = await _PropertyExtractor.analyzeRestricted(imported);
305
+ return isRestricted ? (applicationProviders.unshift(restrictedProviders || []), null) : imported;
306
+ })
307
+ ).then((results) => results.filter(Boolean));
308
+ return { ...metadata, imports, providers, applicationProviders, declarations };
309
+ };
310
+ }
311
+ // Stories built on top of `bootstrapApplication` should pass providers through
312
+ // `applicationConfig`, not via `ModuleWithProviders` entries in `moduleMetadata.imports`.
313
+ static warnImportsModuleWithProviders(propertyExtractor) {
314
+ propertyExtractor.imports.some(
315
+ (importedModule) => "ngModule" in importedModule
316
+ ) && console.warn(
317
+ dedent(
318
+ `
319
+ Storybook Warning:
320
+ moduleMetadata.imports contains one or more ModuleWithProviders (likely the result of a 'Module.forRoot()'-style call).
321
+ Use the 'applicationConfig' decorator from '@storybook/angular-vite' and pass the providers to its 'providers' array instead.
322
+ See https://angular.dev/guide/components/anatomy-of-components#configuring-dependency-injection for more information.
323
+ `
324
+ )
325
+ );
326
+ }
327
+ async init() {
328
+ let analyzed = await this.analyzeMetadata(this.metadata);
329
+ if (this.imports = uniqueArray([CommonModule, analyzed.imports]), this.providers = uniqueArray(analyzed.providers), this.applicationProviders = uniqueArray(analyzed.applicationProviders), this.declarations = uniqueArray(analyzed.declarations), this.component) {
330
+ let { isDeclarable, isStandalone } = _PropertyExtractor.analyzeDecorators(this.component), isDeclared = isComponentAlreadyDeclared(
331
+ this.component,
332
+ analyzed.declarations,
333
+ this.imports
334
+ );
335
+ isStandalone ? this.imports.push(this.component) : isDeclarable && !isDeclared && this.declarations.push(this.component);
336
+ }
337
+ }
338
+ };
339
+ _PropertyExtractor.analyzeRestricted = (ngModule) => ngModule === BrowserModule ? (console.warn(
340
+ dedent`
341
+ Storybook Warning:
342
+ "BrowserModule" is not needed when using bootstrapApplication — its providers are included automatically.
343
+ Please remove "BrowserModule" from moduleMetadata.imports to remove this warning.
344
+ `
345
+ ), [!0]) : ngModule === BrowserAnimationsModule ? (console.warn(
346
+ dedent`
347
+ Storybook Warning:
348
+ "BrowserAnimationsModule" was added to moduleMetadata.imports.
349
+ Use the 'applicationConfig' decorator from '@storybook/angular-vite' and add 'provideAnimations()' to its providers instead.
350
+ `
351
+ ), [!0, provideAnimations()]) : ngModule === NoopAnimationsModule ? (console.warn(
352
+ dedent`
353
+ Storybook Warning:
354
+ "NoopAnimationsModule" was added to moduleMetadata.imports.
355
+ Use the 'applicationConfig' decorator from '@storybook/angular-vite' and add 'provideNoopAnimations()' to its providers instead.
356
+ `
357
+ ), [!0, provideNoopAnimations()]) : [!1], _PropertyExtractor.analyzeDecorators = (component) => {
358
+ let decorators = reflectionCapabilities3.annotations(component), isComponent2 = decorators.some((d) => _PropertyExtractor.isDecoratorInstanceOf(d, "Component")), isDirective = decorators.some((d) => _PropertyExtractor.isDecoratorInstanceOf(d, "Directive")), isPipe = decorators.some((d) => _PropertyExtractor.isDecoratorInstanceOf(d, "Pipe")), isDeclarable = isComponent2 || isDirective || isPipe, isStandalone = (isComponent2 || isDirective) && [...decorators].reverse().find(
359
+ (d) => _PropertyExtractor.isDecoratorInstanceOf(d, "Component") || _PropertyExtractor.isDecoratorInstanceOf(d, "Directive")
360
+ )?.standalone;
361
+ return { isDeclarable, isStandalone: isStandalone ?? !0 };
362
+ }, _PropertyExtractor.isDecoratorInstanceOf = (decorator, name) => {
363
+ let factory;
364
+ switch (name) {
365
+ case "Component":
366
+ factory = Component2;
367
+ break;
368
+ case "Directive":
369
+ factory = Directive2;
370
+ break;
371
+ case "Pipe":
372
+ factory = Pipe2;
373
+ break;
374
+ case "Injectable":
375
+ factory = Injectable;
376
+ break;
377
+ case "Input":
378
+ factory = Input2;
379
+ break;
380
+ case "Output":
381
+ factory = Output2;
382
+ break;
383
+ default:
384
+ throw new Error(`Unknown decorator type: ${name}`);
385
+ }
386
+ return decorator instanceof factory || decorator.ngMetadataName === name;
387
+ };
388
+ var PropertyExtractor = _PropertyExtractor;
389
+
390
+ // src/client/renderer/StorybookWrapperComponent.ts
391
+ var getNonInputsOutputsProps = (ngComponentInputsOutputs, props = {}) => {
392
+ let inputs = ngComponentInputsOutputs.inputs.filter((i) => i.templateName in props).map((i) => i.templateName), outputs = ngComponentInputsOutputs.outputs.filter((o) => o.templateName in props).map((o) => o.templateName);
393
+ return Object.keys(props).filter((k) => ![...inputs, ...outputs].includes(k));
394
+ }, createStorybookWrapperComponent = ({
395
+ selector,
396
+ template,
397
+ storyComponent,
398
+ styles,
399
+ moduleMetadata,
400
+ initialProps,
401
+ analyzedMetadata
402
+ }) => {
403
+ let viewChildSelector = storyComponent ?? "__storybook-noop", { imports, declarations, providers } = analyzedMetadata, StorybookComponentModule = class {
404
+ };
405
+ StorybookComponentModule = __decorateClass([
406
+ NgModule2({
407
+ declarations,
408
+ imports,
409
+ exports: [...declarations, ...imports]
410
+ })
411
+ ], StorybookComponentModule), PropertyExtractor.warnImportsModuleWithProviders(analyzedMetadata);
412
+ let StorybookWrapperComponent = class {
413
+ constructor(storyProps$, changeDetectorRef) {
414
+ this.storyProps$ = storyProps$;
415
+ this.changeDetectorRef = changeDetectorRef;
416
+ // Used in case of a component without selector
417
+ this.storyComponent = storyComponent ?? "";
418
+ }
419
+ ngOnInit() {
420
+ this.storyWrapperPropsSubscription = this.storyProps$.subscribe((storyProps = {}) => {
421
+ Object.assign(this, storyProps), this.changeDetectorRef.detectChanges(), this.changeDetectorRef.markForCheck();
422
+ });
423
+ }
424
+ ngAfterViewInit() {
425
+ if (this.storyComponentElementRef) {
426
+ let ngComponentInputsOutputs = getComponentInputsOutputs(storyComponent);
427
+ getNonInputsOutputsProps(ngComponentInputsOutputs, initialProps).forEach((p) => {
428
+ this.storyComponentElementRef[p] = initialProps[p];
429
+ }), this.storyComponentViewContainerRef.injector.get(ChangeDetectorRef).markForCheck(), this.changeDetectorRef.detectChanges(), this.storyComponentPropsSubscription = this.storyProps$.pipe(
430
+ skip(1),
431
+ map((props) => getNonInputsOutputsProps(ngComponentInputsOutputs, props).reduce((acc, p) => ({ ...acc, [p]: props[p] }), {}))
432
+ ).subscribe((props) => {
433
+ Object.assign(this.storyComponentElementRef, props), this.storyComponentViewContainerRef.injector.get(ChangeDetectorRef).markForCheck(), this.changeDetectorRef.detectChanges();
434
+ });
435
+ }
436
+ }
437
+ ngOnDestroy() {
438
+ this.storyComponentPropsSubscription != null && this.storyComponentPropsSubscription.unsubscribe(), this.storyWrapperPropsSubscription != null && this.storyWrapperPropsSubscription.unsubscribe();
439
+ }
440
+ };
441
+ return __decorateClass([
442
+ ViewChild(viewChildSelector, { static: !0 })
443
+ ], StorybookWrapperComponent.prototype, "storyComponentElementRef", 2), __decorateClass([
444
+ ViewChild(viewChildSelector, { read: ViewContainerRef, static: !0 })
445
+ ], StorybookWrapperComponent.prototype, "storyComponentViewContainerRef", 2), StorybookWrapperComponent = __decorateClass([
446
+ Component3({
447
+ selector,
448
+ template,
449
+ standalone: !0,
450
+ imports: [StorybookComponentModule],
451
+ providers,
452
+ styles,
453
+ schemas: moduleMetadata.schemas
454
+ }),
455
+ __decorateParam(0, Inject(STORY_PROPS)),
456
+ __decorateParam(1, Inject(ChangeDetectorRef))
457
+ ], StorybookWrapperComponent), StorybookWrapperComponent;
458
+ };
459
+
460
+ // src/client/renderer/StorybookModule.ts
461
+ var getApplication = ({
462
+ storyFnAngular,
463
+ component,
464
+ targetSelector,
465
+ analyzedMetadata
466
+ }) => {
467
+ let { props, styles, moduleMetadata = {} } = storyFnAngular, { template } = storyFnAngular;
468
+ return !!hasNoTemplate(template) && component && (template = computesTemplateFromComponent(component, props, "")), createStorybookWrapperComponent({
469
+ moduleMetadata,
470
+ selector: targetSelector,
471
+ template,
472
+ storyComponent: component,
473
+ styles,
474
+ initialProps: props,
475
+ analyzedMetadata
476
+ });
477
+ };
478
+ function hasNoTemplate(template) {
479
+ return template == null;
480
+ }
481
+
482
+ // src/client/renderer/utils/BootstrapQueue.ts
483
+ var queue = [], isProcessing = !1, resetCompiledComponents = async () => {
484
+ try {
485
+ let { \u0275resetCompiledComponents } = await import("@angular/core");
486
+ \u0275resetCompiledComponents();
487
+ } catch {
488
+ }
489
+ }, queueBootstrapping = (fn) => new Promise((resolve, reject) => {
490
+ queue.push(() => fn().then(resolve).catch(reject)), isProcessing || processQueue();
491
+ }), processQueue = async () => {
492
+ for (isProcessing = !0; queue.length > 0; ) {
493
+ let bootstrappingFn = queue.shift();
494
+ bootstrappingFn && (await bootstrappingFn(), await resetCompiledComponents());
495
+ }
496
+ isProcessing = !1;
497
+ };
498
+
499
+ // src/client/renderer/AbstractRenderer.ts
500
+ var applicationRefs = /* @__PURE__ */ new Map(), STORY_UID_ATTRIBUTE = "data-sb-story-uid", AbstractRenderer = class {
501
+ constructor() {
502
+ this.previousStoryRenderInfo = /* @__PURE__ */ new Map();
503
+ }
504
+ /** Wait and destroy the platform */
505
+ static resetApplications(domNode) {
506
+ applicationRefs.forEach((appRef, appDOMNode) => {
507
+ !appRef.destroyed && (!domNode || appDOMNode === domNode) && appRef.destroy();
508
+ });
509
+ }
510
+ /**
511
+ * Bootstrap main angular module with main component or send only new `props` with storyProps$
512
+ *
513
+ * @param storyFnAngular {StoryFnAngularReturnType}
514
+ * @param forced {boolean} If :
515
+ *
516
+ * - True render will only use the StoryFn `props' in storyProps observable that will update sotry's
517
+ * component/template properties. Improves performance without reloading the whole
518
+ * module&component if props changes
519
+ * - False fully recharges or initializes angular module & component
520
+ *
521
+ * @param component {Component}
522
+ */
523
+ async render({
524
+ storyId,
525
+ storyFnAngular,
526
+ forced,
527
+ component,
528
+ targetDOMNode
529
+ }) {
530
+ let targetSelector = this.generateTargetSelectorFromStoryId(storyId), newStoryProps$ = new BehaviorSubject(storyFnAngular.props);
531
+ if (!this.fullRendererRequired({
532
+ targetDOMNode,
533
+ storyFnAngular,
534
+ moduleMetadata: {
535
+ ...storyFnAngular.moduleMetadata
536
+ },
537
+ forced
538
+ })) {
539
+ this.storyProps$.next(storyFnAngular.props);
540
+ return;
541
+ }
542
+ await this.beforeFullRender(targetDOMNode), this.storyProps$ && this.storyProps$.complete(), this.storyProps$ = newStoryProps$, this.initAngularRootElement(targetDOMNode, targetSelector, storyId);
543
+ let analyzedMetadata = new PropertyExtractor(storyFnAngular.moduleMetadata, component);
544
+ await analyzedMetadata.init();
545
+ let storyUid = this.generateStoryUIdFromRawStoryUid(
546
+ targetDOMNode.getAttribute(STORY_UID_ATTRIBUTE)
547
+ ), componentSelector = storyUid !== null ? `${targetSelector}[${storyUid}]` : targetSelector;
548
+ storyUid !== null && targetDOMNode.querySelector(targetSelector).toggleAttribute(storyUid, !0);
549
+ let application = getApplication({
550
+ storyFnAngular,
551
+ component,
552
+ targetSelector: componentSelector,
553
+ analyzedMetadata
554
+ }), providers = [
555
+ storyPropsProvider(newStoryProps$),
556
+ ...analyzedMetadata.applicationProviders,
557
+ ...storyFnAngular.applicationConfig?.providers ?? []
558
+ ];
559
+ STORYBOOK_ANGULAR_OPTIONS?.zoneless && providers.unshift(provideZonelessChangeDetection());
560
+ let applicationRef = await queueBootstrapping(() => bootstrapApplication(application, {
561
+ ...storyFnAngular.applicationConfig,
562
+ providers
563
+ }));
564
+ applicationRefs.set(targetDOMNode, applicationRef);
565
+ }
566
+ /**
567
+ * Only ASCII alphanumerics can be used as HTML tag name. https://html.spec.whatwg.org/#elements-2
568
+ *
569
+ * Therefore, stories break when non-ASCII alphanumerics are included in target selector.
570
+ * https://github.com/storybookjs/storybook/issues/15147
571
+ *
572
+ * This method returns storyId when it doesn't contain any non-ASCII alphanumerics. Otherwise, it
573
+ * generates a valid HTML tag name from storyId by removing non-ASCII alphanumerics from storyId,
574
+ * prefixing "sb-", and suffixing "-component"
575
+ *
576
+ * @memberof AbstractRenderer
577
+ * @protected
578
+ */
579
+ generateTargetSelectorFromStoryId(id) {
580
+ let invalidHtmlTag = /[^A-Za-z0-9-]/g;
581
+ if (!invalidHtmlTag.test(id))
582
+ return id;
583
+ let cleaned = id.replace(invalidHtmlTag, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
584
+ return cleaned ? `sb-${cleaned}-component` : "sb-story-component";
585
+ }
586
+ /**
587
+ * The story UID is interpolated into a CSS attribute selector
588
+ * (`${targetSelector}[${storyUid}]`) at bootstrap. Anything outside
589
+ * `[A-Za-z0-9_-]` — accents, emoji, Cyrillic, CJK, etc. — makes the
590
+ * selector invalid (see https://github.com/storybookjs/storybook/issues/29132
591
+ * for the accent case). Decompose accents first so the base letter survives,
592
+ * then drop the rest. Fall back to a stable token when nothing remains so
593
+ * `document.querySelector` still gets a valid input.
594
+ *
595
+ * @memberof AbstractRenderer
596
+ * @protected
597
+ */
598
+ generateStoryUIdFromRawStoryUid(rawStoryUid) {
599
+ if (rawStoryUid === null)
600
+ return rawStoryUid;
601
+ let accentCharacters = /[\u0300-\u036f]/g, invalidSelectorChar = /[^A-Za-z0-9_-]/g, stripped = rawStoryUid.normalize("NFD").replace(accentCharacters, "").replace(invalidSelectorChar, "").replace(/-+/g, "-").replace(/^-|-$/g, "");
602
+ return stripped ? /^\d/.test(stripped) ? `sb-${stripped}` : stripped : "sb-story-uid";
603
+ }
604
+ /** Adds DOM element that angular will use as bootstrap component. */
605
+ initAngularRootElement(targetDOMNode, targetSelector, _storyId) {
606
+ targetDOMNode.innerHTML = "", targetDOMNode.appendChild(document.createElement(targetSelector));
607
+ }
608
+ fullRendererRequired({
609
+ targetDOMNode,
610
+ storyFnAngular,
611
+ moduleMetadata,
612
+ forced
613
+ }) {
614
+ let previousStoryRenderInfo = this.previousStoryRenderInfo.get(targetDOMNode), currentStoryRender = {
615
+ storyFnAngular,
616
+ moduleMetadataSnapshot: stringify(moduleMetadata, { maxDepth: 50 })
617
+ };
618
+ return this.previousStoryRenderInfo.set(targetDOMNode, currentStoryRender), // check `forceRender` of story RenderContext
619
+ !forced || // if it's the first rendering and storyProps$ is not init
620
+ !this.storyProps$ || !!storyFnAngular?.template && previousStoryRenderInfo?.storyFnAngular?.template !== storyFnAngular.template ? !0 : currentStoryRender.moduleMetadataSnapshot !== previousStoryRenderInfo?.moduleMetadataSnapshot;
621
+ }
622
+ };
623
+
624
+ // src/client/renderer/CanvasRenderer.ts
625
+ var CanvasRenderer = class _CanvasRenderer extends AbstractRenderer {
626
+ async render(options) {
627
+ await super.render(options);
628
+ }
629
+ async beforeFullRender() {
630
+ _CanvasRenderer.resetApplications();
631
+ }
632
+ };
633
+
634
+ // src/client/renderer/DocsRenderer.ts
635
+ import { DOCS_RENDERED, STORY_CHANGED } from "storybook/internal/core-events";
636
+ import { addons } from "storybook/preview-api";
637
+
638
+ // src/client/renderer/utils/StoryUID.ts
639
+ var storyCounts = /* @__PURE__ */ new Map(), getNextStoryUID = (storyId) => {
640
+ storyCounts.has(storyId) || storyCounts.set(storyId, -1);
641
+ let count = storyCounts.get(storyId) + 1;
642
+ return storyCounts.set(storyId, count), `${storyId}-${count}`;
643
+ };
644
+
645
+ // src/client/renderer/DocsRenderer.ts
646
+ var DocsRenderer = class _DocsRenderer extends AbstractRenderer {
647
+ async render(options) {
648
+ let channel = addons.getChannel();
649
+ channel.once(STORY_CHANGED, async () => {
650
+ await _DocsRenderer.resetApplications();
651
+ }), channel.once(DOCS_RENDERED, async () => {
652
+ await _DocsRenderer.resetApplications();
653
+ }), await super.render({ ...options, forced: !1 });
654
+ }
655
+ async beforeFullRender(domNode) {
656
+ _DocsRenderer.resetApplications(domNode);
657
+ }
658
+ initAngularRootElement(targetDOMNode, targetSelector, storyId) {
659
+ super.initAngularRootElement(targetDOMNode, targetSelector, storyId), targetDOMNode.setAttribute(STORY_UID_ATTRIBUTE, getNextStoryUID(storyId));
660
+ }
661
+ };
662
+
663
+ // src/client/renderer/RendererFactory.ts
664
+ var RendererFactory = class {
665
+ constructor() {
666
+ this.rendererMap = /* @__PURE__ */ new Map();
667
+ }
668
+ async getRendererInstance(targetDOMNode) {
669
+ let targetId = targetDOMNode.id;
670
+ if (targetDOMNode === null)
671
+ return null;
672
+ let renderType = getRenderType(targetDOMNode);
673
+ return this.lastRenderType && this.lastRenderType !== renderType && (await AbstractRenderer.resetApplications(), clearRootHTMLElement(renderType), this.rendererMap.clear()), this.rendererMap.has(targetId) || this.rendererMap.set(targetId, this.buildRenderer(renderType)), this.lastRenderType = renderType, this.rendererMap.get(targetId);
674
+ }
675
+ buildRenderer(renderType) {
676
+ return renderType === "docs" ? new DocsRenderer() : new CanvasRenderer();
677
+ }
678
+ }, getRenderType = (targetDOMNode) => {
679
+ if (targetDOMNode.id === "storybook-docs")
680
+ return "docs";
681
+ let docsRoot = (targetDOMNode.ownerDocument ?? global.document)?.getElementById("storybook-docs") ?? null;
682
+ return docsRoot && docsRoot !== targetDOMNode && docsRoot.contains(targetDOMNode) ? "docs" : "canvas";
683
+ };
684
+ function clearRootHTMLElement(renderType) {
685
+ switch (renderType) {
686
+ case "canvas":
687
+ global.document.getElementById("storybook-docs").innerHTML = "";
688
+ break;
689
+ case "docs":
690
+ global.document.getElementById("storybook-root").innerHTML = "";
691
+ break;
692
+ default:
693
+ break;
694
+ }
695
+ }
696
+
697
+ // src/client/render.ts
698
+ var rendererFactory = new RendererFactory(), render = (props) => ({ props });
699
+ async function renderToCanvas({
700
+ storyFn,
701
+ showMain,
702
+ forceRemount,
703
+ storyContext: { component, id: storyId }
704
+ }, element) {
705
+ showMain(), await (await rendererFactory.getRendererInstance(element)).render({
706
+ storyId,
707
+ storyFnAngular: storyFn(),
708
+ component,
709
+ forced: !forceRemount,
710
+ targetDOMNode: element
711
+ });
712
+ }
713
+
714
+ export {
715
+ __export,
716
+ isComponent,
717
+ formatPropInTemplate,
718
+ computesTemplateFromComponent,
719
+ computesTemplateSourceFromComponent,
720
+ render,
721
+ renderToCanvas,
722
+ render_exports
723
+ };