UNPKG

3.48 kBJavaScriptView Raw
1import { storiesOf } from '@storybook/vue';
2import camelCase from 'lodash/camelCase';
3import upperFirst from 'lodash/upperFirst';
4import { configureReadme } from 'storybook-readme';
5
6import 'url-search-params-polyfill';
7
8import { GlExampleExplorer, GlComponentDocumentation } from '../documentation';
9
10import { componentValidator as isValidComponent } from './all_components';
11
12/**
13 * This functions returns the component's name from the current window location's search
14 *
15 * Assume you have this Structure:
16 * - Base
17 * - Form
18 * - Form-Group
19 * - Default
20 * - With Validations
21 *
22 * The URI would look like this: `iframe.html?id=base-form-form-group--with-validations`
23 *
24 * The actual component name we are looking for is `GlFormGroup`.
25 * We know that we can remove the last part.
26 * But unfortunately from `base-form-form-group` we cannot guess which of the following is the component name:
27 * - GlBaseFormFormGroup
28 * - GlFormFormGroup
29 * - GlFormGroup
30 * - GlGroup
31 *
32 * So we are going to through loop all of these and return the first valid component (`GlFormGroup`)
33 *
34 * @returns {string}
35 */
36function getComponentName() {
37 const urlParams = new URLSearchParams(window.location.search);
38
39 const storySlug = urlParams.get('id').split('--')[0];
40 const splitSlug = storySlug.split('-');
41
42 let componentName;
43
44 do {
45 splitSlug.shift();
46 componentName = `Gl${upperFirst(camelCase(splitSlug.join('-')))}`;
47 } while (splitSlug.length > 0 && !isValidComponent(componentName));
48
49 if (!isValidComponent(componentName)) {
50 throw new Error('Could not find a matching component');
51 }
52
53 return componentName;
54}
55
56export const setupStorybookReadme = () =>
57 configureReadme({
58 StoryPreview: {
59 disableForComponents: ['GlAlert', 'GlSprintf', 'GlLink'],
60 components: {
61 GlComponentDocumentation,
62 GlExampleExplorer,
63 },
64 data() {
65 return {
66 componentName: null,
67 error: '',
68 // Style the preview component container
69 // Default container forcefully centers the preview element
70 styles: {
71 padding: '50px 35px',
72 margin: '16px 0',
73 border: '1px dashed rgb(229, 229, 229)',
74 },
75 };
76 },
77 // We infer the component's name from the URL so that we can load related examples and docs.
78 // This needs to be done in the created hook to make sure that componentName is always set
79 // to a valid value once the story loads.
80 created() {
81 try {
82 this.componentName = getComponentName();
83 this.error = '';
84 } catch (error) {
85 this.componentName = false;
86 this.error = error.message;
87 }
88 },
89 template: `
90 <div>
91 <slot v-if="$options.disableForComponents.includes(componentName)" />
92 <template v-else>
93 <div class="story-container" v-bind:style="styles"><slot></slot></div>
94 {{ error }}
95 <template v-if="componentName">
96 <gl-example-explorer :componentName="componentName" />
97 <gl-component-documentation :componentName="componentName" />
98 </template>
99 </template>
100 </div>`,
101 },
102 });
103
104export const documentedStoriesOf = (name, readme) => {
105 const story = storiesOf(name, module);
106 if (process.env.NODE_ENV !== 'test') {
107 story.addParameters({
108 readme: {
109 content: readme,
110 },
111 });
112 }
113 return story;
114};