@graphcommerce/graphcms-ui 2.106.39 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +80 -87
- package/components/Asset/Asset.graphql +7 -0
- package/components/Asset/index.tsx +34 -0
- package/components/RichText/RichText.tsx +117 -0
- package/components/RichText/defaultRenderers.tsx +42 -0
- package/components/RichText/defaultSxRenderer.ts +103 -0
- package/{RichText → components/RichText}/getNodeLength.tsx +3 -2
- package/components/RichText/index.ts +2 -0
- package/components/RichText/types.ts +92 -0
- package/index.ts +2 -1
- package/package.json +12 -18
- package/RichText/RichTextColumns.tsx +0 -22
- package/RichText/RichTextDoubleSpread.tsx +0 -18
- package/RichText/RichTextHeadingStrongStroked.tsx +0 -22
- package/RichText/RichTextHero.tsx +0 -27
- package/RichText/RichTextParagraphStrongStroked.tsx +0 -23
- package/RichText/RichTextQuote.tsx +0 -21
- package/RichText/RichTextSpread.tsx +0 -14
- package/RichText/index.tsx +0 -325
- package/RichText/useRichTextStyles.tsx +0 -118
package/CHANGELOG.md
CHANGED
|
@@ -1,158 +1,151 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
3
|
+
## 3.0.0
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
### Major Changes
|
|
7
6
|
|
|
7
|
+
- [#1258](https://github.com/ho-nl/m2-pwa/pull/1258)
|
|
8
|
+
[`ad36382a4`](https://github.com/ho-nl/m2-pwa/commit/ad36382a4d55d83d9e47b7eb6a02671a2a631a05)
|
|
9
|
+
Thanks [@paales](https://github.com/paales)! - Upgraded to Material UI 5
|
|
8
10
|
|
|
9
|
-
###
|
|
11
|
+
### Patch Changes
|
|
10
12
|
|
|
11
|
-
|
|
13
|
+
- Updated dependencies
|
|
14
|
+
[[`ad36382a4`](https://github.com/ho-nl/m2-pwa/commit/ad36382a4d55d83d9e47b7eb6a02671a2a631a05)]:
|
|
15
|
+
- @graphcommerce/graphql@3.0.0
|
|
16
|
+
- @graphcommerce/image@3.0.0
|
|
17
|
+
- @graphcommerce/next-ui@4.0.0
|
|
12
18
|
|
|
19
|
+
All notable changes to this project will be documented in this file. See
|
|
20
|
+
[Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
13
21
|
|
|
22
|
+
## [2.106.12](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.106.11...@graphcommerce/graphcms-ui@2.106.12) (2021-12-17)
|
|
14
23
|
|
|
24
|
+
### Bug Fixes
|
|
15
25
|
|
|
26
|
+
- make sure we're able to render table_header_cell and do not throw when rendering unknown elements
|
|
27
|
+
in production
|
|
28
|
+
([f7b7972](https://github.com/ho-nl/m2-pwa/commit/f7b797272f5765801c3f2e217fa9905f65dbe6d6))
|
|
16
29
|
|
|
17
30
|
# [2.106.0](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.105.4...@graphcommerce/graphcms-ui@2.106.0) (2021-12-01)
|
|
18
31
|
|
|
19
|
-
|
|
20
32
|
### Bug Fixes
|
|
21
33
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
34
|
+
- build ([72d9353](https://github.com/ho-nl/m2-pwa/commit/72d935376a1967cc976c20b984ef15a862e5d0f4))
|
|
35
|
+
- fontWeights
|
|
36
|
+
([7172527](https://github.com/ho-nl/m2-pwa/commit/71725272fe9f0b854d918ae357a668f641bfe8e5))
|
|
37
|
+
- hero text spacing
|
|
38
|
+
([79dd6aa](https://github.com/ho-nl/m2-pwa/commit/79dd6aa2fe576104ebbbdd092f6b415d319dec48))
|
|
39
|
+
- render bug stroke variable fonts
|
|
40
|
+
([582de18](https://github.com/ho-nl/m2-pwa/commit/582de187800ee9c53718bf43a39ca77398d21b91)),
|
|
41
|
+
closes
|
|
42
|
+
[/github.com/rsms/inter/issues/292#issuecomment-674993644](https://github.com//github.com/rsms/inter/issues/292/issues/issuecomment-674993644)
|
|
27
43
|
|
|
28
44
|
### Features
|
|
29
45
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
46
|
+
- breakpointVal
|
|
47
|
+
([0294503](https://github.com/ho-nl/m2-pwa/commit/029450343051cf6995babad9f9b42c7e6ad1094e))
|
|
48
|
+
- responsiveTyp
|
|
49
|
+
([6108b61](https://github.com/ho-nl/m2-pwa/commit/6108b6148e76ddbbe2db1614f10aaf88423db5ca))
|
|
36
50
|
|
|
37
51
|
# [2.105.0](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.104.29...@graphcommerce/graphcms-ui@2.105.0) (2021-11-12)
|
|
38
52
|
|
|
39
|
-
|
|
40
53
|
### Features
|
|
41
54
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
55
|
+
- added tons of translations
|
|
56
|
+
([9bb0ac7](https://github.com/ho-nl/m2-pwa/commit/9bb0ac709b58df6ea6141e92e4923a5ca9ae2963))
|
|
47
57
|
|
|
48
58
|
## [2.104.29](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.104.28...@graphcommerce/graphcms-ui@2.104.29) (2021-11-12)
|
|
49
59
|
|
|
50
|
-
|
|
51
60
|
### Bug Fixes
|
|
52
61
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
- must have smaller sizes for mobile
|
|
63
|
+
([34cf81e](https://github.com/ho-nl/m2-pwa/commit/34cf81eed6c5996f70be8b2c10888e44fad4d57f))
|
|
58
64
|
|
|
59
65
|
## [2.104.18](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.104.17...@graphcommerce/graphcms-ui@2.104.18) (2021-11-04)
|
|
60
66
|
|
|
61
|
-
|
|
62
67
|
### Bug Fixes
|
|
63
68
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
+
- remove hardcoded fontSize
|
|
70
|
+
([e4e09e1](https://github.com/ho-nl/m2-pwa/commit/e4e09e11baeb8edeff634550b8cdb88571d96911))
|
|
69
71
|
|
|
70
72
|
## [2.104.16](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.104.15...@graphcommerce/graphcms-ui@2.104.16) (2021-11-03)
|
|
71
73
|
|
|
72
|
-
|
|
73
74
|
### Bug Fixes
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
- various accessibility improvements
|
|
77
|
+
([47481a9](https://github.com/ho-nl/m2-pwa/commit/47481a9a882ba87968de6dd797557b0b275d75fb))
|
|
80
78
|
|
|
81
79
|
## [2.104.9](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.104.8...@graphcommerce/graphcms-ui@2.104.9) (2021-11-02)
|
|
82
80
|
|
|
83
|
-
|
|
84
81
|
### Bug Fixes
|
|
85
82
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
83
|
+
- color from palette
|
|
84
|
+
([283cca1](https://github.com/ho-nl/m2-pwa/commit/283cca169ec00cbac8b973e14e6b77a443e26c99))
|
|
85
|
+
- darkMode
|
|
86
|
+
([c7573de](https://github.com/ho-nl/m2-pwa/commit/c7573de6bb80643b26931c35ac61735539e7fbf0))
|
|
92
87
|
|
|
93
88
|
## [2.104.3](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.104.2...@graphcommerce/graphcms-ui@2.104.3) (2021-10-28)
|
|
94
89
|
|
|
95
|
-
|
|
96
90
|
### Bug Fixes
|
|
97
91
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
92
|
+
- default heading margins for CMS content
|
|
93
|
+
([ac7c24f](https://github.com/ho-nl/m2-pwa/commit/ac7c24f731abf9573ad93d534d84b9f7c1b16a2b))
|
|
103
94
|
|
|
104
95
|
# [2.104.0](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.103.30...@graphcommerce/graphcms-ui@2.104.0) (2021-10-27)
|
|
105
96
|
|
|
106
|
-
|
|
107
97
|
### Features
|
|
108
98
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
99
|
+
- **nextjs:** upgraded to nextjs 12
|
|
100
|
+
([9331bc8](https://github.com/ho-nl/m2-pwa/commit/9331bc801f6419522115cc47d291d49d608d5a90))
|
|
114
101
|
|
|
115
102
|
## [2.103.1](https://github.com/ho-nl/m2-pwa/compare/@graphcommerce/graphcms-ui@2.103.0...@graphcommerce/graphcms-ui@2.103.1) (2021-09-27)
|
|
116
103
|
|
|
117
104
|
**Note:** Version bump only for package @graphcommerce/graphcms-ui
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
106
|
# 2.103.0 (2021-09-27)
|
|
124
107
|
|
|
125
|
-
|
|
126
108
|
### Bug Fixes
|
|
127
109
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
110
|
+
- ignore md files from triggering version updates
|
|
111
|
+
([4f98392](https://github.com/ho-nl/m2-pwa/commit/4f9839250b3a32d3070da5290e5efcc5e2243fba))
|
|
112
|
+
- implement next-ui barrel imports
|
|
113
|
+
([75bea70](https://github.com/ho-nl/m2-pwa/commit/75bea703dba898f18a2a1dfa3243ebd0a4e6f0e1))
|
|
114
|
+
- narrow quote on mobile
|
|
115
|
+
([e06ccc2](https://github.com/ho-nl/m2-pwa/commit/e06ccc25048124431dcdb786f1719f688a5e429c))
|
|
116
|
+
- remove conflicting files
|
|
117
|
+
([0c17ae4](https://github.com/ho-nl/m2-pwa/commit/0c17ae46be62b775ac83b35f11c532ce2d9401a3))
|
|
118
|
+
- since all links are of next/link we need to add passHref for custom components
|
|
119
|
+
([16fb931](https://github.com/ho-nl/m2-pwa/commit/16fb93100d367203ea79bb4f93357221253f2ecd))
|
|
134
120
|
|
|
135
121
|
### Features
|
|
136
122
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
123
|
+
- created stacked-pages package
|
|
124
|
+
([d86008e](https://github.com/ho-nl/m2-pwa/commit/d86008ee659ccb25b194a41d624b394a1ddbd088))
|
|
125
|
+
- **image:** introduced completely rewritten Image component
|
|
126
|
+
([e3413b3](https://github.com/ho-nl/m2-pwa/commit/e3413b3a57392d6571ea64cb8d9c8dca05ea31df))
|
|
127
|
+
- implemented the ability to load graphcms content by URL
|
|
128
|
+
([99bc970](https://github.com/ho-nl/m2-pwa/commit/99bc970fc46d40b7efa99a71819529aeaa206bb4))
|
|
129
|
+
- introduced graphcms-ui package to quickly build pages
|
|
130
|
+
([04d89c3](https://github.com/ho-nl/m2-pwa/commit/04d89c3fecf25f64923caf437eeb4b73f8887102))
|
|
131
|
+
- introduces framer-next-pages and framer-sheet to next-ui and soxbase package
|
|
132
|
+
([e04ad8a](https://github.com/ho-nl/m2-pwa/commit/e04ad8a94cd1fd5a7c5575c9db7916b6e8a88f16))
|
|
133
|
+
- next.js 11
|
|
134
|
+
([7d61407](https://github.com/ho-nl/m2-pwa/commit/7d614075a778f488045034f74be4f75b93f63c43))
|
|
135
|
+
- **playwright:** added new playwright package to enable browser testing
|
|
136
|
+
([6f49ec7](https://github.com/ho-nl/m2-pwa/commit/6f49ec7595563775b96ebf21c27e39da1282e8d9))
|
|
137
|
+
- renamed all packages to use [@graphcommerce](https://github.com/graphcommerce) instead of
|
|
138
|
+
[@reachdigital](https://github.com/reachdigital)
|
|
139
|
+
([491e4ce](https://github.com/ho-nl/m2-pwa/commit/491e4cec9a2686472dac36b79f999257c0811ffe))
|
|
140
|
+
- upgrade to node 14
|
|
141
|
+
([d079a75](https://github.com/ho-nl/m2-pwa/commit/d079a751e9bfd8dc7f5009d2c9f31c336a0c96ab))
|
|
142
|
+
- upgraded to nextjs 11
|
|
143
|
+
([0053beb](https://github.com/ho-nl/m2-pwa/commit/0053beb7ef597c190add7264256a0eaec35868da))
|
|
148
144
|
|
|
149
145
|
### Reverts
|
|
150
146
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
147
|
+
- Revert "chore: upgrade @apollo/client"
|
|
148
|
+
([55ff24e](https://github.com/ho-nl/m2-pwa/commit/55ff24ede0e56c85b8095edadadd1ec5e0b1b8d2))
|
|
156
149
|
|
|
157
150
|
# Change Log
|
|
158
151
|
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { removeNull } from '@graphcommerce/graphql'
|
|
2
|
+
import { Image, ImageProps } from '@graphcommerce/image'
|
|
3
|
+
import { AssetFragment } from './Asset.gql'
|
|
4
|
+
|
|
5
|
+
export type { AssetFragment } from './Asset.gql'
|
|
6
|
+
|
|
7
|
+
type ImageAsset = Omit<AssetFragment, 'width' | 'height'> & {
|
|
8
|
+
width: number
|
|
9
|
+
height: number
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function isImage(asset: AssetFragment): asset is ImageAsset {
|
|
13
|
+
return !!(asset.width && asset.height)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
type AssetProps = {
|
|
17
|
+
asset: AssetFragment
|
|
18
|
+
} & Omit<ImageProps, 'src' | 'width' | 'height' | 'alt'>
|
|
19
|
+
|
|
20
|
+
export function Asset(props: AssetProps) {
|
|
21
|
+
const { asset, ...imgProps } = props
|
|
22
|
+
|
|
23
|
+
if (isImage(asset)) {
|
|
24
|
+
const { url, height, mimeType, size, width, ...assetProps } = removeNull(asset)
|
|
25
|
+
return <Image src={url} height={height} width={width} {...imgProps} {...assetProps} />
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (asset.mimeType === 'video/mp4') {
|
|
29
|
+
return <video src={asset.url} autoPlay muted loop playsInline disableRemotePlayback />
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (process.env.NODE_ENV !== 'production') return <div>{asset.mimeType} not supported</div>
|
|
33
|
+
return null
|
|
34
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { SxProps, Theme } from '@mui/material'
|
|
2
|
+
import { defaultRenderers } from './defaultRenderers'
|
|
3
|
+
import { defaultSxRenderer } from './defaultSxRenderer'
|
|
4
|
+
import {
|
|
5
|
+
AdditionalProps,
|
|
6
|
+
Renderers,
|
|
7
|
+
SxRenderer,
|
|
8
|
+
TextNode,
|
|
9
|
+
ElementOrTextNode,
|
|
10
|
+
ElementNode,
|
|
11
|
+
} from './types'
|
|
12
|
+
|
|
13
|
+
const RenderText = ({ classes, text, ...textProps }: TextNode) => {
|
|
14
|
+
let result = <>{text}</>
|
|
15
|
+
if (textProps.bold) result = <strong>{result}</strong>
|
|
16
|
+
if (textProps.italic) result = <em>{result}</em>
|
|
17
|
+
if (textProps.underlined) result = <em>{result}</em>
|
|
18
|
+
|
|
19
|
+
return result
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function isTextNode(node: ElementOrTextNode): node is TextNode {
|
|
23
|
+
return (node as TextNode).text !== undefined
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function isElementNode(node: ElementOrTextNode): node is ElementNode {
|
|
27
|
+
return (node as ElementNode).children !== undefined
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function RenderNode(node: ElementOrTextNode & AdditionalProps) {
|
|
31
|
+
if (isTextNode(node)) {
|
|
32
|
+
return <RenderText {...node} />
|
|
33
|
+
}
|
|
34
|
+
if (isElementNode(node)) {
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
36
|
+
return <RenderElement {...node} />
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
40
|
+
console.error(node)
|
|
41
|
+
throw Error(`RichText: Node not recognized`)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return null
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function RenderChildren({
|
|
48
|
+
childNodes,
|
|
49
|
+
...props
|
|
50
|
+
}: { childNodes: ElementNode['children'] } & AdditionalProps) {
|
|
51
|
+
return (
|
|
52
|
+
<>
|
|
53
|
+
{childNodes.map((node, key) => (
|
|
54
|
+
// Since we don't know any unique identifiers of the element and since this doesn't rerender often this is fine.
|
|
55
|
+
// eslint-disable-next-line react/no-array-index-key
|
|
56
|
+
<RenderNode {...node} {...props} key={key} />
|
|
57
|
+
))}
|
|
58
|
+
</>
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function RenderElement(element: ElementNode & AdditionalProps) {
|
|
63
|
+
const { type, children, sxRenderer, renderers, ...props } = element
|
|
64
|
+
|
|
65
|
+
// todo: this has the any type, could be improved
|
|
66
|
+
const Component = renderers[type]
|
|
67
|
+
const sx = sxRenderer?.[type] ?? []
|
|
68
|
+
|
|
69
|
+
if (Component) {
|
|
70
|
+
return (
|
|
71
|
+
<Component {...props} sx={[sxRenderer.all, ...(Array.isArray(sx) ? sx : [sx])]}>
|
|
72
|
+
<RenderChildren childNodes={children} sxRenderer={sxRenderer} renderers={renderers} />
|
|
73
|
+
</Component>
|
|
74
|
+
)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
78
|
+
console.error(element)
|
|
79
|
+
throw Error(`RichText: Unknown Element: ${element.type}`)
|
|
80
|
+
}
|
|
81
|
+
return <RenderChildren childNodes={children} sxRenderer={sxRenderer} renderers={renderers} />
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export type RichTextProps = { raw: ElementNode } & {
|
|
85
|
+
renderers?: Partial<Renderers>
|
|
86
|
+
sxRenderer?: SxRenderer
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function mergeSxRenderer(base: SxRenderer, sxRenderer?: SxRenderer) {
|
|
90
|
+
if (!sxRenderer) return base
|
|
91
|
+
|
|
92
|
+
return Object.fromEntries(
|
|
93
|
+
Object.entries<SxProps<Theme>>(base).map(([key, sx]) => {
|
|
94
|
+
const sxOverride: SxProps<Theme> = sxRenderer?.[key]
|
|
95
|
+
|
|
96
|
+
return sxOverride
|
|
97
|
+
? [
|
|
98
|
+
key,
|
|
99
|
+
[
|
|
100
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
101
|
+
...(Array.isArray(sxOverride) ? sxOverride : [sxOverride]),
|
|
102
|
+
],
|
|
103
|
+
]
|
|
104
|
+
: [key, sx]
|
|
105
|
+
}),
|
|
106
|
+
) as SxRenderer
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export function RichText({ raw, sxRenderer, renderers }: RichTextProps) {
|
|
110
|
+
return (
|
|
111
|
+
<RenderChildren
|
|
112
|
+
childNodes={raw.children}
|
|
113
|
+
sxRenderer={mergeSxRenderer(defaultSxRenderer, sxRenderer)}
|
|
114
|
+
renderers={{ ...defaultRenderers, ...renderers }}
|
|
115
|
+
/>
|
|
116
|
+
)
|
|
117
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Box, Typography, Link } from '@mui/material'
|
|
2
|
+
import PageLink from 'next/link'
|
|
3
|
+
import { Asset } from '../Asset'
|
|
4
|
+
import { Renderers } from './types'
|
|
5
|
+
|
|
6
|
+
export const defaultRenderers: Renderers = {
|
|
7
|
+
'heading-one': (props) => <Typography variant='h1' {...props} />,
|
|
8
|
+
'heading-two': (props) => <Typography variant='h2' {...props} />,
|
|
9
|
+
'heading-three': (props) => <Typography variant='h3' {...props} />,
|
|
10
|
+
'heading-four': (props) => <Typography variant='h4' {...props} />,
|
|
11
|
+
'heading-five': (props) => <Typography variant='h5' {...props} />,
|
|
12
|
+
'heading-six': (props) => <Typography variant='h6' {...props} />,
|
|
13
|
+
paragraph: (props) => <Typography variant='body1' gutterBottom {...props} />,
|
|
14
|
+
'bulleted-list': (props) => <Box component='ul' {...props} />,
|
|
15
|
+
'numbered-list': (props) => <Box component='ol' {...props} />,
|
|
16
|
+
'list-item': (props) => <Box component='li' {...props} />,
|
|
17
|
+
'list-item-child': (props) => <Box component='span' {...props} />,
|
|
18
|
+
'block-quote': (props) => <Box component='blockquote' {...props} />,
|
|
19
|
+
iframe: (props) => (
|
|
20
|
+
// todo add security attributes to iframe
|
|
21
|
+
// todo make iframe responsive (generic IFrame component?)
|
|
22
|
+
<Box component='iframe' title='embedded content' loading='lazy' {...props} />
|
|
23
|
+
),
|
|
24
|
+
image: ({ src, width, height, title, mimeType }) => (
|
|
25
|
+
<Asset asset={{ url: src, alt: title, width, height, mimeType }} />
|
|
26
|
+
),
|
|
27
|
+
video: ({ src, width, height, title, mimeType }) => (
|
|
28
|
+
<Asset asset={{ url: src, alt: title, width, height, mimeType }} />
|
|
29
|
+
),
|
|
30
|
+
link: ({ href, ...props }) => (
|
|
31
|
+
<PageLink href={href} passHref>
|
|
32
|
+
<Link underline='hover' {...props} />
|
|
33
|
+
</PageLink>
|
|
34
|
+
),
|
|
35
|
+
table: (props) => <Box component='table' {...props} />,
|
|
36
|
+
table_head: (props) => <Box component='thead' {...props} />,
|
|
37
|
+
table_header_cell: (props) => <Box component='th' {...props} />,
|
|
38
|
+
table_body: (props) => <Box component='tbody' {...props} />,
|
|
39
|
+
table_row: (props) => <Box component='tr' {...props} />,
|
|
40
|
+
table_cell: (props) => <Box component='td' {...props} />,
|
|
41
|
+
code: (props) => <Box component='code' {...props} />,
|
|
42
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { SxRenderer } from './types'
|
|
2
|
+
|
|
3
|
+
export const defaultSxRenderer: SxRenderer = {
|
|
4
|
+
all: {
|
|
5
|
+
'&:empty': {
|
|
6
|
+
display: 'none',
|
|
7
|
+
},
|
|
8
|
+
'&:last-of-type': { marginBottom: 0 },
|
|
9
|
+
},
|
|
10
|
+
paragraph: {
|
|
11
|
+
marginBottom: '1em',
|
|
12
|
+
wordBreak: 'break-word',
|
|
13
|
+
},
|
|
14
|
+
'heading-one': {
|
|
15
|
+
marginTop: '0.5em',
|
|
16
|
+
marginBottom: '0.5em',
|
|
17
|
+
},
|
|
18
|
+
'heading-two': {
|
|
19
|
+
marginTop: '0.5em',
|
|
20
|
+
marginBottom: '0.5em',
|
|
21
|
+
'&:first-of-type': { marginTop: 0 },
|
|
22
|
+
},
|
|
23
|
+
'heading-three': {
|
|
24
|
+
marginTop: '0.5em',
|
|
25
|
+
marginBottom: '0.5em',
|
|
26
|
+
'&:first-of-type': { marginTop: 0 },
|
|
27
|
+
},
|
|
28
|
+
'heading-four': {
|
|
29
|
+
marginTop: '0.5em',
|
|
30
|
+
marginBottom: '0.5em',
|
|
31
|
+
'&:first-of-type': { marginTop: 0 },
|
|
32
|
+
},
|
|
33
|
+
'heading-five': {
|
|
34
|
+
marginTop: '0.5em',
|
|
35
|
+
marginBottom: '0.5em',
|
|
36
|
+
'&:first-of-type': { marginTop: 0 },
|
|
37
|
+
},
|
|
38
|
+
image: {
|
|
39
|
+
width: '100%',
|
|
40
|
+
height: 'auto',
|
|
41
|
+
},
|
|
42
|
+
video: {
|
|
43
|
+
width: '100%',
|
|
44
|
+
height: 'auto',
|
|
45
|
+
},
|
|
46
|
+
'block-quote': (theme) => ({
|
|
47
|
+
paddingLeft: theme.spacings.sm,
|
|
48
|
+
margin: `${theme.spacings.md} 0`,
|
|
49
|
+
}),
|
|
50
|
+
'bulleted-list': {
|
|
51
|
+
marginBottom: '1em',
|
|
52
|
+
},
|
|
53
|
+
'numbered-list': {
|
|
54
|
+
marginBottom: '1em',
|
|
55
|
+
},
|
|
56
|
+
code: {
|
|
57
|
+
width: 'fit-content',
|
|
58
|
+
maxWidth: '100%',
|
|
59
|
+
padding: 5,
|
|
60
|
+
overflow: 'scroll',
|
|
61
|
+
},
|
|
62
|
+
table: (theme) => ({
|
|
63
|
+
display: 'table',
|
|
64
|
+
width: '100%',
|
|
65
|
+
borderSpacing: '2px',
|
|
66
|
+
borderCollapse: 'collapse',
|
|
67
|
+
marginTop: theme.spacings.md,
|
|
68
|
+
marginBottom: theme.spacings.sm,
|
|
69
|
+
'& thead, tbody': {
|
|
70
|
+
'& td': {
|
|
71
|
+
padding: '10px 20px',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
'& thead': {
|
|
75
|
+
'& tr': {
|
|
76
|
+
'& td': {
|
|
77
|
+
'& p': {
|
|
78
|
+
fontWeight: theme.typography.fontWeightBold,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
'& tbody': {
|
|
84
|
+
display: 'table-row-group',
|
|
85
|
+
verticalAlign: 'center',
|
|
86
|
+
borderColor: 'inherit',
|
|
87
|
+
'& tr': {
|
|
88
|
+
'&:nth-of-type(odd)': {
|
|
89
|
+
background: theme.palette.background.paper,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
'& td': {
|
|
93
|
+
[theme.breakpoints.up('sm')]: {
|
|
94
|
+
minWidth: '150px',
|
|
95
|
+
},
|
|
96
|
+
'& p': {},
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
}),
|
|
100
|
+
link: {
|
|
101
|
+
wordBreak: 'break-word',
|
|
102
|
+
},
|
|
103
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { isElementNode, isTextNode
|
|
1
|
+
import { isElementNode, isTextNode } from './RichText'
|
|
2
|
+
import { ElementOrTextNode } from './types'
|
|
2
3
|
|
|
3
|
-
export
|
|
4
|
+
export function getNodeLength(node: ElementOrTextNode): number {
|
|
4
5
|
if (isElementNode(node))
|
|
5
6
|
return node.children.map(getNodeLength).reduce<number>((prev, curr) => prev + curr, 0)
|
|
6
7
|
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { SxProps, Theme } from '@mui/material'
|
|
2
|
+
import { LiteralUnion } from 'type-fest'
|
|
3
|
+
|
|
4
|
+
type BaseElementTypes =
|
|
5
|
+
| 'heading-one'
|
|
6
|
+
| 'heading-two'
|
|
7
|
+
| 'heading-three'
|
|
8
|
+
| 'heading-four'
|
|
9
|
+
| 'heading-five'
|
|
10
|
+
| 'heading-six'
|
|
11
|
+
| 'paragraph'
|
|
12
|
+
| 'numbered-list'
|
|
13
|
+
| 'bulleted-list'
|
|
14
|
+
| 'block-quote'
|
|
15
|
+
| 'paragraph'
|
|
16
|
+
| 'list-item'
|
|
17
|
+
| 'list-item-child'
|
|
18
|
+
| 'table'
|
|
19
|
+
| 'table_head'
|
|
20
|
+
| 'table_header_cell'
|
|
21
|
+
| 'table_body'
|
|
22
|
+
| 'table_row'
|
|
23
|
+
| 'table_cell'
|
|
24
|
+
| 'code'
|
|
25
|
+
|
|
26
|
+
type SimpleElement = {
|
|
27
|
+
children: ElementOrTextNode[]
|
|
28
|
+
type: LiteralUnion<BaseElementTypes, string>
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export type TextNode = {
|
|
32
|
+
text: string
|
|
33
|
+
bold?: true
|
|
34
|
+
italic?: true
|
|
35
|
+
underlined?: true
|
|
36
|
+
[key: string]: unknown
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
type LinkElement = {
|
|
40
|
+
type: 'link'
|
|
41
|
+
children: ElementOrTextNode[]
|
|
42
|
+
href: string
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
type ImageElement = {
|
|
46
|
+
type: 'image'
|
|
47
|
+
children: ElementOrTextNode[]
|
|
48
|
+
src: string
|
|
49
|
+
title: string
|
|
50
|
+
width: number
|
|
51
|
+
height: number
|
|
52
|
+
mimeType: string
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
type VideoElement = {
|
|
56
|
+
type: 'image'
|
|
57
|
+
children: ElementOrTextNode[]
|
|
58
|
+
src: string
|
|
59
|
+
title: string
|
|
60
|
+
width: number
|
|
61
|
+
height: number
|
|
62
|
+
mimeType: string
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type IframeElement = {
|
|
66
|
+
type: 'iframe'
|
|
67
|
+
children: ElementOrTextNode[]
|
|
68
|
+
src: string
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export type ElementNode = SimpleElement | LinkElement | ImageElement | VideoElement | IframeElement
|
|
72
|
+
export type ElementOrTextNode = ElementNode | TextNode
|
|
73
|
+
|
|
74
|
+
type RendererBase = { sx?: SxProps<Theme>; children?: React.ReactNode }
|
|
75
|
+
type Renderer<P extends ElementNode> = (
|
|
76
|
+
props: Omit<P, 'children'> & RendererBase,
|
|
77
|
+
) => React.ReactElement | null
|
|
78
|
+
|
|
79
|
+
export type Renderers = {
|
|
80
|
+
[k in BaseElementTypes]: Renderer<SimpleElement>
|
|
81
|
+
} & {
|
|
82
|
+
link: Renderer<LinkElement>
|
|
83
|
+
image: Renderer<ImageElement>
|
|
84
|
+
video: Renderer<VideoElement>
|
|
85
|
+
iframe: Renderer<IframeElement>
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export type SxRenderer = {
|
|
89
|
+
[k in keyof Renderers | 'all']?: SxProps<Theme>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export type AdditionalProps = { renderers: Renderers; sxRenderer: SxRenderer }
|
package/index.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
export
|
|
1
|
+
export * from './components/RichText'
|
|
2
|
+
export * from './components/Asset'
|
package/package.json
CHANGED
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@graphcommerce/graphcms-ui",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"sideEffects": false,
|
|
5
5
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
6
|
-
"browserslist": [
|
|
7
|
-
"extends @graphcommerce/browserslist-config-pwa"
|
|
8
|
-
],
|
|
9
6
|
"eslintConfig": {
|
|
10
7
|
"extends": "@graphcommerce/eslint-config-pwa",
|
|
11
8
|
"parserOptions": {
|
|
@@ -13,22 +10,19 @@
|
|
|
13
10
|
}
|
|
14
11
|
},
|
|
15
12
|
"devDependencies": {
|
|
16
|
-
"@graphcommerce/
|
|
17
|
-
"@graphcommerce/
|
|
18
|
-
"@graphcommerce/
|
|
19
|
-
"@
|
|
20
|
-
"@playwright/test": "^1.17.1"
|
|
13
|
+
"@graphcommerce/eslint-config-pwa": "^4.0.0",
|
|
14
|
+
"@graphcommerce/prettier-config-pwa": "^4.0.0",
|
|
15
|
+
"@graphcommerce/typescript-config-pwa": "^4.0.0",
|
|
16
|
+
"@playwright/test": "^1.18.1"
|
|
21
17
|
},
|
|
22
18
|
"dependencies": {
|
|
23
|
-
"@
|
|
24
|
-
"@graphcommerce/image": "^
|
|
25
|
-
"@graphcommerce/next-ui": "^
|
|
26
|
-
"@material
|
|
27
|
-
"
|
|
28
|
-
"next": "^12.0.7",
|
|
19
|
+
"@graphcommerce/graphql": "^3.0.0",
|
|
20
|
+
"@graphcommerce/image": "^3.0.0",
|
|
21
|
+
"@graphcommerce/next-ui": "^4.0.0",
|
|
22
|
+
"@mui/material": "^5.4.1",
|
|
23
|
+
"next": "^12.0.10",
|
|
29
24
|
"react": "^17.0.2",
|
|
30
25
|
"react-dom": "^17.0.2",
|
|
31
|
-
"type-fest": "^2.
|
|
32
|
-
}
|
|
33
|
-
"gitHead": "41e42c8cd6f565ab0cbba81a1954a0041dc46768"
|
|
26
|
+
"type-fest": "^2.11.2"
|
|
27
|
+
}
|
|
34
28
|
}
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { UseStyles } from '@graphcommerce/next-ui'
|
|
2
|
-
import { makeStyles, Theme } from '@material-ui/core'
|
|
3
|
-
import React from 'react'
|
|
4
|
-
import RichText, { RichTextProps } from '.'
|
|
5
|
-
|
|
6
|
-
type StyleProps = { columnCount: number }
|
|
7
|
-
|
|
8
|
-
const useStyles = makeStyles(({ spacings, breakpoints }: Theme) => ({
|
|
9
|
-
paragraph: {
|
|
10
|
-
[breakpoints.up('md')]: {
|
|
11
|
-
columnCount: ({ columnCount }: StyleProps) => columnCount,
|
|
12
|
-
columnGap: spacings.md,
|
|
13
|
-
},
|
|
14
|
-
},
|
|
15
|
-
}))
|
|
16
|
-
|
|
17
|
-
type RichTextColumnsProps = UseStyles<typeof useStyles> & StyleProps & RichTextProps
|
|
18
|
-
|
|
19
|
-
export default function RichTextColumns(props: RichTextColumnsProps) {
|
|
20
|
-
const classes = useStyles(props)
|
|
21
|
-
return <RichText classes={classes} {...props} />
|
|
22
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { withStyles, Theme } from '@material-ui/core'
|
|
2
|
-
import RichText from '.'
|
|
3
|
-
|
|
4
|
-
const RichTextDoubleSpread = withStyles((theme: Theme) => ({
|
|
5
|
-
h2: theme.typography.h4,
|
|
6
|
-
paragraph: {
|
|
7
|
-
[theme.breakpoints.up('sm')]: {
|
|
8
|
-
columnCount: 2,
|
|
9
|
-
columnGap: theme.spacings.md,
|
|
10
|
-
},
|
|
11
|
-
[theme.breakpoints.up('lg')]: {
|
|
12
|
-
columnCount: 3,
|
|
13
|
-
columnGap: theme.spacings.md,
|
|
14
|
-
},
|
|
15
|
-
},
|
|
16
|
-
}))(RichText)
|
|
17
|
-
|
|
18
|
-
export default RichTextDoubleSpread
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { breakpointVal } from '@graphcommerce/next-ui'
|
|
2
|
-
import { Theme, withStyles } from '@material-ui/core'
|
|
3
|
-
import RichText from '.'
|
|
4
|
-
|
|
5
|
-
const RichTextHeadingStrongStroked = withStyles((theme: Theme) => ({
|
|
6
|
-
h2: {
|
|
7
|
-
...theme.typography.h1,
|
|
8
|
-
textTransform: 'uppercase',
|
|
9
|
-
color: theme.palette.text.primary,
|
|
10
|
-
[theme.breakpoints.up('sm')]: {
|
|
11
|
-
...breakpointVal('fontSize', 36, 82, theme.breakpoints.values),
|
|
12
|
-
},
|
|
13
|
-
'& strong': {
|
|
14
|
-
// https://github.com/rsms/inter/issues/292#issuecomment-674993644
|
|
15
|
-
color: theme.palette.background.default,
|
|
16
|
-
textShadow: `1.2px 0 0 ${theme.palette.text.primary},0 1.2px 0 ${theme.palette.text.primary},-1.2px 0 0 ${theme.palette.text.primary},0 -1.2px 0 ${theme.palette.text.primary}`,
|
|
17
|
-
},
|
|
18
|
-
[theme.breakpoints.up('md')]: {},
|
|
19
|
-
},
|
|
20
|
-
}))(RichText)
|
|
21
|
-
|
|
22
|
-
export default RichTextHeadingStrongStroked
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { breakpointVal } from '@graphcommerce/next-ui'
|
|
2
|
-
import { Theme, withStyles } from '@material-ui/core'
|
|
3
|
-
import RichText from '.'
|
|
4
|
-
|
|
5
|
-
const RichTextHero = withStyles((theme: Theme) => ({
|
|
6
|
-
h1: {
|
|
7
|
-
...theme.typography.h1,
|
|
8
|
-
textTransform: 'uppercase',
|
|
9
|
-
maxWidth: '70%',
|
|
10
|
-
textAlign: 'center',
|
|
11
|
-
margin: 0,
|
|
12
|
-
marginBottom: theme.spacings.md,
|
|
13
|
-
[theme.breakpoints.up('sm')]: {
|
|
14
|
-
...breakpointVal('fontSize', 36, 82, theme.breakpoints.values),
|
|
15
|
-
},
|
|
16
|
-
[theme.breakpoints.up('md')]: {
|
|
17
|
-
textAlign: 'left',
|
|
18
|
-
maxWidth: '100%',
|
|
19
|
-
},
|
|
20
|
-
'& strong': {
|
|
21
|
-
WebkitTextFillColor: 'transparent',
|
|
22
|
-
WebkitTextStroke: `1.2px #fff`,
|
|
23
|
-
},
|
|
24
|
-
},
|
|
25
|
-
}))(RichText)
|
|
26
|
-
|
|
27
|
-
export default RichTextHero
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import { Theme, withStyles } from '@material-ui/core'
|
|
2
|
-
import RichText from '.'
|
|
3
|
-
|
|
4
|
-
const RichTextParagraphStrongStroked = withStyles((theme: Theme) => ({
|
|
5
|
-
paragraph: {
|
|
6
|
-
...theme.typography.body2,
|
|
7
|
-
textTransform: 'uppercase',
|
|
8
|
-
maxWidth: '100%',
|
|
9
|
-
fontWeight: 600,
|
|
10
|
-
textAlign: 'left',
|
|
11
|
-
[theme.breakpoints.up('md')]: {
|
|
12
|
-
...theme.typography.h3,
|
|
13
|
-
fontWeight: 600,
|
|
14
|
-
maxWidth: '100%',
|
|
15
|
-
},
|
|
16
|
-
'& strong': {
|
|
17
|
-
color: 'transparent',
|
|
18
|
-
WebkitTextStroke: '1.2px #fff',
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
}))(RichText)
|
|
22
|
-
|
|
23
|
-
export default RichTextParagraphStrongStroked
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Theme, withStyles } from '@material-ui/core'
|
|
2
|
-
import RichText from '.'
|
|
3
|
-
|
|
4
|
-
const RichTextQuote = withStyles((theme: Theme) => ({
|
|
5
|
-
paragraph: {
|
|
6
|
-
...theme.typography.h4,
|
|
7
|
-
fontWeight: 600,
|
|
8
|
-
'@supports (font-variation-settings: normal)': {
|
|
9
|
-
fontVariationSettings: "'wght' 620",
|
|
10
|
-
},
|
|
11
|
-
textTransform: 'uppercase',
|
|
12
|
-
maxWidth: '60%',
|
|
13
|
-
textAlign: 'center',
|
|
14
|
-
margin: '0 auto',
|
|
15
|
-
[theme.breakpoints.up('lg')]: {
|
|
16
|
-
maxWidth: '80%',
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
}))(RichText)
|
|
20
|
-
|
|
21
|
-
export default RichTextQuote
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import { withStyles, Theme } from '@material-ui/core'
|
|
2
|
-
import RichText from '.'
|
|
3
|
-
|
|
4
|
-
const RichTextSpread = withStyles((theme: Theme) => ({
|
|
5
|
-
h2: theme.typography.h4,
|
|
6
|
-
paragraph: {
|
|
7
|
-
[theme.breakpoints.up('md')]: {
|
|
8
|
-
columnCount: 2,
|
|
9
|
-
columnGap: theme.spacings.md,
|
|
10
|
-
},
|
|
11
|
-
},
|
|
12
|
-
}))(RichText)
|
|
13
|
-
|
|
14
|
-
export default RichTextSpread
|
package/RichText/index.tsx
DELETED
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
import { Image } from '@graphcommerce/image'
|
|
2
|
-
import { Link, Typography } from '@material-ui/core'
|
|
3
|
-
import PageLink from 'next/link'
|
|
4
|
-
import React from 'react'
|
|
5
|
-
import useRichTextStyles, { UseRichTextStyles } from './useRichTextStyles'
|
|
6
|
-
|
|
7
|
-
export interface Element {
|
|
8
|
-
children: Node[]
|
|
9
|
-
type:
|
|
10
|
-
| 'heading-one'
|
|
11
|
-
| 'heading-two'
|
|
12
|
-
| 'heading-three'
|
|
13
|
-
| 'heading-four'
|
|
14
|
-
| 'heading-five'
|
|
15
|
-
| 'heading-six'
|
|
16
|
-
| 'paragraph'
|
|
17
|
-
| 'numbered-list'
|
|
18
|
-
| 'bulleted-list'
|
|
19
|
-
| 'block-quote'
|
|
20
|
-
| 'paragraph'
|
|
21
|
-
| 'list-item'
|
|
22
|
-
| 'list-item-child'
|
|
23
|
-
| 'table'
|
|
24
|
-
| 'table_head'
|
|
25
|
-
| 'table_header_cell'
|
|
26
|
-
| 'table_body'
|
|
27
|
-
| 'table_row'
|
|
28
|
-
| 'table_cell'
|
|
29
|
-
| string
|
|
30
|
-
[key: string]: unknown
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export interface Text {
|
|
34
|
-
text: string
|
|
35
|
-
bold?: true
|
|
36
|
-
italic?: true
|
|
37
|
-
underlined?: true
|
|
38
|
-
[key: string]: unknown
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
interface LinkElement extends Element {
|
|
42
|
-
type: 'link'
|
|
43
|
-
href: string
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
interface ImageElement extends Element {
|
|
47
|
-
type: 'image'
|
|
48
|
-
src: string
|
|
49
|
-
title: string
|
|
50
|
-
width: number
|
|
51
|
-
height: number
|
|
52
|
-
mimeType: string
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
interface VideoElement extends Element {
|
|
56
|
-
type: 'image'
|
|
57
|
-
src: string
|
|
58
|
-
title: string
|
|
59
|
-
width: number
|
|
60
|
-
height: number
|
|
61
|
-
mimeType: string
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
interface LinkElement extends Element {
|
|
65
|
-
type: 'link'
|
|
66
|
-
href: string
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
interface IframeElement extends Element {
|
|
70
|
-
type: 'iframe'
|
|
71
|
-
src: string
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
export type ElementNode =
|
|
75
|
-
| Element
|
|
76
|
-
| LinkElement
|
|
77
|
-
| ImageElement
|
|
78
|
-
| VideoElement
|
|
79
|
-
| IframeElement
|
|
80
|
-
| LinkElement
|
|
81
|
-
|
|
82
|
-
export type Node = ElementNode | Text
|
|
83
|
-
|
|
84
|
-
const RenderText = ({ classes, text, ...textProps }: Text & Required<UseRichTextStyles>) => {
|
|
85
|
-
let result = <>{text}</>
|
|
86
|
-
if (textProps.bold) result = <strong>{result}</strong>
|
|
87
|
-
if (textProps.italic) result = <em>{result}</em>
|
|
88
|
-
if (textProps.underlined) result = <em>{result}</em>
|
|
89
|
-
|
|
90
|
-
return result
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
export function isTextNode(node: Node): node is Text {
|
|
94
|
-
return (node as Text).text !== undefined
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function isElementNode(node: Node): node is ElementNode {
|
|
98
|
-
return (node as ElementNode).children !== undefined
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function RenderNode({ classes, ...node }: Node & Required<UseRichTextStyles>) {
|
|
102
|
-
if (isTextNode(node)) {
|
|
103
|
-
return <RenderText {...node} classes={classes} />
|
|
104
|
-
}
|
|
105
|
-
if (isElementNode(node)) {
|
|
106
|
-
// eslint-disable-next-line @typescript-eslint/no-use-before-define
|
|
107
|
-
return <RenderElement {...node} classes={classes} />
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
console.error(node)
|
|
111
|
-
throw Error(`RichText: Node not recognized`)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function RenderChildren({ children, classes }: { children: Node[] } & Required<UseRichTextStyles>) {
|
|
115
|
-
return (
|
|
116
|
-
<>
|
|
117
|
-
{children.map((node, key) => (
|
|
118
|
-
// Since we don't know any unique identifiers of the element and since this doesn't rerender often this is fine.
|
|
119
|
-
// eslint-disable-next-line react/no-array-index-key
|
|
120
|
-
<RenderNode {...node} key={key} classes={classes} />
|
|
121
|
-
))}
|
|
122
|
-
</>
|
|
123
|
-
)
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function RenderElement({ classes, ...element }: ElementNode & Required<UseRichTextStyles>) {
|
|
127
|
-
const {
|
|
128
|
-
root,
|
|
129
|
-
asset,
|
|
130
|
-
h1,
|
|
131
|
-
h2,
|
|
132
|
-
h3,
|
|
133
|
-
h4,
|
|
134
|
-
h5,
|
|
135
|
-
h6,
|
|
136
|
-
paragraph,
|
|
137
|
-
ul,
|
|
138
|
-
ol,
|
|
139
|
-
blockQuote,
|
|
140
|
-
code,
|
|
141
|
-
iframe,
|
|
142
|
-
aspectContainer,
|
|
143
|
-
table,
|
|
144
|
-
link,
|
|
145
|
-
} = classes
|
|
146
|
-
|
|
147
|
-
switch (element.type) {
|
|
148
|
-
case 'heading-one':
|
|
149
|
-
return (
|
|
150
|
-
<Typography variant='h1' classes={{ root, h1 }}>
|
|
151
|
-
<RenderChildren {...element} classes={classes} />
|
|
152
|
-
</Typography>
|
|
153
|
-
)
|
|
154
|
-
case 'heading-two':
|
|
155
|
-
return (
|
|
156
|
-
<Typography variant='h2' classes={{ root, h2 }}>
|
|
157
|
-
<RenderChildren {...element} classes={classes} />
|
|
158
|
-
</Typography>
|
|
159
|
-
)
|
|
160
|
-
case 'heading-three':
|
|
161
|
-
return (
|
|
162
|
-
<Typography variant='h3' classes={{ root, h3 }}>
|
|
163
|
-
<RenderChildren {...element} classes={classes} />
|
|
164
|
-
</Typography>
|
|
165
|
-
)
|
|
166
|
-
case 'heading-four':
|
|
167
|
-
return (
|
|
168
|
-
<Typography variant='h4' classes={{ root, h4 }}>
|
|
169
|
-
<RenderChildren {...element} classes={classes} />
|
|
170
|
-
</Typography>
|
|
171
|
-
)
|
|
172
|
-
case 'heading-five':
|
|
173
|
-
return (
|
|
174
|
-
<Typography variant='h5' classes={{ root, h5 }}>
|
|
175
|
-
<RenderChildren {...element} classes={classes} />
|
|
176
|
-
</Typography>
|
|
177
|
-
)
|
|
178
|
-
case 'heading-six':
|
|
179
|
-
return (
|
|
180
|
-
<Typography variant='h6' classes={{ root, h6 }}>
|
|
181
|
-
<RenderChildren {...element} classes={classes} />
|
|
182
|
-
</Typography>
|
|
183
|
-
)
|
|
184
|
-
case 'paragraph':
|
|
185
|
-
return element.children[0].code ? (
|
|
186
|
-
<pre className={classes.code}>
|
|
187
|
-
<code>
|
|
188
|
-
<RenderChildren {...element} classes={classes} />
|
|
189
|
-
</code>
|
|
190
|
-
</pre>
|
|
191
|
-
) : (
|
|
192
|
-
<Typography variant='body1' paragraph classes={{ root, paragraph }}>
|
|
193
|
-
<RenderChildren {...element} classes={classes} />
|
|
194
|
-
</Typography>
|
|
195
|
-
)
|
|
196
|
-
|
|
197
|
-
case 'bulleted-list':
|
|
198
|
-
return (
|
|
199
|
-
<Typography component='ul' classes={{ root: ul }}>
|
|
200
|
-
<RenderChildren {...element} classes={classes} />
|
|
201
|
-
</Typography>
|
|
202
|
-
)
|
|
203
|
-
case 'numbered-list':
|
|
204
|
-
return (
|
|
205
|
-
<Typography component='ol' classes={{ root: ol }}>
|
|
206
|
-
<RenderChildren {...element} classes={classes} />
|
|
207
|
-
</Typography>
|
|
208
|
-
)
|
|
209
|
-
case 'list-item':
|
|
210
|
-
return (
|
|
211
|
-
<li>
|
|
212
|
-
<RenderChildren {...element} classes={classes} />
|
|
213
|
-
</li>
|
|
214
|
-
)
|
|
215
|
-
case 'list-item-child':
|
|
216
|
-
return <RenderChildren {...element} classes={classes} />
|
|
217
|
-
case 'block-quote':
|
|
218
|
-
return (
|
|
219
|
-
<Typography component='blockquote' classes={{ root: blockQuote }}>
|
|
220
|
-
<RenderChildren {...element} classes={classes} />
|
|
221
|
-
</Typography>
|
|
222
|
-
)
|
|
223
|
-
case 'iframe':
|
|
224
|
-
// eslint-disable-next-line no-case-declarations
|
|
225
|
-
const iframeElement = element as IframeElement
|
|
226
|
-
// todo(paales) add security attributes to iframe
|
|
227
|
-
// todo(paales) make iframe responsive
|
|
228
|
-
return (
|
|
229
|
-
<div className={aspectContainer}>
|
|
230
|
-
<iframe
|
|
231
|
-
src={iframeElement.src}
|
|
232
|
-
title='embedded content'
|
|
233
|
-
className={iframe}
|
|
234
|
-
loading='lazy'
|
|
235
|
-
/>
|
|
236
|
-
</div>
|
|
237
|
-
)
|
|
238
|
-
case 'image':
|
|
239
|
-
// eslint-disable-next-line no-case-declarations
|
|
240
|
-
const imageElement = element as ImageElement
|
|
241
|
-
return (
|
|
242
|
-
<Image
|
|
243
|
-
src={imageElement.src}
|
|
244
|
-
width={imageElement.width}
|
|
245
|
-
height={imageElement.height}
|
|
246
|
-
alt={imageElement.title}
|
|
247
|
-
className={asset}
|
|
248
|
-
/>
|
|
249
|
-
)
|
|
250
|
-
case 'video':
|
|
251
|
-
// eslint-disable-next-line no-case-declarations
|
|
252
|
-
const videoElement = element as VideoElement
|
|
253
|
-
return (
|
|
254
|
-
<div>IMPLEMENT VIDEO</div>
|
|
255
|
-
// <Asset
|
|
256
|
-
// asset={{ url: videoElement.src, mimeType: videoElement.mimeType }}
|
|
257
|
-
// autoPlay
|
|
258
|
-
// loop
|
|
259
|
-
// muted
|
|
260
|
-
// playsInline
|
|
261
|
-
// width={380}
|
|
262
|
-
// className={asset}
|
|
263
|
-
// />
|
|
264
|
-
)
|
|
265
|
-
case 'link':
|
|
266
|
-
// eslint-disable-next-line no-case-declarations
|
|
267
|
-
const linkElement = element as LinkElement
|
|
268
|
-
return (
|
|
269
|
-
<PageLink href={linkElement.href} passHref>
|
|
270
|
-
<Link classes={{ root: link }}>
|
|
271
|
-
<RenderChildren {...element} classes={classes} />
|
|
272
|
-
</Link>
|
|
273
|
-
</PageLink>
|
|
274
|
-
)
|
|
275
|
-
case 'table':
|
|
276
|
-
return (
|
|
277
|
-
<table className={table}>
|
|
278
|
-
<RenderChildren {...element} classes={classes} />
|
|
279
|
-
</table>
|
|
280
|
-
)
|
|
281
|
-
case 'table_head':
|
|
282
|
-
return (
|
|
283
|
-
<thead>
|
|
284
|
-
<RenderChildren {...element} classes={classes} />
|
|
285
|
-
</thead>
|
|
286
|
-
)
|
|
287
|
-
case 'table_header_cell':
|
|
288
|
-
return (
|
|
289
|
-
<th>
|
|
290
|
-
<RenderChildren {...element} classes={classes} />
|
|
291
|
-
</th>
|
|
292
|
-
)
|
|
293
|
-
case 'table_body':
|
|
294
|
-
return (
|
|
295
|
-
<tbody>
|
|
296
|
-
<RenderChildren {...element} classes={classes} />
|
|
297
|
-
</tbody>
|
|
298
|
-
)
|
|
299
|
-
case 'table_row':
|
|
300
|
-
return (
|
|
301
|
-
<tr>
|
|
302
|
-
<RenderChildren {...element} classes={classes} />
|
|
303
|
-
</tr>
|
|
304
|
-
)
|
|
305
|
-
case 'table_cell':
|
|
306
|
-
return (
|
|
307
|
-
<td>
|
|
308
|
-
<RenderChildren {...element} classes={classes} />
|
|
309
|
-
</td>
|
|
310
|
-
)
|
|
311
|
-
default:
|
|
312
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
313
|
-
console.error(element)
|
|
314
|
-
throw Error(`RichText: Unknown Element: ${element.type}`)
|
|
315
|
-
}
|
|
316
|
-
return <RenderChildren {...element} classes={classes} />
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
|
-
export type RichTextProps = { raw: ElementNode } & UseRichTextStyles
|
|
321
|
-
|
|
322
|
-
export default function RichText({ raw, ...props }: RichTextProps) {
|
|
323
|
-
const classes = useRichTextStyles(props)
|
|
324
|
-
return <RenderChildren classes={classes} {...raw} />
|
|
325
|
-
}
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import { UseStyles, responsiveVal } from '@graphcommerce/next-ui'
|
|
2
|
-
import { makeStyles, Theme } from '@material-ui/core'
|
|
3
|
-
|
|
4
|
-
const useRichTextStyles = makeStyles(
|
|
5
|
-
(theme: Theme) => ({
|
|
6
|
-
root: {
|
|
7
|
-
'&:empty': {
|
|
8
|
-
display: 'none',
|
|
9
|
-
},
|
|
10
|
-
'&:last-child': {
|
|
11
|
-
marginBottom: 0,
|
|
12
|
-
},
|
|
13
|
-
},
|
|
14
|
-
paragraph: {
|
|
15
|
-
marginBottom: '1em',
|
|
16
|
-
wordBreak: 'break-word',
|
|
17
|
-
},
|
|
18
|
-
h1: {
|
|
19
|
-
marginTop: '0.5em',
|
|
20
|
-
marginBottom: '0.5em',
|
|
21
|
-
},
|
|
22
|
-
h2: {
|
|
23
|
-
marginTop: '0.5em',
|
|
24
|
-
marginBottom: '0.5em',
|
|
25
|
-
'&:first-child': { marginTop: 0 },
|
|
26
|
-
},
|
|
27
|
-
h3: {
|
|
28
|
-
marginTop: '0.5em',
|
|
29
|
-
marginBottom: '0.5em',
|
|
30
|
-
'&:first-child': { marginTop: 0 },
|
|
31
|
-
},
|
|
32
|
-
h4: {
|
|
33
|
-
marginTop: responsiveVal(11, 30),
|
|
34
|
-
marginBottom: responsiveVal(11, 30),
|
|
35
|
-
'&:first-child': { marginTop: 0 },
|
|
36
|
-
},
|
|
37
|
-
h5: {
|
|
38
|
-
marginTop: responsiveVal(7, 20),
|
|
39
|
-
marginBottom: responsiveVal(7, 20),
|
|
40
|
-
'&:first-child': { marginTop: 0 },
|
|
41
|
-
},
|
|
42
|
-
h6: {
|
|
43
|
-
'&:first-of-type': {
|
|
44
|
-
marginTop: 0,
|
|
45
|
-
},
|
|
46
|
-
},
|
|
47
|
-
asset: {
|
|
48
|
-
width: '100%',
|
|
49
|
-
height: 'auto',
|
|
50
|
-
},
|
|
51
|
-
blockQuote: {
|
|
52
|
-
paddingLeft: theme.spacings.sm,
|
|
53
|
-
margin: `${theme.spacings.md} 0`,
|
|
54
|
-
},
|
|
55
|
-
ol: {
|
|
56
|
-
marginBottom: '1em',
|
|
57
|
-
},
|
|
58
|
-
ul: {
|
|
59
|
-
marginBottom: '1em',
|
|
60
|
-
},
|
|
61
|
-
strong: {},
|
|
62
|
-
italic: {},
|
|
63
|
-
underlined: {},
|
|
64
|
-
code: {
|
|
65
|
-
width: 'fit-content',
|
|
66
|
-
maxWidth: '100%',
|
|
67
|
-
padding: 5,
|
|
68
|
-
overflow: 'scroll',
|
|
69
|
-
},
|
|
70
|
-
iframe: {},
|
|
71
|
-
aspectContainer: {},
|
|
72
|
-
table: {
|
|
73
|
-
display: 'table',
|
|
74
|
-
width: '100%',
|
|
75
|
-
borderSpacing: '2px',
|
|
76
|
-
borderCollapse: 'collapse',
|
|
77
|
-
marginTop: theme.spacings.md,
|
|
78
|
-
marginBottom: theme.spacings.sm,
|
|
79
|
-
'& thead, tbody': {
|
|
80
|
-
'& td': {
|
|
81
|
-
padding: '10px 20px',
|
|
82
|
-
},
|
|
83
|
-
},
|
|
84
|
-
'& thead': {
|
|
85
|
-
'& tr': {
|
|
86
|
-
'& td': {
|
|
87
|
-
'& p': {
|
|
88
|
-
fontWeight: theme.typography.fontWeightBold,
|
|
89
|
-
},
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
'& tbody': {
|
|
94
|
-
display: 'table-row-group',
|
|
95
|
-
verticalAlign: 'center',
|
|
96
|
-
borderColor: 'inherit',
|
|
97
|
-
'& tr': {
|
|
98
|
-
'&:nth-child(odd)': {
|
|
99
|
-
background: theme.palette.background.paper,
|
|
100
|
-
},
|
|
101
|
-
},
|
|
102
|
-
'& td': {
|
|
103
|
-
[theme.breakpoints.up('sm')]: {
|
|
104
|
-
minWidth: '150px',
|
|
105
|
-
},
|
|
106
|
-
'& p': {},
|
|
107
|
-
},
|
|
108
|
-
},
|
|
109
|
-
},
|
|
110
|
-
link: {
|
|
111
|
-
wordBreak: 'break-word',
|
|
112
|
-
},
|
|
113
|
-
}),
|
|
114
|
-
{ name: 'RichText' },
|
|
115
|
-
)
|
|
116
|
-
export type UseRichTextStyles = UseStyles<typeof useRichTextStyles>
|
|
117
|
-
|
|
118
|
-
export default useRichTextStyles
|