diff --git a/.vscode/launch.json b/.vscode/launch.json index 65d7ba6ca..bb12f1064 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -79,7 +79,18 @@ "/**" ] }, - + { + "name": "gatsby develop", + "type": "node", + "request": "launch", + "protocol": "inspector", + "program": "${workspaceRoot}/node_modules/gatsby/dist/bin/gatsby", + "cwd": "${workspaceFolder}/examples/gatsby", + "args": ["develop"], + "stopOnEntry": false, + "runtimeArgs": ["--nolazy"], + "sourceMaps": false + }, { "type": "node", "request": "launch", diff --git a/core/store/src/index.ts b/core/store/src/index.ts index 772221f9a..a99b4711d 100644 --- a/core/store/src/index.ts +++ b/core/store/src/index.ts @@ -1,2 +1,3 @@ export * from './Store/Store'; export * from './types'; +export * from './serialization/load-store'; diff --git a/core/store/src/serialization/load-store.ts b/core/store/src/serialization/load-store.ts index e0a19e36d..66114735b 100644 --- a/core/store/src/serialization/load-store.ts +++ b/core/store/src/serialization/load-store.ts @@ -11,18 +11,21 @@ import { addSmartControls } from './smart-controls'; let storyStore: StoriesStore | undefined = undefined; -export const loadStoryStore = (): StoriesStore | undefined => { +export const loadStoryStore = ( + store?: LoadingStore, +): StoriesStore | undefined => { if (storyStore) { return storyStore; } - const store = require('@component-controls/loader/story-store-data.js'); - if (store) { + const newStore: LoadingStore = + store || require('@component-controls/loader/story-store-data.js'); + if (newStore) { try { const { stores, packages: loadedPackages, components: loadedComponents, - }: LoadingStore = store; + } = newStore; if (stores) { const globalStore: StoriesStore = { @@ -31,13 +34,13 @@ export const loadStoryStore = (): StoriesStore | undefined => { components: {}, packages: {}, }; - stores.forEach(store => { - if (Object.keys(store.kinds).length > 0) { - Object.keys(store.kinds).forEach(kindName => { - const kind = store.kinds[kindName]; + stores.forEach(s => { + if (Object.keys(s.kinds).length > 0) { + Object.keys(s.kinds).forEach(kindName => { + const kind = s.kinds[kindName]; globalStore.kinds[kindName] = kind; - Object.keys(store.stories).forEach(storyName => { - const story: Story = store.stories[storyName]; + Object.keys(s.stories).forEach(storyName => { + const story: Story = s.stories[storyName]; const { title, stories, diff --git a/core/store/src/serialization/smart-controls.ts b/core/store/src/serialization/smart-controls.ts index 87eaf5e5d..a160d123c 100644 --- a/core/store/src/serialization/smart-controls.ts +++ b/core/store/src/serialization/smart-controls.ts @@ -23,13 +23,22 @@ export const addSmartControls = ( return null; } const storyComponent = story.component || params.component; + if (!storyComponent) { return null; } - const componentName = getComponentName(storyComponent); + let componentName = getComponentName(storyComponent); + if ( + !componentName || + (!components[kind.components[componentName]] && + typeof kind.component === 'string') + ) { + componentName = kind.component as string; + } if (componentName) { const component = components[kind.components[componentName]]; - if (component.info) { + + if (component?.info) { const newControls = controlsFromProps(component.info.props); const { include, exclude } = smartControls; const usedProps: string[] | undefined = Array.isArray( diff --git a/integrations/gatsby-theme-stories/src/components/Layout.tsx b/integrations/gatsby-theme-stories/src/components/Layout.tsx index 1e38c91ee..ecb9a1eac 100644 --- a/integrations/gatsby-theme-stories/src/components/Layout.tsx +++ b/integrations/gatsby-theme-stories/src/components/Layout.tsx @@ -3,7 +3,7 @@ import React, { FC } from 'react'; import { jsx, Container } from 'theme-ui'; import { Global } from '@emotion/core'; import { ThemeProvider } from '@component-controls/components'; -import { PageContainer, store } from '@component-controls/blocks'; +import { PageContainer } from '@component-controls/blocks'; import { Store } from '@component-controls/store'; import { SEO } from './SEO'; import { Sidebar } from './Sidebar'; @@ -12,14 +12,16 @@ import { Header } from './Header'; interface LayoutProps { children: React.ReactNode; title?: string; + storyStore: Store; + storyId: string; } -export const Layout: FC = ({ children, title }) => { - const storyStore = React.useMemo( - () => new Store({ store, updateLocalStorage: false }), - [], - ); - +export const Layout: FC = ({ + children, + title, + storyStore, + storyId, +}) => { return ( = ({ children, title }) => {
- + {children} diff --git a/integrations/gatsby-theme-stories/src/components/Sidebar.tsx b/integrations/gatsby-theme-stories/src/components/Sidebar.tsx index d6c4bee17..11934ada8 100644 --- a/integrations/gatsby-theme-stories/src/components/Sidebar.tsx +++ b/integrations/gatsby-theme-stories/src/components/Sidebar.tsx @@ -2,7 +2,7 @@ import { Sidenav } from '@theme-ui/sidenav'; import { jsx, useColorMode } from 'theme-ui'; import { graphql, useStaticQuery } from 'gatsby'; -import { StoriesKind } from '@component-controls/specification'; +import { Story } from '@component-controls/specification'; import { useSiteMetadata } from '../hooks/use-site-metadata'; import { ColorMode } from './ColorMode'; @@ -17,16 +17,18 @@ export const Sidebar = () => { const data = useStaticQuery(graphql` query { - allStoryKind { + allStory { edges { node { - title + id + kind + name } } } } `); - const kinds = data.allStoryKind.edges; + const stories = data.allStory.edges; return (
{ width: `initial`, }} > - {kinds.map(({ node: kind }: { node: StoriesKind }) => ( + {stories.map(({ node: story }: { node: Story }) => ( //@ts-ignore -
  • - {kind.title} +
  • + {story.name}
  • ))} diff --git a/integrations/gatsby-theme-stories/src/gatsby-node.ts b/integrations/gatsby-theme-stories/src/gatsby-node.ts index 71fe0112a..5fce2a105 100644 --- a/integrations/gatsby-theme-stories/src/gatsby-node.ts +++ b/integrations/gatsby-theme-stories/src/gatsby-node.ts @@ -1,9 +1,12 @@ import { compile } from '@component-controls/webpack-compile'; -import { NodePluginArgs, CreatePagesArgs } from 'gatsby'; +import { NodePluginArgs, NodeInput, CreatePagesArgs } from 'gatsby'; +import { StoriesStore } from '@component-controls/specification'; +import { loadStoryStore } from '@component-controls/store'; import { LoaderOptions } from './types'; const defaultPresets = ['react', 'react-docgen-typescript']; +let loadedStore: StoriesStore | undefined; exports.sourceNodes = async function sourceNodes( { actions, createContentDigest, createNodeId }: NodePluginArgs, options: LoaderOptions, @@ -15,11 +18,14 @@ exports.sourceNodes = async function sourceNodes( presets: defaultPresets, configPath: options.configPath, }); - store.stores.forEach(s => { - Object.keys(s.kinds).forEach(key => { - const kind = s.kinds[key]; + loadedStore = loadStoryStore(store); - const nodeMetadata = { + if (loadedStore) { + Object.keys(loadedStore.kinds).forEach(key => { + //@ts-ignore + const kind = loadedStore.kinds[key]; + + const kindMetadata: NodeInput = { id: createNodeId(`storyKind-${key}`), children: [], internal: { @@ -29,34 +35,54 @@ exports.sourceNodes = async function sourceNodes( }, }; - const node = Object.assign({}, kind, nodeMetadata); - createNode(node); + const nodeKind = Object.assign({}, kind, kindMetadata); + createNode(nodeKind); }); - }); + Object.keys(loadedStore.stories).forEach(storyId => { + //@ts-ignore + const story = loadedStore.stories[storyId]; + const storyMetadata: NodeInput = { + id: storyId, + children: [], + internal: { + type: 'story', + content: JSON.stringify(story), + contentDigest: createContentDigest(story), + }, + }; + + const nodeStory = Object.assign({}, story, storyMetadata); + createNode(nodeStory); + }); + } }; exports.createPages = async ({ graphql, actions }: CreatePagesArgs) => { - const kinds = await graphql<{ - allStoryKind: any; + const stories = await graphql<{ + allStory: any; }>(` query { - allStoryKind { + allStory { edges { node { - title + id + kind + name } } } } `); const { createPage } = actions; - if (kinds.data) { - kinds.data.allStoryKind.edges.forEach(({ node }: any) => { + if (stories.data) { + stories.data.allStory.edges.forEach(({ node }: any) => { createPage({ - path: node.title.toLowerCase(), + path: `stories/${node.id}`, component: require.resolve(`../src/templates/StoryPage.tsx`), context: { title: node.title, + storyId: node.id, + loadedStore, }, }); }); diff --git a/integrations/gatsby-theme-stories/src/templates/StoryPage.tsx b/integrations/gatsby-theme-stories/src/templates/StoryPage.tsx index 5eac1b103..0a8b50c6f 100644 --- a/integrations/gatsby-theme-stories/src/templates/StoryPage.tsx +++ b/integrations/gatsby-theme-stories/src/templates/StoryPage.tsx @@ -1,16 +1,31 @@ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { ClassicPage } from '@component-controls/pages'; -import { Layout } from '../components/layout'; + +import { StoriesStore } from '@component-controls/specification'; +import { Store } from '@component-controls/store'; +import { Layout } from '../components/Layout'; interface SitePageProps { pathContext: { title: string; + loadedStore: StoriesStore; + storyId: string; }; } -const SitePage: FC = ({ pathContext: { title } }) => { +const SitePage: FC = ({ + pathContext: { title, loadedStore, storyId }, +}) => { + const storyStore = useMemo( + () => + new Store({ + store: loadedStore, + updateLocalStorage: false, + }), + [loadedStore], + ); return ( - + ); diff --git a/ui/blocks/src/PageContainer/PageContainer.tsx b/ui/blocks/src/PageContainer/PageContainer.tsx index 7e7b84d2c..4c8997433 100644 --- a/ui/blocks/src/PageContainer/PageContainer.tsx +++ b/ui/blocks/src/PageContainer/PageContainer.tsx @@ -82,7 +82,7 @@ export const PageContainer: FC = ({ }} > - {storyId && ( + {store && storyId ? ( = ({ }} + ) : ( + children )}