@storybook/angular 8.0.0-alpha.3 → 8.0.0-alpha.4

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.
@@ -4,6 +4,13 @@ type StoryRenderInfo = {
4
4
  storyFnAngular: StoryFnAngularReturnType;
5
5
  moduleMetadataSnapshot: string;
6
6
  };
7
+ /**
8
+ * Attribute name for the story UID that may be written to the targetDOMNode.
9
+ *
10
+ * If a target DOM node has a story UID attribute, it will be used as part of
11
+ * the selector for the Angular component.
12
+ */
13
+ export declare const STORY_UID_ATTRIBUTE = "data-sb-story-uid";
7
14
  export declare abstract class AbstractRenderer {
8
15
  /**
9
16
  * Wait and destroy the platform
@@ -47,6 +54,9 @@ export declare abstract class AbstractRenderer {
47
54
  * @memberof AbstractRenderer
48
55
  */
49
56
  protected generateTargetSelectorFromStoryId(id: string): string;
57
+ /**
58
+ * Adds DOM element that angular will use as bootstrap component.
59
+ */
50
60
  protected initAngularRootElement(targetDOMNode: HTMLElement, targetSelector: string): void;
51
61
  private fullRendererRequired;
52
62
  }
@@ -24,7 +24,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
24
24
  };
25
25
  var _a;
26
26
  Object.defineProperty(exports, "__esModule", { value: true });
27
- exports.AbstractRenderer = void 0;
27
+ exports.AbstractRenderer = exports.STORY_UID_ATTRIBUTE = void 0;
28
28
  const core_1 = require("@angular/core");
29
29
  const platform_browser_1 = require("@angular/platform-browser");
30
30
  const rxjs_1 = require("rxjs");
@@ -34,6 +34,13 @@ const StorybookProvider_1 = require("./StorybookProvider");
34
34
  const StorybookWrapperComponent_1 = require("./StorybookWrapperComponent");
35
35
  const PropertyExtractor_1 = require("./utils/PropertyExtractor");
36
36
  const applicationRefs = new Map();
37
+ /**
38
+ * Attribute name for the story UID that may be written to the targetDOMNode.
39
+ *
40
+ * If a target DOM node has a story UID attribute, it will be used as part of
41
+ * the selector for the Angular component.
42
+ */
43
+ exports.STORY_UID_ATTRIBUTE = 'data-sb-story-uid';
37
44
  class AbstractRenderer {
38
45
  /**
39
46
  * Wait and destroy the platform
@@ -90,10 +97,16 @@ class AbstractRenderer {
90
97
  this.storyProps$ = newStoryProps$;
91
98
  this.initAngularRootElement(targetDOMNode, targetSelector);
92
99
  const analyzedMetadata = new PropertyExtractor_1.PropertyExtractor(storyFnAngular.moduleMetadata, component);
100
+ const storyUid = targetDOMNode.getAttribute(exports.STORY_UID_ATTRIBUTE);
101
+ const componentSelector = storyUid !== null ? `${targetSelector}[${storyUid}]` : targetSelector;
102
+ if (storyUid !== null) {
103
+ const element = targetDOMNode.querySelector(targetSelector);
104
+ element.toggleAttribute(storyUid, true);
105
+ }
93
106
  const application = (0, StorybookModule_1.getApplication)({
94
107
  storyFnAngular,
95
108
  component,
96
- targetSelector,
109
+ targetSelector: componentSelector,
97
110
  analyzedMetadata,
98
111
  });
99
112
  const applicationRef = await (0, platform_browser_1.bootstrapApplication)(application, {
@@ -124,8 +137,10 @@ class AbstractRenderer {
124
137
  const storyIdIsInvalidHtmlTagName = invalidHtmlTag.test(id);
125
138
  return storyIdIsInvalidHtmlTagName ? `sb-${id.replace(invalidHtmlTag, '')}-component` : id;
126
139
  }
140
+ /**
141
+ * Adds DOM element that angular will use as bootstrap component.
142
+ */
127
143
  initAngularRootElement(targetDOMNode, targetSelector) {
128
- // Adds DOM element that angular will use as bootstrap component
129
144
  // eslint-disable-next-line no-param-reassign
130
145
  targetDOMNode.innerHTML = '';
131
146
  targetDOMNode.appendChild(document.createElement(targetSelector));
@@ -10,4 +10,5 @@ export declare class DocsRenderer extends AbstractRenderer {
10
10
  }): Promise<void>;
11
11
  beforeFullRender(domNode?: HTMLElement): Promise<void>;
12
12
  afterFullRender(): Promise<void>;
13
+ protected initAngularRootElement(targetDOMNode: HTMLElement, targetSelector: string): void;
13
14
  }
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DocsRenderer = void 0;
4
4
  const preview_api_1 = require("@storybook/preview-api");
5
5
  const core_events_1 = require("@storybook/core-events");
6
+ const StoryUID_1 = require("./utils/StoryUID");
6
7
  const AbstractRenderer_1 = require("./AbstractRenderer");
7
8
  class DocsRenderer extends AbstractRenderer_1.AbstractRenderer {
8
9
  async render(options) {
@@ -36,5 +37,9 @@ class DocsRenderer extends AbstractRenderer_1.AbstractRenderer {
36
37
  async afterFullRender() {
37
38
  await AbstractRenderer_1.AbstractRenderer.resetCompiledComponents();
38
39
  }
40
+ initAngularRootElement(targetDOMNode, targetSelector) {
41
+ super.initAngularRootElement(targetDOMNode, targetSelector);
42
+ targetDOMNode.setAttribute(AbstractRenderer_1.STORY_UID_ATTRIBUTE, (0, StoryUID_1.getNextStoryUID)(targetDOMNode.id));
43
+ }
39
44
  }
40
45
  exports.DocsRenderer = DocsRenderer;
@@ -17,10 +17,12 @@ describe('RendererFactory', () => {
17
17
  let rendererFactory;
18
18
  let rootTargetDOMNode;
19
19
  let rootDocstargetDOMNode;
20
+ let storyInDocstargetDOMNode;
20
21
  beforeEach(async () => {
21
22
  rendererFactory = new RendererFactory_1.RendererFactory();
22
23
  document.body.innerHTML =
23
- '<div id="storybook-root"></div><div id="root-docs"><div id="story-in-docs"></div></div>';
24
+ '<div id="storybook-root"></div><div id="root-docs"><div id="story-in-docs"></div></div>' +
25
+ '<div id="storybook-docs"></div>';
24
26
  rootTargetDOMNode = global.document.getElementById('storybook-root');
25
27
  rootDocstargetDOMNode = global.document.getElementById('root-docs');
26
28
  platform_browser_dynamic_1.platformBrowserDynamic.mockImplementation(testing_1.platformBrowserDynamicTesting);
@@ -160,5 +162,39 @@ describe('RendererFactory', () => {
160
162
  const render = await rendererFactory.getRendererInstance(rootDocstargetDOMNode);
161
163
  expect(render).toBeInstanceOf(DocsRenderer_1.DocsRenderer);
162
164
  });
165
+ describe('when multiple story for the same component', () => {
166
+ it('should render both stories', async () => {
167
+ let FooComponent = class FooComponent {
168
+ };
169
+ FooComponent = __decorate([
170
+ (0, core_1.Component)({ selector: 'foo', template: '🦊' })
171
+ ], FooComponent);
172
+ const render = await rendererFactory.getRendererInstance(global.document.getElementById('storybook-docs'));
173
+ const targetDOMNode1 = global.document.createElement('div');
174
+ targetDOMNode1.id = 'story-1';
175
+ global.document.getElementById('storybook-docs').appendChild(targetDOMNode1);
176
+ await render?.render({
177
+ storyFnAngular: {
178
+ props: {},
179
+ },
180
+ forced: false,
181
+ component: FooComponent,
182
+ targetDOMNode: targetDOMNode1,
183
+ });
184
+ const targetDOMNode2 = global.document.createElement('div');
185
+ targetDOMNode2.id = 'story-1';
186
+ global.document.getElementById('storybook-docs').appendChild(targetDOMNode2);
187
+ await render?.render({
188
+ storyFnAngular: {
189
+ props: {},
190
+ },
191
+ forced: false,
192
+ component: FooComponent,
193
+ targetDOMNode: targetDOMNode2,
194
+ });
195
+ expect(global.document.querySelectorAll('#story-1 > story-1')[0].innerHTML).toBe('<foo>🦊</foo><!--container-->');
196
+ expect(global.document.querySelectorAll('#story-1 > story-1')[1].innerHTML).toBe('<foo>🦊</foo><!--container-->');
197
+ });
198
+ });
163
199
  });
164
200
  });
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Increments the count for a storyId and returns the next UID.
3
+ *
4
+ * When a story is bootstrapped, the storyId is used as the element tag. That
5
+ * becomes an issue when a story is rendered multiple times in the same docs
6
+ * page. This function returns a UID that is appended to the storyId to make
7
+ * it unique.
8
+ *
9
+ * @param storyId id of a story
10
+ * @returns uid of a story
11
+ */
12
+ export declare const getNextStoryUID: (storyId: string) => string;
13
+ /**
14
+ * Clears the storyId counts.
15
+ *
16
+ * Can be useful for testing, where you need predictable increments, without
17
+ * reloading the global state.
18
+ *
19
+ * If onlyStoryId is provided, only that storyId is cleared.
20
+ *
21
+ * @param onlyStoryId id of a story
22
+ */
23
+ export declare const clearStoryUIDs: (onlyStoryId?: string) => void;
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.clearStoryUIDs = exports.getNextStoryUID = void 0;
4
+ /**
5
+ * Count of stories for each storyId.
6
+ */
7
+ const storyCounts = new Map();
8
+ /**
9
+ * Increments the count for a storyId and returns the next UID.
10
+ *
11
+ * When a story is bootstrapped, the storyId is used as the element tag. That
12
+ * becomes an issue when a story is rendered multiple times in the same docs
13
+ * page. This function returns a UID that is appended to the storyId to make
14
+ * it unique.
15
+ *
16
+ * @param storyId id of a story
17
+ * @returns uid of a story
18
+ */
19
+ const getNextStoryUID = (storyId) => {
20
+ if (!storyCounts.has(storyId)) {
21
+ storyCounts.set(storyId, -1);
22
+ }
23
+ const count = storyCounts.get(storyId) + 1;
24
+ storyCounts.set(storyId, count);
25
+ return `${storyId}-${count}`;
26
+ };
27
+ exports.getNextStoryUID = getNextStoryUID;
28
+ /**
29
+ * Clears the storyId counts.
30
+ *
31
+ * Can be useful for testing, where you need predictable increments, without
32
+ * reloading the global state.
33
+ *
34
+ * If onlyStoryId is provided, only that storyId is cleared.
35
+ *
36
+ * @param onlyStoryId id of a story
37
+ */
38
+ const clearStoryUIDs = (onlyStoryId) => {
39
+ if (onlyStoryId !== undefined && onlyStoryId !== null) {
40
+ storyCounts.delete(onlyStoryId);
41
+ }
42
+ else {
43
+ storyCounts.clear();
44
+ }
45
+ };
46
+ exports.clearStoryUIDs = clearStoryUIDs;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@storybook/angular",
3
- "version": "8.0.0-alpha.3",
3
+ "version": "8.0.0-alpha.4",
4
4
  "description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.",
5
5
  "keywords": [
6
6
  "storybook",
@@ -37,19 +37,19 @@
37
37
  "prep": "node --loader ../../../scripts/node_modules/esbuild-register/loader.js -r ../../../scripts/node_modules/esbuild-register/register.js ../../../scripts/prepare/tsc.ts"
38
38
  },
39
39
  "dependencies": {
40
- "@storybook/builder-webpack5": "8.0.0-alpha.3",
41
- "@storybook/cli": "8.0.0-alpha.3",
42
- "@storybook/client-logger": "8.0.0-alpha.3",
43
- "@storybook/core-common": "8.0.0-alpha.3",
44
- "@storybook/core-events": "8.0.0-alpha.3",
45
- "@storybook/core-server": "8.0.0-alpha.3",
46
- "@storybook/core-webpack": "8.0.0-alpha.3",
47
- "@storybook/docs-tools": "8.0.0-alpha.3",
40
+ "@storybook/builder-webpack5": "8.0.0-alpha.4",
41
+ "@storybook/cli": "8.0.0-alpha.4",
42
+ "@storybook/client-logger": "8.0.0-alpha.4",
43
+ "@storybook/core-common": "8.0.0-alpha.4",
44
+ "@storybook/core-events": "8.0.0-alpha.4",
45
+ "@storybook/core-server": "8.0.0-alpha.4",
46
+ "@storybook/core-webpack": "8.0.0-alpha.4",
47
+ "@storybook/docs-tools": "8.0.0-alpha.4",
48
48
  "@storybook/global": "^5.0.0",
49
- "@storybook/node-logger": "8.0.0-alpha.3",
50
- "@storybook/preview-api": "8.0.0-alpha.3",
51
- "@storybook/telemetry": "8.0.0-alpha.3",
52
- "@storybook/types": "8.0.0-alpha.3",
49
+ "@storybook/node-logger": "8.0.0-alpha.4",
50
+ "@storybook/preview-api": "8.0.0-alpha.4",
51
+ "@storybook/telemetry": "8.0.0-alpha.4",
52
+ "@storybook/types": "8.0.0-alpha.4",
53
53
  "@types/node": "^18.0.0",
54
54
  "@types/react": "^18.0.37",
55
55
  "@types/react-dom": "^18.0.11",