diff --git a/addons/notes/package.json b/addons/notes/package.json index ab4c08978991..36280152197c 100644 --- a/addons/notes/package.json +++ b/addons/notes/package.json @@ -28,6 +28,7 @@ "@storybook/client-logger": "5.1.0-alpha.34", "@storybook/components": "5.1.0-alpha.34", "@storybook/core-events": "5.1.0-alpha.34", + "@storybook/router": "5.1.0-alpha.34", "@storybook/theming": "5.1.0-alpha.34", "core-js": "^2.6.5", "global": "^4.3.2", diff --git a/addons/notes/src/Panel.test.js b/addons/notes/src/Panel.test.js index 3a6cadb2c70c..13ef69d336c9 100644 --- a/addons/notes/src/Panel.test.js +++ b/addons/notes/src/Panel.test.js @@ -1,7 +1,8 @@ import React from 'react'; -import { shallow } from 'enzyme'; +import { shallow, mount } from 'enzyme'; +import { Link } from '@reach/router'; import { SyntaxHighlighter as SyntaxHighlighterBase } from '@storybook/components'; -import { SyntaxHighlighter } from './Panel'; +import { SyntaxHighlighter, NotesLink } from './Panel'; describe('NotesPanel', () => { describe('SyntaxHighlighter component', () => { @@ -20,4 +21,25 @@ describe('NotesPanel', () => { expect(syntaxHighlighterBase.prop('language')).toBe('jsx'); }); }); + + describe('NotesLink component', () => { + it('should render storybook links with @storybook/router Link', () => { + const component = mount( + + Storybook Link + + ); + expect(component.find(Link).prop('to')).toBe('/?path=/story/addon-notes'); + expect(component.find(Link).prop('title')).toBe('title'); + }); + it('should render absolute links as ', () => { + const component = mount( + + Storybook Link + + ); + expect(component.find('a').prop('href')).toBe('https://example.com'); + expect(component.find('a').prop('title')).toBe('title'); + }); + }); }); diff --git a/addons/notes/src/Panel.tsx b/addons/notes/src/Panel.tsx index d48f1d4a8394..401e457c03aa 100644 --- a/addons/notes/src/Panel.tsx +++ b/addons/notes/src/Panel.tsx @@ -1,6 +1,7 @@ import React, { ReactElement, Fragment, ReactNode } from 'react'; import { types } from '@storybook/addons'; import { API, Consumer, Combo } from '@storybook/api'; +import { Link as RouterLink } from '@storybook/router'; import { styled } from '@storybook/theming'; import { @@ -66,11 +67,34 @@ export const SyntaxHighlighter = ({ className, children, ...props }: SyntaxHighl ); }; +interface NotesLinkProps { + href: string; + children: ReactElement; +} +export const NotesLink = ({ href, children, ...props }: NotesLinkProps) => { + /* https://github.com/sindresorhus/is-absolute-url/blob/master/index.js */ + const isAbsoluteUrl = /^[a-z][a-z0-9+.-]*:/.test(href); + if (isAbsoluteUrl) { + return ( + + {children} + + ); + } + + return ( + + {children} + + ); +}; + // use our SyntaxHighlighter component in place of a element when // converting markdown to react elements const defaultOptions = { overrides: { code: SyntaxHighlighter, + a: NotesLink, Giphy: { component: Giphy, }, diff --git a/examples/svelte-kitchen-sink/src/stories/addon-notes.stories.js b/examples/svelte-kitchen-sink/src/stories/addon-notes.stories.js index 43228243f0d8..ec8dcb3da0f8 100644 --- a/examples/svelte-kitchen-sink/src/stories/addon-notes.stories.js +++ b/examples/svelte-kitchen-sink/src/stories/addon-notes.stories.js @@ -8,7 +8,7 @@ storiesOf('Addon|Notes', module) () => ({ Component: ButtonView, }), - { notes: 'My notes on the ButtonView component' } + { notes: 'My notes on the [ButtonView](/story/addon-notes--simple-note) component' } ) .add( 'Note with HTML',