Skip to content

Commit

Permalink
feat(ContentBlockAdapter): Add ability to embed stories
Browse files Browse the repository at this point in the history
This adds the ability to embed a Storybook story within a content block.

This is done through the use of an iframe which is resized automatically using the iframe-resizer-react library.
  • Loading branch information
jpveooys committed Mar 14, 2022
1 parent dec93cd commit 4a390c3
Show file tree
Hide file tree
Showing 8 changed files with 288 additions and 8 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@

MOD.UK Design System documentation site.

## Environment variables

| Name | Required | Default value | Description |
|-------------------------------------|----------|--------------------------------------------------|---------------------------------------------------|
| NEXT_PUBLIC_CONTENTFUL_SPACE_ID | Yes | | Contentful space ID |
| NEXT_PUBLIC_CONTENTFUL_ACCESS_TOKEN | Yes | | Contentful content delivery API token |
| NEXT_PUBLIC_CONTENTFUL_ENVIRONMENT | No | master | Custom Contentful environment to use |
| NEXT_PUBLIC_STORYBOOK_BASE_URL | No | `https://storybook.design-system.digital.mod.uk` | Base URL for Storybook; used for embedded stories |

## End to end tests

Tests are dependent on the application running.
Expand Down
34 changes: 33 additions & 1 deletion components/adapters/Docs/ContentBlockAdapter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,20 @@ import { selectors } from '@defencedigital/design-tokens'
import kebabCase from 'lodash/kebabCase'
import { documentToReactComponents } from '@contentful/rich-text-react-renderer'
import { BLOCKS, INLINES } from '@contentful/rich-text-types'
import IframeResizer from 'iframe-resizer-react'
import { stringify } from 'query-string'

import { MarkdownTable } from '../../presenters/Docs/MarkdownTable'

import { ComponentWithClass } from '../../../common/ComponentWithClass'
import { CodeBlock } from '../../presenters/Framework/CodeBlock'
import { Swatch, SwatchColour } from '../../presenters/Docs/Swatch'
import { StorybookStory } from '../../../graphql'

export const STORYBOOK_BASE_URL = (
process.env.NEXT_PUBLIC_STORYBOOK_BASE_URL ||
'https://storybook.design-system.digital.mod.uk'
).replace(/\/$/, '')

interface ContentBlockAdapterProps extends ComponentWithClass {
fields: Record<string, any>
Expand Down Expand Up @@ -82,6 +91,12 @@ function getEntryMap<T>(links, linkType, entryType = 'block') {
)
}

const StyledIframeResizer = styled(IframeResizer)`
border: none;
width: 100%;
display: block;
`

function getRichTextRenderOptions(links) {
let h2Index = 0

Expand All @@ -105,7 +120,7 @@ function getRichTextRenderOptions(links) {
},
[BLOCKS.EMBEDDED_ENTRY]: (node) => {
const entryBlockMap = getEntryMap<
CodeBlockType | MarkdownTableType | SwatchType
CodeBlockType | MarkdownTableType | SwatchType | StorybookStory
>(links, 'entries')
const entry = entryBlockMap.get(node.data.target.sys.id)

Expand Down Expand Up @@ -139,6 +154,23 @@ function getRichTextRenderOptions(links) {
)
}

if (entry.__typename === 'StorybookStory') {
const story = entry as StorybookStory
const query = {
viewMode: 'story',
id: story.storyId,
args: story.args,
}

return (
<StyledIframeResizer
title={story.title}
height={0}
src={`${STORYBOOK_BASE_URL}/iframe.html?${stringify(query)}`}
/>
)
}

return null
},
[BLOCKS.HEADING_2]: (_: unknown, content: string[]) => {
Expand Down
72 changes: 71 additions & 1 deletion components/adapters/Docs/__tests__/ContentBlockAdapter.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react'
import '@testing-library/jest-dom/extend-expect'
import { render, RenderResult } from '@testing-library/react'

import { ContentBlockAdapter } from '../ContentBlockAdapter'
import { ContentBlockAdapter, STORYBOOK_BASE_URL } from '../ContentBlockAdapter'

describe('Docs/ContentBlockAdapter', () => {
let wrapper: RenderResult
Expand Down Expand Up @@ -385,4 +385,74 @@ describe('Docs/ContentBlockAdapter', () => {
expect(wrapper.getByText('Link')).toHaveAttribute('href', 'https://url')
})
})

describe.each([
{
args: null,
expectedUrlPath:
'/iframe.html?args&id=autocomplete--default&viewMode=story',
},
{
args: 'isDisabled:true',
expectedUrlPath:
'/iframe.html?args=isDisabled%3Atrue&id=autocomplete--default&viewMode=story',
},
])('with an embedded story, args: `$args`', ({ args, expectedUrlPath }) => {
beforeEach(() => {
const fields = {
title: 'Example Title',
description: {
json: {
nodeType: 'document',
data: {},
content: [
{
nodeType: 'embedded-entry-block',
content: [],
data: {
target: {
sys: {
id: '1fzaGVgT83VYAg2xKvNXpU',
type: 'Link',
linkType: 'Entry',
},
},
},
},
],
},
links: {
assets: {
block: [],
hyperlink: [],
},
entries: {
block: [
{
sys: {
id: '1fzaGVgT83VYAg2xKvNXpU',
},
__typename: 'StorybookStory',
storyId: 'autocomplete--default',
args,
title: 'IFrame title',
},
],
inline: [],
},
},
},
image: null,
}

wrapper = render(<ContentBlockAdapter fields={fields} />)
})

it('renders the story', () => {
expect(wrapper.getByTitle('IFrame title')).toHaveAttribute(
'src',
`${STORYBOOK_BASE_URL}${expectedUrlPath}`
)
})
})
})
12 changes: 8 additions & 4 deletions components/layouts/Legacy/partials/StyledContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,16 +48,20 @@ export const StyledContent = styled.div`
color: ${color('neutral', '700')};
}
iframe,
p {
font-size: ${fontSize('m')};
color: ${color('neutral', '500')};
line-height: 1.75;
margin: ${spacing('8')} 0 ${spacing('4')} 0;
max-width: 670px;
${mq({ gte: 'xl' })`
max-width: 740px;
`}
}
p {
font-size: ${fontSize('m')};
color: ${color('neutral', '500')};
line-height: 1.75;
margin: ${spacing('8')} 0 ${spacing('4')} 0;
+ ul {
margin-top: 0;
Expand Down
124 changes: 122 additions & 2 deletions graphql/index.ts

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions graphql/queries/PageByPath.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,11 @@ query PageByPath($path: String!) {
... on CodeBlock {
sourceCode
}
... on StorybookStory {
storyId
args
title
}
}
inline {
sys {
Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
"next": "^12.1.0",
"prism-react-renderer": "^1.2.0",
"prismjs": "^1.27.0",
"query-string": "^7.1.1",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-responsive": "^9.0.0-beta.6",
Expand Down Expand Up @@ -90,6 +91,7 @@
"eslint-junit": "^1.0.1",
"eslint-plugin-jest": "^25.3.0",
"eslint-plugin-prettier": "^4.0.0",
"iframe-resizer-react": "^1.1.0",
"jest": "^27.4.5",
"jest-canvas-mock": "^2.3.1",
"jest-environment-jsdom": "^27.3.0",
Expand Down
38 changes: 38 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8780,6 +8780,11 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"

filter-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/filter-obj/-/filter-obj-1.1.0.tgz#9b311112bc6c6127a16e016c6c5d7f19e0805c5b"
integrity sha1-mzERErxsYSehbgFsbF1/GeCAXFs=

finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
Expand Down Expand Up @@ -9945,6 +9950,19 @@ iferr@^0.1.5:
resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=

iframe-resizer-react@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/iframe-resizer-react/-/iframe-resizer-react-1.1.0.tgz#5009e019b7a5c7f1c009bff5bcdf0dbf33557465"
integrity sha512-FrytSq91AIJaDgE+6uK/Vdd6IR8CrwLoZ6eGmL2qQMPTzF0xlSV2jaSzRRUh5V2fttD7vzl21jvBl97bV40eBw==
dependencies:
iframe-resizer "^4.3.0"
warning "^4.0.3"

iframe-resizer@^4.3.0:
version "4.3.2"
resolved "https://registry.yarnpkg.com/iframe-resizer/-/iframe-resizer-4.3.2.tgz#42dd88345d18b9e377b6044dddb98c664ab0ce6b"
integrity sha512-gOWo2hmdPjMQsQ+zTKbses08mDfDEMh4NneGQNP4qwePYujY1lguqP6gnbeJkf154gojWlBhIltlgnMfYjGHWA==

ignore-walk@^3.0.3:
version "3.0.4"
resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.4.tgz#c9a09f69b7c7b479a5d74ac1a3c0d4236d2a6335"
Expand Down Expand Up @@ -14519,6 +14537,16 @@ qs@~6.5.2:
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==

query-string@^7.1.1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/query-string/-/query-string-7.1.1.tgz#754620669db978625a90f635f12617c271a088e1"
integrity sha512-MplouLRDHBZSG9z7fpuAAcI7aAYjDLhtsiVZsevsfaHWDS2IDdORKbSd1kWUA+V4zyva/HZoSfpwnYMMQDhb0w==
dependencies:
decode-uri-component "^0.2.0"
filter-obj "^1.1.0"
split-on-first "^1.0.0"
strict-uri-encode "^2.0.0"

querystring-es3@^0.2.0:
version "0.2.1"
resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
Expand Down Expand Up @@ -15992,6 +16020,11 @@ spdx-license-ids@^3.0.0:
resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz#50c0d8c40a14ec1bf449bae69a0ea4685a9d9f95"
integrity sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==

split-on-first@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/split-on-first/-/split-on-first-1.1.0.tgz#f610afeee3b12bce1d0c30425e76398b78249a5f"
integrity sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==

split-string@^3.0.2:
version "3.1.0"
resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
Expand Down Expand Up @@ -16139,6 +16172,11 @@ stream-shift@^1.0.0:
resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.1.tgz#d7088281559ab2778424279b0877da3c392d5a3d"
integrity sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==

strict-uri-encode@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz#b9c7330c7042862f6b142dc274bbcc5866ce3546"
integrity sha1-ucczDHBChi9rFC3CdLvMWGbONUY=

string-env-interpolation@1.0.1, string-env-interpolation@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/string-env-interpolation/-/string-env-interpolation-1.0.1.tgz#ad4397ae4ac53fe6c91d1402ad6f6a52862c7152"
Expand Down

0 comments on commit 4a390c3

Please sign in to comment.