From 4a4974577784cf593e5cb1a3e9a86d0f29117cf4 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Tue, 20 Jun 2023 11:25:17 +0800 Subject: [PATCH 01/10] Docs: Add opt-in Table of Contents --- code/ui/blocks/package.json | 1 + code/ui/blocks/src/blocks/DocsContainer.tsx | 12 +- code/ui/blocks/src/components/DocsPage.tsx | 31 +++- .../blocks/src/components/TableOfContents.tsx | 162 ++++++++++++++++++ code/yarn.lock | 8 + 5 files changed, 208 insertions(+), 6 deletions(-) create mode 100644 code/ui/blocks/src/components/TableOfContents.tsx diff --git a/code/ui/blocks/package.json b/code/ui/blocks/package.json index c3cc1a90c0c9..6a345d8ebd60 100644 --- a/code/ui/blocks/package.json +++ b/code/ui/blocks/package.json @@ -63,6 +63,7 @@ "polished": "^4.2.2", "react-colorful": "^5.1.2", "telejson": "^7.0.3", + "tocbot": "^4.20.1", "ts-dedent": "^2.0.0", "util-deprecate": "^1.0.2" }, diff --git a/code/ui/blocks/src/blocks/DocsContainer.tsx b/code/ui/blocks/src/blocks/DocsContainer.tsx index 8640f06a68f1..e2141a2b370c 100644 --- a/code/ui/blocks/src/blocks/DocsContainer.tsx +++ b/code/ui/blocks/src/blocks/DocsContainer.tsx @@ -9,6 +9,7 @@ import type { DocsContextProps } from './DocsContext'; import { DocsContext } from './DocsContext'; import { SourceContainer } from './SourceContainer'; import { scrollToElement } from './utils'; +import { useOf } from './useOf'; const { document, window: globalWindow } = global; @@ -22,6 +23,15 @@ export const DocsContainer: FC> = ({ theme, children, }) => { + let toc; + try { + const meta = useOf('meta', ['meta']); + toc = meta.preparedMeta.parameters?.docs?.toc || {}; + } catch (err) { + // No meta, falling back to project annotations + toc = context?.projectAnnotations?.parameters?.docs?.toc || {}; + } + useEffect(() => { let url; try { @@ -44,7 +54,7 @@ export const DocsContainer: FC> = ({ - {children} + {children} diff --git a/code/ui/blocks/src/components/DocsPage.tsx b/code/ui/blocks/src/components/DocsPage.tsx index 6b097e66063e..c4cc84f7266e 100644 --- a/code/ui/blocks/src/components/DocsPage.tsx +++ b/code/ui/blocks/src/components/DocsPage.tsx @@ -1,9 +1,11 @@ +import type { FC } from 'react'; +import React from 'react'; +import { transparentize } from 'polished'; import { withReset } from '@storybook/components'; import type { CSSObject } from '@storybook/theming'; import { styled } from '@storybook/theming'; -import { transparentize } from 'polished'; -import type { FC } from 'react'; -import React from 'react'; +import { TableOfContents } from './TableOfContents'; +import type { TocParameters } from './TableOfContents'; /** * This selector styles all raw elements inside the DocsPage like this example with a `
`: @@ -433,12 +435,31 @@ export const DocsWrapper = styled.div(({ theme }) => ({ [`@media (min-width: ${breakpoint}px)`]: {}, })); +const TocWrapper = styled.div` + display: flex; + gap: 0rem; + + @media only screen and (min-width: 1200px) { + gap: 3rem; + } +`; + +const ContentWrapper = styled.div` + width: 100%; +`; + interface DocsPageWrapperProps { children?: React.ReactNode; + toc?: TocParameters; } -export const DocsPageWrapper: FC = ({ children }) => ( +export const DocsPageWrapper: FC = ({ children, toc }) => ( - {children} + + + {children} + {toc ? : null} + + ); diff --git a/code/ui/blocks/src/components/TableOfContents.tsx b/code/ui/blocks/src/components/TableOfContents.tsx new file mode 100644 index 000000000000..bbea7ff84df1 --- /dev/null +++ b/code/ui/blocks/src/components/TableOfContents.tsx @@ -0,0 +1,162 @@ +import React, { useEffect } from 'react'; +import type { FC, ReactElement } from 'react'; +import { styled } from '@storybook/theming'; +import tocbot from 'tocbot'; + +export interface TocParameters { + /** CSS selector for the container to search for headings. */ + contentsSelector?: string; + + /** + * When true, hide the TOC. We still show the empty container + * (as opposed to showing nothing at all) because it affects the + * page layout and we want to preserve the layout across pages. + */ + disable?: boolean; + + /** CSS selector to match headings to list in the TOC. */ + headingSelector?: string; + + /** Headings that match the ignoreSelector will be skipped. */ + ignoreSelector?: string; + + /** Custom title ReactElement or string to display above the TOC. */ + title?: ReactElement | string | null; + + /** + * TocBot options, not guaranteed to be available in future versions. + * See [tocbot docs](https://tscanlin.github.io/tocbot/#usage) + */ + unsafeTocbotOptions?: tocbot.IStaticOptions; +} + +const space = (n: number) => `${n * 10}px`; + +const Container = styled('div')` + font-family: ${(p) => p.theme.typography.fonts.base}; + height: 100%; + display: none; + width: 10rem; + + @media only screen and (min-width: 1200px) { + display: block; + } +`; + +const Content = styled('div')` + position: fixed; + top: 0; + width: 10rem; + padding-top: 4rem; + + & > .toc-wrapper > .toc-list { + padding-left: 0; + border-left: solid 2px ${(p) => p.theme.color.mediumlight}; + + .toc-list { + padding-left: 0; + border-left: solid 2px ${(p) => p.theme.color.mediumlight}; + + .toc-list { + padding-left: 0; + border-left: solid 2px ${(p) => p.theme.color.mediumlight}; + } + } + } + & .toc-list-item { + position: relative; + list-style-type: none; + margin-left: ${space(2)}; + } + & .toc-list-item::before { + content: ''; + position: absolute; + height: 100%; + top: 0; + left: 0; + transform: translateX(calc(-2px - ${space(2)})); + border-left: solid 2px ${(p) => p.theme.color.mediumdark}; + opacity: 0; + transition: opacity 0.2s; + } + & .toc-list-item.is-active-li::before { + opacity: 1; + } + & .toc-list-item > a { + color: ${(p) => p.theme.color.defaultText}; + } + & .toc-list-item.is-active-li > a { + font-weight: 600; + color: ${(p) => p.theme.color.secondary}; + } +`; + +const Heading = styled('p')` + font-weight: 600; + font-size: 0.875em; + color: ${(p) => p.theme.textColor}; + text-transform: uppercase; + margin-bottom: ${space(1)}; +`; + +type TableOfContentsProps = React.PropsWithChildren< + TocParameters & { + className?: string; + } +>; + +const OptionalTitle: FC<{ title: TableOfContentsProps['title'] }> = ({ title }) => { + if (title === null) return null; + if (typeof title === 'string') return {title}; + return title; +}; + +export const TableOfContents = ({ + title, + disable, + headingSelector, + contentsSelector, + ignoreSelector, + unsafeTocbotOptions, +}: TableOfContentsProps) => { + console.log({ title, disable, headingSelector, ignoreSelector, unsafeTocbotOptions }); + useEffect(() => { + const configuration = { + tocSelector: '.toc-wrapper', + contentSelector: contentsSelector ?? '.sbdocs-content', + headingSelector: headingSelector ?? 'h3', + ignoreSelector: ignoreSelector ?? '.skip-toc', + headingsOffset: 40, + scrollSmoothOffset: -40, + /** + * Ignore headings that did not + * come from the main markdown code. + */ + // ignoreSelector: ':not(.sbdocs), .hide-from-toc', + orderedList: false, + /** + * Prevent default linking behavior, + * leaving only the smooth scrolling. + */ + onClick: () => false, + ...unsafeTocbotOptions, + }; + console.log({ configuration }); + + /** + * Wait for the DOM to be ready. + */ + setTimeout(() => tocbot.init(configuration), 100); + }, [disable]); + + return ( + + {!disable && ( + + +
+ + )} + + ); +}; diff --git a/code/yarn.lock b/code/yarn.lock index b5e567ea951c..f6e79c1bcc5d 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5802,6 +5802,7 @@ __metadata: polished: ^4.2.2 react-colorful: ^5.1.2 telejson: ^7.0.3 + tocbot: ^4.20.1 ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 peerDependencies: @@ -29196,6 +29197,13 @@ __metadata: languageName: node linkType: hard +"tocbot@npm:^4.20.1": + version: 4.21.0 + resolution: "tocbot@npm:4.21.0" + checksum: 877d99df40c07ec5e5c2259b820be9c8af9a9f52d582a61b7bed3d43daff820f23031bc613a5cc3bb14ecc34b79c1a45349dcbae8f3a79de7ecc127f366ed3c6 + languageName: node + linkType: hard + "toggle-selection@npm:^1.0.6": version: 1.0.6 resolution: "toggle-selection@npm:1.0.6" From bd15fe715dfe8ce954dbeda6e400fdc7d4bd544c Mon Sep 17 00:00:00 2001 From: Norbert de Langen Date: Tue, 20 Jun 2023 17:01:03 +0200 Subject: [PATCH 02/10] make changes --- code/ui/.storybook/preview.tsx | 1 + code/ui/blocks/src/blocks/DocsContainer.tsx | 7 +- code/ui/blocks/src/components/DocsPage.tsx | 25 +-- .../blocks/src/components/TableOfContents.tsx | 181 ++++++++++-------- 4 files changed, 111 insertions(+), 103 deletions(-) diff --git a/code/ui/.storybook/preview.tsx b/code/ui/.storybook/preview.tsx index 7c52ad023776..c89c15e85db4 100644 --- a/code/ui/.storybook/preview.tsx +++ b/code/ui/.storybook/preview.tsx @@ -277,6 +277,7 @@ export const parameters = { }, docs: { theme: themes.light, + toc: {}, }, controls: { presetColors: [ diff --git a/code/ui/blocks/src/blocks/DocsContainer.tsx b/code/ui/blocks/src/blocks/DocsContainer.tsx index e2141a2b370c..ea49c6d57b1d 100644 --- a/code/ui/blocks/src/blocks/DocsContainer.tsx +++ b/code/ui/blocks/src/blocks/DocsContainer.tsx @@ -10,6 +10,7 @@ import { DocsContext } from './DocsContext'; import { SourceContainer } from './SourceContainer'; import { scrollToElement } from './utils'; import { useOf } from './useOf'; +import { TableOfContents } from '../components/TableOfContents'; const { document, window: globalWindow } = global; @@ -54,7 +55,11 @@ export const DocsContainer: FC> = ({ - {children} + : null} + > + {children} + diff --git a/code/ui/blocks/src/components/DocsPage.tsx b/code/ui/blocks/src/components/DocsPage.tsx index c4cc84f7266e..796bbb563f90 100644 --- a/code/ui/blocks/src/components/DocsPage.tsx +++ b/code/ui/blocks/src/components/DocsPage.tsx @@ -4,7 +4,6 @@ import { transparentize } from 'polished'; import { withReset } from '@storybook/components'; import type { CSSObject } from '@storybook/theming'; import { styled } from '@storybook/theming'; -import { TableOfContents } from './TableOfContents'; import type { TocParameters } from './TableOfContents'; /** @@ -431,35 +430,19 @@ export const DocsWrapper = styled.div(({ theme }) => ({ padding: '4rem 20px', minHeight: '100vh', boxSizing: 'border-box', + gap: '3rem', [`@media (min-width: ${breakpoint}px)`]: {}, })); -const TocWrapper = styled.div` - display: flex; - gap: 0rem; - - @media only screen and (min-width: 1200px) { - gap: 3rem; - } -`; - -const ContentWrapper = styled.div` - width: 100%; -`; - interface DocsPageWrapperProps { children?: React.ReactNode; - toc?: TocParameters; + toc?: React.ReactNode; } export const DocsPageWrapper: FC = ({ children, toc }) => ( - - - {children} - {toc ? : null} - - + {children} + {toc} ); diff --git a/code/ui/blocks/src/components/TableOfContents.tsx b/code/ui/blocks/src/components/TableOfContents.tsx index bbea7ff84df1..c5ee1a6048b6 100644 --- a/code/ui/blocks/src/components/TableOfContents.tsx +++ b/code/ui/blocks/src/components/TableOfContents.tsx @@ -30,74 +30,85 @@ export interface TocParameters { unsafeTocbotOptions?: tocbot.IStaticOptions; } -const space = (n: number) => `${n * 10}px`; - -const Container = styled('div')` - font-family: ${(p) => p.theme.typography.fonts.base}; - height: 100%; - display: none; - width: 10rem; - - @media only screen and (min-width: 1200px) { - display: block; - } -`; - -const Content = styled('div')` - position: fixed; - top: 0; - width: 10rem; - padding-top: 4rem; - - & > .toc-wrapper > .toc-list { - padding-left: 0; - border-left: solid 2px ${(p) => p.theme.color.mediumlight}; - - .toc-list { - padding-left: 0; - border-left: solid 2px ${(p) => p.theme.color.mediumlight}; - - .toc-list { - padding-left: 0; - border-left: solid 2px ${(p) => p.theme.color.mediumlight}; - } - } - } - & .toc-list-item { - position: relative; - list-style-type: none; - margin-left: ${space(2)}; - } - & .toc-list-item::before { - content: ''; - position: absolute; - height: 100%; - top: 0; - left: 0; - transform: translateX(calc(-2px - ${space(2)})); - border-left: solid 2px ${(p) => p.theme.color.mediumdark}; - opacity: 0; - transition: opacity 0.2s; - } - & .toc-list-item.is-active-li::before { - opacity: 1; - } - & .toc-list-item > a { - color: ${(p) => p.theme.color.defaultText}; - } - & .toc-list-item.is-active-li > a { - font-weight: 600; - color: ${(p) => p.theme.color.secondary}; - } -`; - -const Heading = styled('p')` - font-weight: 600; - font-size: 0.875em; - color: ${(p) => p.theme.textColor}; - text-transform: uppercase; - margin-bottom: ${space(1)}; -`; +const Wrapper = styled.div(({ theme }) => ({ + width: '10rem', + + '@media (max-width: 768px)': { + display: 'none', + }, +})); + +const Content = styled.div(({ theme }) => ({ + position: 'fixed', + top: 0, + width: '10rem', + paddingTop: '4rem', + + fontFamily: theme.typography.fonts.base, + fontSize: theme.typography.size.s2, + + WebkitFontSmoothing: 'antialiased', + MozOsxFontSmoothing: 'grayscale', + WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)', + WebkitOverflowScrolling: 'touch', + + '& *': { + boxSizing: 'border-box', + }, + + '& > .toc-wrapper > .toc-list': { + paddingLeft: 0, + borderLeft: `solid 2px ${theme.color.mediumlight}`, + + '.toc-list': { + paddingLeft: 0, + borderLeft: `solid 2px ${theme.color.mediumlight}`, + + '.toc-list': { + paddingLeft: 0, + borderLeft: `solid 2px ${theme.color.mediumlight}`, + }, + }, + }, + '& .toc-list-item': { + position: 'relative', + listStyleType: 'none', + marginLeft: 20, + paddingTop: 3, + paddingBottom: 3, + }, + '& .toc-list-item::before': { + content: '""', + position: 'absolute', + height: '100%', + top: 0, + left: 0, + transform: `translateX(calc(-2px - 20px))`, + borderLeft: `solid 2px ${theme.color.mediumdark}`, + opacity: 0, + transition: 'opacity 0.2s', + }, + '& .toc-list-item.is-active-li::before': { + opacity: 1, + }, + '& .toc-list-item > a': { + color: theme.color.defaultText, + textDecoration: 'none', + }, + '& .toc-list-item.is-active-li > a': { + fontWeight: 600, + color: theme.color.secondary, + textDecoration: 'none', + }, +})); + +const Heading = styled.p(({ theme }) => ({ + fontWeight: 600, + fontSize: '0.875em', + color: theme.textColor, + textTransform: 'uppercase', + marginBottom: 10, +})); type TableOfContentsProps = React.PropsWithChildren< TocParameters & { @@ -106,8 +117,12 @@ type TableOfContentsProps = React.PropsWithChildren< >; const OptionalTitle: FC<{ title: TableOfContentsProps['title'] }> = ({ title }) => { - if (title === null) return null; - if (typeof title === 'string') return {title}; + if (title === null) { + return null; + } + if (typeof title === 'string') { + return {title}; + } return title; }; @@ -119,7 +134,6 @@ export const TableOfContents = ({ ignoreSelector, unsafeTocbotOptions, }: TableOfContentsProps) => { - console.log({ title, disable, headingSelector, ignoreSelector, unsafeTocbotOptions }); useEffect(() => { const configuration = { tocSelector: '.toc-wrapper', @@ -141,22 +155,27 @@ export const TableOfContents = ({ onClick: () => false, ...unsafeTocbotOptions, }; - console.log({ configuration }); /** * Wait for the DOM to be ready. */ - setTimeout(() => tocbot.init(configuration), 100); + const timeout = setTimeout(() => tocbot.init(configuration), 100); + return () => { + clearTimeout(timeout); + tocbot.destroy(); + }; }, [disable]); return ( - - {!disable && ( - - -
- - )} - + <> + + {!disable ? ( + + +
+ + ) : null} + + ); }; From 054630104fc8198977754f640f20091c1dfc6f62 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 22 Jun 2023 00:18:04 +0800 Subject: [PATCH 03/10] Fix build --- code/ui/blocks/src/components/DocsPage.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/code/ui/blocks/src/components/DocsPage.tsx b/code/ui/blocks/src/components/DocsPage.tsx index 796bbb563f90..112025269863 100644 --- a/code/ui/blocks/src/components/DocsPage.tsx +++ b/code/ui/blocks/src/components/DocsPage.tsx @@ -4,7 +4,6 @@ import { transparentize } from 'polished'; import { withReset } from '@storybook/components'; import type { CSSObject } from '@storybook/theming'; import { styled } from '@storybook/theming'; -import type { TocParameters } from './TableOfContents'; /** * This selector styles all raw elements inside the DocsPage like this example with a `
`: From fe01f47500b6de56c99826e8da9f49930a6d5eee Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 6 Jul 2023 00:12:39 +0800 Subject: [PATCH 04/10] Addon-docs: Fix bug where TOC is always showing --- code/ui/blocks/src/blocks/DocsContainer.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/ui/blocks/src/blocks/DocsContainer.tsx b/code/ui/blocks/src/blocks/DocsContainer.tsx index ea49c6d57b1d..60756a7ae25a 100644 --- a/code/ui/blocks/src/blocks/DocsContainer.tsx +++ b/code/ui/blocks/src/blocks/DocsContainer.tsx @@ -25,12 +25,13 @@ export const DocsContainer: FC> = ({ children, }) => { let toc; + try { const meta = useOf('meta', ['meta']); - toc = meta.preparedMeta.parameters?.docs?.toc || {}; + toc = meta.preparedMeta.parameters?.docs?.toc; } catch (err) { // No meta, falling back to project annotations - toc = context?.projectAnnotations?.parameters?.docs?.toc || {}; + toc = context?.projectAnnotations?.parameters?.docs?.toc; } useEffect(() => { From 43a5531da3457f7500d1c32e397299de6c6ea678 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 6 Jul 2023 00:13:04 +0800 Subject: [PATCH 05/10] Remove spurious console.log --- code/builders/builder-manager/src/index.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/code/builders/builder-manager/src/index.ts b/code/builders/builder-manager/src/index.ts index 3597a206ec46..e2bdf248be82 100644 --- a/code/builders/builder-manager/src/index.ts +++ b/code/builders/builder-manager/src/index.ts @@ -190,7 +190,6 @@ const starter: StarterFunction = async function* starterGeneratorFn({ } }); router.use(`/index.html`, ({ path }, res) => { - console.log({ path }); res.status(200).send(html); }); From e09f436a8a661cdcfa1a68fb5e0a6cfcecff2cfd Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 6 Jul 2023 00:14:55 +0800 Subject: [PATCH 06/10] Addon-docs: Add TOC stories --- .../template/stories/toc/basic.stories.ts | 22 +++++++++++++++++++ .../stories/toc/custom-selector.stories.ts | 13 +++++++++++ .../stories/toc/custom-title.stories.ts | 13 +++++++++++ .../stories/toc/ignore-selector.stories.ts | 13 +++++++++++ 4 files changed, 61 insertions(+) create mode 100644 code/addons/docs/template/stories/toc/basic.stories.ts create mode 100644 code/addons/docs/template/stories/toc/custom-selector.stories.ts create mode 100644 code/addons/docs/template/stories/toc/custom-title.stories.ts create mode 100644 code/addons/docs/template/stories/toc/ignore-selector.stories.ts diff --git a/code/addons/docs/template/stories/toc/basic.stories.ts b/code/addons/docs/template/stories/toc/basic.stories.ts new file mode 100644 index 000000000000..c66fe554aa34 --- /dev/null +++ b/code/addons/docs/template/stories/toc/basic.stories.ts @@ -0,0 +1,22 @@ +import { global as globalThis } from '@storybook/global'; + +export default { + component: globalThis.Components.Button, + tags: ['autodocs'], + parameters: { + chromatic: { disable: true }, + docs: { toc: {} }, + }, +}; + +export const One = { + args: { label: 'One' }, +}; + +export const Two = { + args: { label: 'Two' }, +}; + +export const Three = { + args: { label: 'Two' }, +}; diff --git a/code/addons/docs/template/stories/toc/custom-selector.stories.ts b/code/addons/docs/template/stories/toc/custom-selector.stories.ts new file mode 100644 index 000000000000..f000675593d8 --- /dev/null +++ b/code/addons/docs/template/stories/toc/custom-selector.stories.ts @@ -0,0 +1,13 @@ +import { global as globalThis } from '@storybook/global'; +import { One, Two, Three } from './basic.stories'; + +export default { + component: globalThis.Components.Button, + tags: ['autodocs'], + parameters: { + chromatic: { disable: true }, + docs: { toc: { headingSelector: 'h1, h2, h3' } }, + }, +}; + +export { One, Two, Three }; diff --git a/code/addons/docs/template/stories/toc/custom-title.stories.ts b/code/addons/docs/template/stories/toc/custom-title.stories.ts new file mode 100644 index 000000000000..6b079cf36659 --- /dev/null +++ b/code/addons/docs/template/stories/toc/custom-title.stories.ts @@ -0,0 +1,13 @@ +import { global as globalThis } from '@storybook/global'; +import { One, Two, Three } from './basic.stories'; + +export default { + component: globalThis.Components.Button, + tags: ['autodocs'], + parameters: { + chromatic: { disable: true }, + docs: { toc: { title: 'Contents' } }, + }, +}; + +export { One, Two, Three }; diff --git a/code/addons/docs/template/stories/toc/ignore-selector.stories.ts b/code/addons/docs/template/stories/toc/ignore-selector.stories.ts new file mode 100644 index 000000000000..9a3721b5742b --- /dev/null +++ b/code/addons/docs/template/stories/toc/ignore-selector.stories.ts @@ -0,0 +1,13 @@ +import { global as globalThis } from '@storybook/global'; +import { One, Two, Three } from './basic.stories'; + +export default { + component: globalThis.Components.Button, + tags: ['autodocs'], + parameters: { + chromatic: { disable: true }, + docs: { toc: { ignoreSelector: '#one' } }, + }, +}; + +export { One, Two, Three }; From 90c9929d32f24700612d70ec8d92a9914ec244c1 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 6 Jul 2023 00:23:38 +0800 Subject: [PATCH 07/10] Addon-docs: Fix TOC context bug --- code/ui/blocks/src/blocks/DocsContainer.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ui/blocks/src/blocks/DocsContainer.tsx b/code/ui/blocks/src/blocks/DocsContainer.tsx index 60756a7ae25a..58e4d2b3a824 100644 --- a/code/ui/blocks/src/blocks/DocsContainer.tsx +++ b/code/ui/blocks/src/blocks/DocsContainer.tsx @@ -27,7 +27,7 @@ export const DocsContainer: FC> = ({ let toc; try { - const meta = useOf('meta', ['meta']); + const meta = context.resolveOf('meta', ['meta']); toc = meta.preparedMeta.parameters?.docs?.toc; } catch (err) { // No meta, falling back to project annotations From 76ca248055cda84f1204e1c07c19c35800effc54 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 6 Jul 2023 00:27:53 +0800 Subject: [PATCH 08/10] Cleanup --- code/addons/docs/template/stories/toc/custom-selector.stories.ts | 1 + code/addons/docs/template/stories/toc/custom-title.stories.ts | 1 + code/addons/docs/template/stories/toc/ignore-selector.stories.ts | 1 + code/ui/blocks/src/blocks/DocsContainer.tsx | 1 - 4 files changed, 3 insertions(+), 1 deletion(-) diff --git a/code/addons/docs/template/stories/toc/custom-selector.stories.ts b/code/addons/docs/template/stories/toc/custom-selector.stories.ts index f000675593d8..48f1ee785156 100644 --- a/code/addons/docs/template/stories/toc/custom-selector.stories.ts +++ b/code/addons/docs/template/stories/toc/custom-selector.stories.ts @@ -6,6 +6,7 @@ export default { tags: ['autodocs'], parameters: { chromatic: { disable: true }, + // Select all the headings in the document docs: { toc: { headingSelector: 'h1, h2, h3' } }, }, }; diff --git a/code/addons/docs/template/stories/toc/custom-title.stories.ts b/code/addons/docs/template/stories/toc/custom-title.stories.ts index 6b079cf36659..2fde6ebcabf3 100644 --- a/code/addons/docs/template/stories/toc/custom-title.stories.ts +++ b/code/addons/docs/template/stories/toc/custom-title.stories.ts @@ -6,6 +6,7 @@ export default { tags: ['autodocs'], parameters: { chromatic: { disable: true }, + // Custom title label docs: { toc: { title: 'Contents' } }, }, }; diff --git a/code/addons/docs/template/stories/toc/ignore-selector.stories.ts b/code/addons/docs/template/stories/toc/ignore-selector.stories.ts index 9a3721b5742b..d355ac9ae966 100644 --- a/code/addons/docs/template/stories/toc/ignore-selector.stories.ts +++ b/code/addons/docs/template/stories/toc/ignore-selector.stories.ts @@ -6,6 +6,7 @@ export default { tags: ['autodocs'], parameters: { chromatic: { disable: true }, + // Skip the first story in the TOC docs: { toc: { ignoreSelector: '#one' } }, }, }; diff --git a/code/ui/blocks/src/blocks/DocsContainer.tsx b/code/ui/blocks/src/blocks/DocsContainer.tsx index 58e4d2b3a824..07b855295f10 100644 --- a/code/ui/blocks/src/blocks/DocsContainer.tsx +++ b/code/ui/blocks/src/blocks/DocsContainer.tsx @@ -9,7 +9,6 @@ import type { DocsContextProps } from './DocsContext'; import { DocsContext } from './DocsContext'; import { SourceContainer } from './SourceContainer'; import { scrollToElement } from './utils'; -import { useOf } from './useOf'; import { TableOfContents } from '../components/TableOfContents'; const { document, window: globalWindow } = global; From 995732e0a7a47d107010219fdfa3cc9ff5cebc96 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 6 Jul 2023 17:31:38 +0800 Subject: [PATCH 09/10] Update code/ui/blocks/src/components/TableOfContents.tsx Co-authored-by: Jeppe Reinhold --- code/ui/blocks/src/components/TableOfContents.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/ui/blocks/src/components/TableOfContents.tsx b/code/ui/blocks/src/components/TableOfContents.tsx index c5ee1a6048b6..892f1e137f20 100644 --- a/code/ui/blocks/src/components/TableOfContents.tsx +++ b/code/ui/blocks/src/components/TableOfContents.tsx @@ -25,7 +25,7 @@ export interface TocParameters { /** * TocBot options, not guaranteed to be available in future versions. - * See [tocbot docs](https://tscanlin.github.io/tocbot/#usage) + * @see tocbot docs {@link https://tscanlin.github.io/tocbot/#usage} */ unsafeTocbotOptions?: tocbot.IStaticOptions; } From deeac7737763c6c23f2c4f80cba981b99952b235 Mon Sep 17 00:00:00 2001 From: Michael Shilman Date: Thu, 6 Jul 2023 17:54:03 +0800 Subject: [PATCH 10/10] Revert "Addon-docs: Add opt-in table of contents" --- .../template/stories/toc/basic.stories.ts | 22 --- .../stories/toc/custom-selector.stories.ts | 14 -- .../stories/toc/custom-title.stories.ts | 14 -- .../stories/toc/ignore-selector.stories.ts | 14 -- code/builders/builder-manager/src/index.ts | 1 + code/ui/.storybook/preview.tsx | 1 - code/ui/blocks/package.json | 1 - code/ui/blocks/src/blocks/DocsContainer.tsx | 17 +- code/ui/blocks/src/components/DocsPage.tsx | 11 +- .../blocks/src/components/TableOfContents.tsx | 181 ------------------ code/yarn.lock | 8 - 11 files changed, 6 insertions(+), 278 deletions(-) delete mode 100644 code/addons/docs/template/stories/toc/basic.stories.ts delete mode 100644 code/addons/docs/template/stories/toc/custom-selector.stories.ts delete mode 100644 code/addons/docs/template/stories/toc/custom-title.stories.ts delete mode 100644 code/addons/docs/template/stories/toc/ignore-selector.stories.ts delete mode 100644 code/ui/blocks/src/components/TableOfContents.tsx diff --git a/code/addons/docs/template/stories/toc/basic.stories.ts b/code/addons/docs/template/stories/toc/basic.stories.ts deleted file mode 100644 index c66fe554aa34..000000000000 --- a/code/addons/docs/template/stories/toc/basic.stories.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { global as globalThis } from '@storybook/global'; - -export default { - component: globalThis.Components.Button, - tags: ['autodocs'], - parameters: { - chromatic: { disable: true }, - docs: { toc: {} }, - }, -}; - -export const One = { - args: { label: 'One' }, -}; - -export const Two = { - args: { label: 'Two' }, -}; - -export const Three = { - args: { label: 'Two' }, -}; diff --git a/code/addons/docs/template/stories/toc/custom-selector.stories.ts b/code/addons/docs/template/stories/toc/custom-selector.stories.ts deleted file mode 100644 index 48f1ee785156..000000000000 --- a/code/addons/docs/template/stories/toc/custom-selector.stories.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { global as globalThis } from '@storybook/global'; -import { One, Two, Three } from './basic.stories'; - -export default { - component: globalThis.Components.Button, - tags: ['autodocs'], - parameters: { - chromatic: { disable: true }, - // Select all the headings in the document - docs: { toc: { headingSelector: 'h1, h2, h3' } }, - }, -}; - -export { One, Two, Three }; diff --git a/code/addons/docs/template/stories/toc/custom-title.stories.ts b/code/addons/docs/template/stories/toc/custom-title.stories.ts deleted file mode 100644 index 2fde6ebcabf3..000000000000 --- a/code/addons/docs/template/stories/toc/custom-title.stories.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { global as globalThis } from '@storybook/global'; -import { One, Two, Three } from './basic.stories'; - -export default { - component: globalThis.Components.Button, - tags: ['autodocs'], - parameters: { - chromatic: { disable: true }, - // Custom title label - docs: { toc: { title: 'Contents' } }, - }, -}; - -export { One, Two, Three }; diff --git a/code/addons/docs/template/stories/toc/ignore-selector.stories.ts b/code/addons/docs/template/stories/toc/ignore-selector.stories.ts deleted file mode 100644 index d355ac9ae966..000000000000 --- a/code/addons/docs/template/stories/toc/ignore-selector.stories.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { global as globalThis } from '@storybook/global'; -import { One, Two, Three } from './basic.stories'; - -export default { - component: globalThis.Components.Button, - tags: ['autodocs'], - parameters: { - chromatic: { disable: true }, - // Skip the first story in the TOC - docs: { toc: { ignoreSelector: '#one' } }, - }, -}; - -export { One, Two, Three }; diff --git a/code/builders/builder-manager/src/index.ts b/code/builders/builder-manager/src/index.ts index e2bdf248be82..3597a206ec46 100644 --- a/code/builders/builder-manager/src/index.ts +++ b/code/builders/builder-manager/src/index.ts @@ -190,6 +190,7 @@ const starter: StarterFunction = async function* starterGeneratorFn({ } }); router.use(`/index.html`, ({ path }, res) => { + console.log({ path }); res.status(200).send(html); }); diff --git a/code/ui/.storybook/preview.tsx b/code/ui/.storybook/preview.tsx index c89c15e85db4..7c52ad023776 100644 --- a/code/ui/.storybook/preview.tsx +++ b/code/ui/.storybook/preview.tsx @@ -277,7 +277,6 @@ export const parameters = { }, docs: { theme: themes.light, - toc: {}, }, controls: { presetColors: [ diff --git a/code/ui/blocks/package.json b/code/ui/blocks/package.json index 564ebb3a4c77..b3d11cff17df 100644 --- a/code/ui/blocks/package.json +++ b/code/ui/blocks/package.json @@ -63,7 +63,6 @@ "polished": "^4.2.2", "react-colorful": "^5.1.2", "telejson": "^7.0.3", - "tocbot": "^4.20.1", "ts-dedent": "^2.0.0", "util-deprecate": "^1.0.2" }, diff --git a/code/ui/blocks/src/blocks/DocsContainer.tsx b/code/ui/blocks/src/blocks/DocsContainer.tsx index 07b855295f10..8640f06a68f1 100644 --- a/code/ui/blocks/src/blocks/DocsContainer.tsx +++ b/code/ui/blocks/src/blocks/DocsContainer.tsx @@ -9,7 +9,6 @@ import type { DocsContextProps } from './DocsContext'; import { DocsContext } from './DocsContext'; import { SourceContainer } from './SourceContainer'; import { scrollToElement } from './utils'; -import { TableOfContents } from '../components/TableOfContents'; const { document, window: globalWindow } = global; @@ -23,16 +22,6 @@ export const DocsContainer: FC> = ({ theme, children, }) => { - let toc; - - try { - const meta = context.resolveOf('meta', ['meta']); - toc = meta.preparedMeta.parameters?.docs?.toc; - } catch (err) { - // No meta, falling back to project annotations - toc = context?.projectAnnotations?.parameters?.docs?.toc; - } - useEffect(() => { let url; try { @@ -55,11 +44,7 @@ export const DocsContainer: FC> = ({ - : null} - > - {children} - + {children} diff --git a/code/ui/blocks/src/components/DocsPage.tsx b/code/ui/blocks/src/components/DocsPage.tsx index 112025269863..6b097e66063e 100644 --- a/code/ui/blocks/src/components/DocsPage.tsx +++ b/code/ui/blocks/src/components/DocsPage.tsx @@ -1,9 +1,9 @@ -import type { FC } from 'react'; -import React from 'react'; -import { transparentize } from 'polished'; import { withReset } from '@storybook/components'; import type { CSSObject } from '@storybook/theming'; import { styled } from '@storybook/theming'; +import { transparentize } from 'polished'; +import type { FC } from 'react'; +import React from 'react'; /** * This selector styles all raw elements inside the DocsPage like this example with a `
`: @@ -429,19 +429,16 @@ export const DocsWrapper = styled.div(({ theme }) => ({ padding: '4rem 20px', minHeight: '100vh', boxSizing: 'border-box', - gap: '3rem', [`@media (min-width: ${breakpoint}px)`]: {}, })); interface DocsPageWrapperProps { children?: React.ReactNode; - toc?: React.ReactNode; } -export const DocsPageWrapper: FC = ({ children, toc }) => ( +export const DocsPageWrapper: FC = ({ children }) => ( {children} - {toc} ); diff --git a/code/ui/blocks/src/components/TableOfContents.tsx b/code/ui/blocks/src/components/TableOfContents.tsx deleted file mode 100644 index 892f1e137f20..000000000000 --- a/code/ui/blocks/src/components/TableOfContents.tsx +++ /dev/null @@ -1,181 +0,0 @@ -import React, { useEffect } from 'react'; -import type { FC, ReactElement } from 'react'; -import { styled } from '@storybook/theming'; -import tocbot from 'tocbot'; - -export interface TocParameters { - /** CSS selector for the container to search for headings. */ - contentsSelector?: string; - - /** - * When true, hide the TOC. We still show the empty container - * (as opposed to showing nothing at all) because it affects the - * page layout and we want to preserve the layout across pages. - */ - disable?: boolean; - - /** CSS selector to match headings to list in the TOC. */ - headingSelector?: string; - - /** Headings that match the ignoreSelector will be skipped. */ - ignoreSelector?: string; - - /** Custom title ReactElement or string to display above the TOC. */ - title?: ReactElement | string | null; - - /** - * TocBot options, not guaranteed to be available in future versions. - * @see tocbot docs {@link https://tscanlin.github.io/tocbot/#usage} - */ - unsafeTocbotOptions?: tocbot.IStaticOptions; -} - -const Wrapper = styled.div(({ theme }) => ({ - width: '10rem', - - '@media (max-width: 768px)': { - display: 'none', - }, -})); - -const Content = styled.div(({ theme }) => ({ - position: 'fixed', - top: 0, - width: '10rem', - paddingTop: '4rem', - - fontFamily: theme.typography.fonts.base, - fontSize: theme.typography.size.s2, - - WebkitFontSmoothing: 'antialiased', - MozOsxFontSmoothing: 'grayscale', - WebkitTapHighlightColor: 'rgba(0, 0, 0, 0)', - WebkitOverflowScrolling: 'touch', - - '& *': { - boxSizing: 'border-box', - }, - - '& > .toc-wrapper > .toc-list': { - paddingLeft: 0, - borderLeft: `solid 2px ${theme.color.mediumlight}`, - - '.toc-list': { - paddingLeft: 0, - borderLeft: `solid 2px ${theme.color.mediumlight}`, - - '.toc-list': { - paddingLeft: 0, - borderLeft: `solid 2px ${theme.color.mediumlight}`, - }, - }, - }, - '& .toc-list-item': { - position: 'relative', - listStyleType: 'none', - marginLeft: 20, - paddingTop: 3, - paddingBottom: 3, - }, - '& .toc-list-item::before': { - content: '""', - position: 'absolute', - height: '100%', - top: 0, - left: 0, - transform: `translateX(calc(-2px - 20px))`, - borderLeft: `solid 2px ${theme.color.mediumdark}`, - opacity: 0, - transition: 'opacity 0.2s', - }, - '& .toc-list-item.is-active-li::before': { - opacity: 1, - }, - '& .toc-list-item > a': { - color: theme.color.defaultText, - textDecoration: 'none', - }, - '& .toc-list-item.is-active-li > a': { - fontWeight: 600, - color: theme.color.secondary, - textDecoration: 'none', - }, -})); - -const Heading = styled.p(({ theme }) => ({ - fontWeight: 600, - fontSize: '0.875em', - color: theme.textColor, - textTransform: 'uppercase', - marginBottom: 10, -})); - -type TableOfContentsProps = React.PropsWithChildren< - TocParameters & { - className?: string; - } ->; - -const OptionalTitle: FC<{ title: TableOfContentsProps['title'] }> = ({ title }) => { - if (title === null) { - return null; - } - if (typeof title === 'string') { - return {title}; - } - return title; -}; - -export const TableOfContents = ({ - title, - disable, - headingSelector, - contentsSelector, - ignoreSelector, - unsafeTocbotOptions, -}: TableOfContentsProps) => { - useEffect(() => { - const configuration = { - tocSelector: '.toc-wrapper', - contentSelector: contentsSelector ?? '.sbdocs-content', - headingSelector: headingSelector ?? 'h3', - ignoreSelector: ignoreSelector ?? '.skip-toc', - headingsOffset: 40, - scrollSmoothOffset: -40, - /** - * Ignore headings that did not - * come from the main markdown code. - */ - // ignoreSelector: ':not(.sbdocs), .hide-from-toc', - orderedList: false, - /** - * Prevent default linking behavior, - * leaving only the smooth scrolling. - */ - onClick: () => false, - ...unsafeTocbotOptions, - }; - - /** - * Wait for the DOM to be ready. - */ - const timeout = setTimeout(() => tocbot.init(configuration), 100); - return () => { - clearTimeout(timeout); - tocbot.destroy(); - }; - }, [disable]); - - return ( - <> - - {!disable ? ( - - -
- - ) : null} - - - ); -}; diff --git a/code/yarn.lock b/code/yarn.lock index 627d6e00186f..4ec2c6d73313 100644 --- a/code/yarn.lock +++ b/code/yarn.lock @@ -5802,7 +5802,6 @@ __metadata: polished: ^4.2.2 react-colorful: ^5.1.2 telejson: ^7.0.3 - tocbot: ^4.20.1 ts-dedent: ^2.0.0 util-deprecate: ^1.0.2 peerDependencies: @@ -29219,13 +29218,6 @@ __metadata: languageName: node linkType: hard -"tocbot@npm:^4.20.1": - version: 4.21.0 - resolution: "tocbot@npm:4.21.0" - checksum: 877d99df40c07ec5e5c2259b820be9c8af9a9f52d582a61b7bed3d43daff820f23031bc613a5cc3bb14ecc34b79c1a45349dcbae8f3a79de7ecc127f366ed3c6 - languageName: node - linkType: hard - "toggle-selection@npm:^1.0.6": version: 1.0.6 resolution: "toggle-selection@npm:1.0.6"