diff --git a/core/config/src/index.ts b/core/config/src/index.ts index b127740c1..94c26c483 100644 --- a/core/config/src/index.ts +++ b/core/config/src/index.ts @@ -14,6 +14,7 @@ export const configFileNames = [ export interface ConfigrationResult { config: Configuration; configPath: string; + configFilePath: string; } /** * return the configration folder from command-line parameters @@ -54,12 +55,15 @@ export const loadConfiguration = ( configFileNames.includes(file.toLowerCase()), ); - return configFile - ? { - config: require(path.resolve(configPath, configFile)), - configPath, - } - : undefined; + if (configFile) { + const configFilePath = path.resolve(configPath, configFile); + return { + config: require(configFilePath), + configFilePath, + configPath, + }; + } + return undefined; }; /** diff --git a/core/loader/src/replaceSource.ts b/core/loader/src/replaceSource.ts index 890c4a6b1..a1ded2f81 100644 --- a/core/loader/src/replaceSource.ts +++ b/core/loader/src/replaceSource.ts @@ -3,9 +3,16 @@ export interface StoryPath { relPath: string; } -export const replaceSource = (stories: StoryPath[], hashKey: string) => { +export const replaceSource = ( + stories: StoryPath[], + configFilePath: string | undefined, + hashKey: string, +) => { const imports = ` const imports = {}; +const configJSON = ${ + configFilePath ? `require("${configFilePath}")` : 'undefined' + }; ${stories .map(story => `imports['${story.absPath}'] = require(${story.relPath});`) .join('\n')} @@ -59,6 +66,7 @@ ${stories const newContent = ` ${imports} ${storeConst} +store.config = configJSON; ${loadStories} ${hmr} ${exports} diff --git a/core/loader/src/runtimeLoader.ts b/core/loader/src/runtimeLoader.ts index 3c5a4699d..ad828818c 100644 --- a/core/loader/src/runtimeLoader.ts +++ b/core/loader/src/runtimeLoader.ts @@ -16,6 +16,7 @@ module.exports = function(content: string) { ); content = replaceSource( stories, + config?.configFilePath, `__COMPILATION_HASH__${params.compilationHash}`, ); return content; diff --git a/core/loader/src/store.ts b/core/loader/src/store.ts index 4ff30a132..7d1ae4f78 100644 --- a/core/loader/src/store.ts +++ b/core/loader/src/store.ts @@ -2,9 +2,14 @@ import { StoriesStore, StoryComponents, StoryPackages, + Configuration, } from '@component-controls/specification'; export interface LoadingStore { + /** + * global configuration from project config file + */ + config?: Configuration; /** * global store of packages */ diff --git a/core/specification/src/configuration.ts b/core/specification/src/configuration.ts index b8ed1d194..470bf55a7 100644 --- a/core/specification/src/configuration.ts +++ b/core/specification/src/configuration.ts @@ -17,4 +17,13 @@ export interface Configuration { * example: [story => {story()}] */ decorators?: StoryRenderFn[]; + /** + * global options object + */ + options?: { + /** + * story sorting function + */ + storySort?: (a: string, b: string) => number; + }; } diff --git a/core/specification/src/stories.ts b/core/specification/src/stories.ts index 486d5644c..75c7c8893 100644 --- a/core/specification/src/stories.ts +++ b/core/specification/src/stories.ts @@ -1,7 +1,7 @@ import { CodeLocation, PackageInfo, StoryRenderFn } from './utility'; import { StoryComponent } from './components'; import { ComponentControls } from './controls'; - +import { Configuration } from './configuration'; /** * an identifier/variable.argument in the source code */ @@ -271,6 +271,10 @@ export interface StoryPackages { * store of stories information in memory after the loader is applied */ export interface StoriesStore { + /** + * global configuration for config file + */ + config?: Configuration; /** * list of story files, or groups */ diff --git a/core/store/src/Store/Store.ts b/core/store/src/Store/Store.ts index ba4e84b1b..53915f6d6 100644 --- a/core/store/src/Store/Store.ts +++ b/core/store/src/Store/Store.ts @@ -1,4 +1,4 @@ -import { StoriesStore } from '@component-controls/specification'; +import { StoriesStore, Configuration } from '@component-controls/specification'; import { BroadcastChannel } from 'broadcast-channel'; import { StoreObserver, @@ -121,6 +121,10 @@ export class Store implements StoryStore { const store = this.getStore(); return store ? store.docs : undefined; }; + + get config(): Configuration | undefined { + return this.loadedStore?.config; + } /** * modify story properties, for example controls values. * will notify all installed store observers of the changed story. diff --git a/core/store/src/serialization/load-store.ts b/core/store/src/serialization/load-store.ts index 553455b0e..83b0d451d 100644 --- a/core/store/src/serialization/load-store.ts +++ b/core/store/src/serialization/load-store.ts @@ -25,6 +25,7 @@ export const loadStoryStore = ( stores, packages: loadedPackages, components: loadedComponents, + config, } = newStore; if (stores) { @@ -33,6 +34,7 @@ export const loadStoryStore = ( stories: {}, components: {}, packages: {}, + config, }; stores.forEach(s => { const storeDocs = s.docs; diff --git a/core/store/src/types.ts b/core/store/src/types.ts index 9e3b18622..aea4fc4ae 100644 --- a/core/store/src/types.ts +++ b/core/store/src/types.ts @@ -2,6 +2,7 @@ import { StoriesStore, Story, StoryDocs, + Configuration, } from '@component-controls/specification'; /** @@ -16,6 +17,7 @@ export interface StoryStore { getStory: (storyId: string) => Story | undefined; getStoryDoc: (name: string) => StoryDocs | undefined; getDocs: () => StoryDocs | undefined; + config: Configuration | undefined; updateStoryProp: ( storyId: string, propName: string, diff --git a/examples/gatsby/.config/main.js b/examples/gatsby/.config/main.js index a3885a6db..f3aae1e30 100644 --- a/examples/gatsby/.config/main.js +++ b/examples/gatsby/.config/main.js @@ -1,5 +1,26 @@ +const categories = ['Introduction', 'Controls','Blocks', 'Editors', 'Components', 'App components', 'Plugins']; +storySort: (a, b) => { + const aKind = a[1].kind.split('/')[0]; + const aIndex = categories.findIndex(c => c === aKind); + const bKind = b[1].kind.split('/')[0]; + const bIndex = categories.findIndex(c => c === bKind); + return aIndex - bIndex; +}, + module.exports = { stories: [ '../../stories/src/**/*.stories.(js|jsx|tsx|mdx)', + '../../../core/specification/src/stories/**/*.stories.(js|jsx|tsx|mdx)', + '../../../ui/app-components/src/**/*.stories.(js|jsx|tsx|mdx)', + '../../../ui/components/src/**/*.stories.(js|jsx|tsx|mdx)', ], + options: { + storySort: (a, b) => { + const aDoc = a.split('/')[0]; + const aIndex = categories.findIndex(c => c === aDoc); + const bDoc = b.split('/')[0]; + const bIndex = categories.findIndex(c => c === bDoc); + return aIndex - bIndex; + }, + } }; diff --git a/integrations/gatsby-theme-stories/src/gatsby-node.ts b/integrations/gatsby-theme-stories/src/gatsby-node.ts index 6145246d7..439fc58e7 100644 --- a/integrations/gatsby-theme-stories/src/gatsby-node.ts +++ b/integrations/gatsby-theme-stories/src/gatsby-node.ts @@ -1,4 +1,8 @@ -import { compile } from '@component-controls/webpack-compile'; +import { + compile, + watch, + CompileProps, +} from '@component-controls/webpack-compile'; import { NodePluginArgs, NodeInput, CreatePagesArgs } from 'gatsby'; import { StoriesStore } from '@component-controls/specification'; import { loadStoryStore } from '@component-controls/store'; @@ -11,12 +15,12 @@ exports.sourceNodes = async function sourceNodes( options: LoaderOptions, ) { const { createNode } = actions; - - const { store } = await compile({ + const config: CompileProps = { webPack: options.webpack, presets: defaultPresets, configPath: options.configPath, - }); + }; + const { store } = true ? await watch(config) : await compile(config); const loadedStore: StoriesStore | undefined = loadStoryStore(store); if (loadedStore) { diff --git a/integrations/storybook/src/preset.ts b/integrations/storybook/src/preset.ts index 164c8ed5b..dd0d28d0a 100644 --- a/integrations/storybook/src/preset.ts +++ b/integrations/storybook/src/preset.ts @@ -47,7 +47,6 @@ module.exports = { return result; }, webpackFinal: (config: any = {}, options: PresetOptions = {}) => { - debugger; const mergedConfig = mergeWebpackConfig( config, options?.webpack || defaultRules, diff --git a/plugins/axe-plugin/src/typings.d.ts b/plugins/axe-plugin/src/typings.d.ts deleted file mode 100644 index 201a6a9cf..000000000 --- a/plugins/axe-plugin/src/typings.d.ts +++ /dev/null @@ -1 +0,0 @@ -declare module 'recoil'; diff --git a/ui/app/src/Sidebar/Sidebar.tsx b/ui/app/src/Sidebar/Sidebar.tsx index ca2aa3a02..a9048bf07 100644 --- a/ui/app/src/Sidebar/Sidebar.tsx +++ b/ui/app/src/Sidebar/Sidebar.tsx @@ -65,8 +65,12 @@ export const Sidebar: FC = ({ docPath, buttonClass, title }) => { const { storeProvider } = useContext(BlockContext); const menuItems = useMemo(() => { if (storeProvider) { + const { options } = storeProvider.config || {}; + const docs: string[] = Object.keys(storeProvider.getDocs() || []); - const menuItems = docs.reduce((acc: MenuItems, doc: string) => { + const sortedDocs = + options && options.storySort ? docs.sort(options.storySort) : docs; + const menuItems = sortedDocs.reduce((acc: MenuItems, doc: string) => { const levels = doc.split('/'); createMenuItem(levels, levels, acc); return acc;