import * as React from 'react'; import { Provider, teamsTheme } from '@fluentui/react-northstar'; const reqContexts = [ // TODO: Relative pathing isn't the best here, but docs containing perf stories isn't a package that can be added as a dep. require.context('../../docs/src', true, /\.perf\.tsx$/), require.context('..', true, /\.perf\.tsx$/), // TODO: why does this break index.html?? seems to pull in stories the same way... // require.context('../stories', true, /\.perf\.tsx$/), ]; // TODO: can comment this out to remove Provider. this should be made part of URL / digest bundle. // TODO: should this be specified by story? disabled by story? applied and not applied centrally? const decorator = content => {content}; // const decorator = content => content; // TODO: type errors in this file aren't generating build errors. scripts should be typechecked as part of digest build. // TODO: most of this stuff should be in digest package, not consumer config // TODO: make nameMatcher part of consumer config with default value? // TODO: add types for all input and output // TODO: have default loadStories function that loads according to CSF but allows for overload // TODO: support iterations in story? or e2e scenarios? or both? function isFunctionalComponent(Component) { // TODO: are we supporting class components too? how will that affect this impl? return typeof Component === 'function'; } function loadStories() { const stories = {}; const nameMatcher = /\.\/([^/]+)\//; reqContexts.forEach(reqContext => { reqContext.keys().forEach((fileKey: string) => { const matches = fileKey.match(nameMatcher); // TODO: what does storybook do if two story files have the same name? merge? warn? error? // https://github.com/storybookjs/storybook/blob/5484720791e7621e9a164d58fbe79db49db1522d/lib/client-api/src/story_store.ts#L191 // This code should behave the same way. if (matches) { // TODO: fluent-ui storybook "config" seems to assume differing story file formats from CSF: only one story per file, naming, etc. // This code was modified to support multiple stories per file. Variable naming follows storybook CSF convention. // https://storybook.js.org/docs/testing/automated-visual-testing/#custom-solutions let kindName; // Attempt to read story name from file with fallback to file naming. // https://storybook.js.org/docs/formats/component-story-format/ // TODO: this should have typing (ideally from storybook) if (reqContext(fileKey).default && reqContext(fileKey).default.name) { kindName = reqContext(fileKey).default.name; } else { kindName = fileKey.substr(fileKey.lastIndexOf('/') + 1).replace('.perf.tsx', ''); } if (stories[kindName]) { // TODO: this should fail build or show a more visible warning console.error(`Kind ${kindName} already exists! Please ensure unique naming.`); } stories[kindName] = {}; // TODO: React docs impl was treating all defaults as stories, even if they were not functions. // This code ignores exports that aren't functions to more closely align with CSF format for storybook compatibility. Object.keys(reqContext(fileKey)).forEach(exportKey => { const StoryExport = reqContext(fileKey)[exportKey]; // Assign default objects to kind even if they're not functions. Leave it up to bundle // render to detect and not render 'default' if it is not a function. if ((StoryExport && isFunctionalComponent(StoryExport)) || exportKey === 'default') { stories[kindName][exportKey] = StoryExport; } }); } }); }); // TODO: If storybook has strongly defined types for kind/story structures, we should probably use them. // For now, return a simple nested dictionary backed by types. return stories; } // TODO: the rest of this should be handled by digest package const config = { stories: loadStories(), decorator, }; export default config;