@graphcommerce/graphcms-ui 3.0.5 → 3.0.8

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 CHANGED
@@ -1,5 +1,34 @@
1
1
  # Change Log
2
2
 
3
+ ## 3.0.8
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1369](https://github.com/graphcommerce-org/graphcommerce/pull/1369) [`ae6449502`](https://github.com/graphcommerce-org/graphcommerce/commit/ae64495024a455bbe5188588604368c1542840c9) Thanks [@paales](https://github.com/paales)! - Upgraded dependencies
8
+
9
+ - Updated dependencies [[`892018809`](https://github.com/graphcommerce-org/graphcommerce/commit/8920188093d0422ec50580e408dc28ac5f93e46a), [`892018809`](https://github.com/graphcommerce-org/graphcommerce/commit/8920188093d0422ec50580e408dc28ac5f93e46a), [`ae6449502`](https://github.com/graphcommerce-org/graphcommerce/commit/ae64495024a455bbe5188588604368c1542840c9), [`892018809`](https://github.com/graphcommerce-org/graphcommerce/commit/8920188093d0422ec50580e408dc28ac5f93e46a), [`892018809`](https://github.com/graphcommerce-org/graphcommerce/commit/8920188093d0422ec50580e408dc28ac5f93e46a)]:
10
+ - @graphcommerce/graphql@3.0.6
11
+ - @graphcommerce/next-ui@4.5.0
12
+ - @graphcommerce/image@3.1.2
13
+
14
+ ## 3.0.7
15
+
16
+ ### Patch Changes
17
+
18
+ - [#1353](https://github.com/graphcommerce-org/graphcommerce/pull/1353) [`0e5ee7ba8`](https://github.com/graphcommerce-org/graphcommerce/commit/0e5ee7ba89698e5e711001e846ed182528060cba) Thanks [@paales](https://github.com/paales)! - Eslint: enable rules that were previously disabled and make fixes
19
+
20
+ - Updated dependencies [[`49a2d6617`](https://github.com/graphcommerce-org/graphcommerce/commit/49a2d661712e1787fba46c6195f7b559189e23d9), [`f67da3cfb`](https://github.com/graphcommerce-org/graphcommerce/commit/f67da3cfbe2dcf5ea23519d088c5aa0074029182), [`218766869`](https://github.com/graphcommerce-org/graphcommerce/commit/218766869f7468c067a590857c942f3819f8add4), [`0e5ee7ba8`](https://github.com/graphcommerce-org/graphcommerce/commit/0e5ee7ba89698e5e711001e846ed182528060cba), [`829b8690b`](https://github.com/graphcommerce-org/graphcommerce/commit/829b8690bc5d0a46e596299e4120e9837a9f179c)]:
21
+ - @graphcommerce/next-ui@4.4.0
22
+
23
+ ## 3.0.6
24
+
25
+ ### Patch Changes
26
+
27
+ - [#1322](https://github.com/graphcommerce-org/graphcommerce/pull/1322) [`ae7385b94`](https://github.com/graphcommerce-org/graphcommerce/commit/ae7385b943e591fcd6fe9e5747f22e03a73e481a) Thanks [@paales](https://github.com/paales)! - RichText component’s first and last element should have no marginTop and marginBottom respectively unless withMargin is specified
28
+
29
+ - Updated dependencies [[`5266388ea`](https://github.com/graphcommerce-org/graphcommerce/commit/5266388eaffda41592623ef7a3ddbbe03c8e0dad), [`9b35403d9`](https://github.com/graphcommerce-org/graphcommerce/commit/9b35403d9dbb2606ac7cf3bb641a0f9cc3d8a2ba), [`0298a0de1`](https://github.com/graphcommerce-org/graphcommerce/commit/0298a0de1d13e543c4124a6a099297b4e27e2b05), [`815132ea4`](https://github.com/graphcommerce-org/graphcommerce/commit/815132ea43937b4b84b59ec9974ac593cb4eb456), [`3326742a0`](https://github.com/graphcommerce-org/graphcommerce/commit/3326742a0dceb45f0cac4741ca09dc4d4f09ad90), [`7a3799bfc`](https://github.com/graphcommerce-org/graphcommerce/commit/7a3799bfc107f26aa9991a91db5f228e3476f4aa), [`9a77f88ed`](https://github.com/graphcommerce-org/graphcommerce/commit/9a77f88ed26cbecdae9a135c3cb234a5b7ecf4df), [`0eeaad304`](https://github.com/graphcommerce-org/graphcommerce/commit/0eeaad30461b1d5b486438f0287fa76d49429044), [`bc5213547`](https://github.com/graphcommerce-org/graphcommerce/commit/bc52135471479c83d989449dad24798112e898f4), [`3f1912f55`](https://github.com/graphcommerce-org/graphcommerce/commit/3f1912f553318d5888f8af2b841918ef4ae96a84), [`b6c68cda8`](https://github.com/graphcommerce-org/graphcommerce/commit/b6c68cda8836a1d0c78ef351899cec9ec1037385)]:
30
+ - @graphcommerce/next-ui@4.3.0
31
+
3
32
  ## 3.0.5
4
33
 
5
34
  ### Patch Changes
@@ -1,22 +1,59 @@
1
+ /* eslint-disable @typescript-eslint/no-use-before-define */
1
2
  import { SxProps, Theme } from '@mui/material'
2
3
  import { defaultRenderers } from './defaultRenderers'
3
4
  import { defaultSxRenderer } from './defaultSxRenderer'
4
5
  import {
5
6
  AdditionalProps,
6
7
  Renderers,
8
+ Renderer,
7
9
  SxRenderer,
8
10
  TextNode,
9
11
  ElementOrTextNode,
10
12
  ElementNode,
13
+ SimpleElement,
11
14
  } from './types'
12
15
 
13
- function 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>
16
+ const sxArr = (sxAny?: SxProps<Theme> | false) => {
17
+ if (!sxAny) return []
18
+ return Array.isArray(sxAny) ? sxAny : [sxAny]
19
+ }
20
+
21
+ function useRenderProps(
22
+ { first, last, sxRenderer }: Pick<AdditionalProps, 'first' | 'last' | 'sxRenderer'>,
23
+ type?: ElementNode['type'],
24
+ ) {
25
+ if (!type) return []
26
+ const sx: SxProps<Theme> = sxRenderer?.[type] ?? []
27
+
28
+ return [
29
+ ...sxArr(sxRenderer.all),
30
+ ...sxArr(sx),
31
+ ...sxArr(first && sxRenderer.first),
32
+ ...sxArr(last && sxRenderer.last),
33
+ ]
34
+ }
35
+
36
+ function RenderText({
37
+ text,
38
+ renderers,
39
+ sxRenderer,
40
+ first,
41
+ last,
42
+ ...textProps
43
+ }: TextNode & AdditionalProps) {
44
+ let type: 'bold' | 'italic' | 'underlined' | undefined
45
+
46
+ if (textProps.bold) type = 'bold'
47
+ if (textProps.italic) type = 'italic'
48
+ if (textProps.underlined) type = 'underlined'
18
49
 
19
- return result
50
+ const sx = useRenderProps({ first, last, sxRenderer }, type)
51
+
52
+ if (!type) return <>{text}</>
53
+
54
+ const Component: Renderer<SimpleElement> = renderers[type]
55
+
56
+ return <Component sx={sx}>{text}</Component>
20
57
  }
21
58
 
22
59
  export function isTextNode(node: ElementOrTextNode): node is TextNode {
@@ -46,29 +83,37 @@ function RenderNode(node: ElementOrTextNode & AdditionalProps) {
46
83
 
47
84
  function RenderChildren({
48
85
  childNodes,
86
+ noMargin,
49
87
  ...props
50
- }: { childNodes: ElementNode['children'] } & AdditionalProps) {
88
+ }: { childNodes: ElementNode['children']; noMargin?: boolean } & AdditionalProps) {
51
89
  return (
52
90
  <>
53
91
  {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} />
92
+ <RenderNode
93
+ {...node}
94
+ {...props}
95
+ // Since we don't know any unique identifiers of the element and since this doesn't rerender often this is fine.
96
+ // eslint-disable-next-line react/no-array-index-key
97
+ key={key}
98
+ first={noMargin && key === 0}
99
+ last={noMargin && key === childNodes.length - 1}
100
+ />
57
101
  ))}
58
102
  </>
59
103
  )
60
104
  }
61
105
 
62
106
  function RenderElement(element: ElementNode & AdditionalProps) {
63
- const { type, children, sxRenderer, renderers, ...props } = element
107
+ const { type, children, sxRenderer, renderers, first, last, ...props } = element
64
108
 
65
109
  // todo: this has the any type, could be improved
66
- const Component = renderers[type]
67
- const sx = sxRenderer?.[type] ?? []
110
+ const Component: Renderer<SimpleElement> = renderers[type]
111
+
112
+ const sx = useRenderProps({ first, last, sxRenderer }, type)
68
113
 
69
114
  if (Component) {
70
115
  return (
71
- <Component {...props} sx={[sxRenderer.all, ...(Array.isArray(sx) ? sx : [sx])]}>
116
+ <Component {...props} sx={sx}>
72
117
  <RenderChildren childNodes={children} sxRenderer={sxRenderer} renderers={renderers} />
73
118
  </Component>
74
119
  )
@@ -76,17 +121,12 @@ function RenderElement(element: ElementNode & AdditionalProps) {
76
121
 
77
122
  if (process.env.NODE_ENV !== 'production') {
78
123
  console.error(element)
79
- throw Error(`RichText: Unknown Element: ${element.type}`)
124
+ throw Error(`RichText: Unknown Element: ${type}`)
80
125
  }
81
126
  return <RenderChildren childNodes={children} sxRenderer={sxRenderer} renderers={renderers} />
82
127
  }
83
128
 
84
- export type RichTextProps = { raw: ElementNode } & {
85
- renderers?: Partial<Renderers>
86
- sxRenderer?: SxRenderer
87
- }
88
-
89
- export function mergeSxRenderer(base: SxRenderer, sxRenderer?: SxRenderer) {
129
+ function mergeSxRenderer(base: SxRenderer, sxRenderer?: SxRenderer) {
90
130
  if (!sxRenderer) return base
91
131
 
92
132
  return Object.fromEntries(
@@ -106,12 +146,38 @@ export function mergeSxRenderer(base: SxRenderer, sxRenderer?: SxRenderer) {
106
146
  ) as SxRenderer
107
147
  }
108
148
 
109
- export function RichText({ raw, sxRenderer, renderers }: RichTextProps) {
149
+ export type RichTextProps = { raw: ElementNode } & {
150
+ renderers?: Partial<Renderers>
151
+ /**
152
+ * Allows you to theme all the types of components
153
+ *
154
+ * ```tsx
155
+ * function MyComponent()f {
156
+ * return <RichText
157
+ * sxRenderer={{
158
+ * paragraph: (theme) => ({
159
+ * columnCount: { xs: 1, md: getColumnCount(props, 2) },
160
+ * columnGap: theme.spacings.md,
161
+ * }),
162
+ * //other props here
163
+ * }}
164
+ * />
165
+ * }
166
+ * ```
167
+ */
168
+ sxRenderer?: SxRenderer
169
+
170
+ /** By default the component will render the first and last element without any margins */
171
+ withMargin?: boolean
172
+ }
173
+
174
+ export function RichText({ raw, sxRenderer, renderers, withMargin = false }: RichTextProps) {
110
175
  return (
111
176
  <RenderChildren
112
177
  childNodes={raw.children}
113
178
  sxRenderer={mergeSxRenderer(defaultSxRenderer, sxRenderer)}
114
179
  renderers={{ ...defaultRenderers, ...renderers }}
180
+ noMargin={!withMargin}
115
181
  />
116
182
  )
117
183
  }
@@ -27,9 +27,9 @@ export const defaultRenderers: Renderers = {
27
27
  video: ({ src, width, height, title, mimeType }) => (
28
28
  <Asset asset={{ url: src, alt: title, width, height, mimeType }} />
29
29
  ),
30
- link: ({ href, ...props }) => (
30
+ link: ({ href, openInNewTab, ...props }) => (
31
31
  <PageLink href={href} passHref>
32
- <Link underline='hover' {...props} />
32
+ <Link underline='hover' {...props} target={openInNewTab ? '_blank' : undefined} />
33
33
  </PageLink>
34
34
  ),
35
35
  table: (props) => <Box component='table' {...props} />,
@@ -39,4 +39,7 @@ export const defaultRenderers: Renderers = {
39
39
  table_row: (props) => <Box component='tr' {...props} />,
40
40
  table_cell: (props) => <Box component='td' {...props} />,
41
41
  code: (props) => <Box component='code' {...props} />,
42
+ bold: (props) => <Box component='strong' fontWeight='bold' {...props} />,
43
+ italic: (props) => <Box component='em' fontStyle='italic' {...props} />,
44
+ underlined: (props) => <Box component='span' {...props} />,
42
45
  }
@@ -5,7 +5,12 @@ export const defaultSxRenderer: SxRenderer = {
5
5
  '&:empty': {
6
6
  display: 'none',
7
7
  },
8
- '&:last-of-type': { marginBottom: 0 },
8
+ },
9
+ first: {
10
+ marginTop: 0,
11
+ },
12
+ last: {
13
+ marginBottom: 0,
9
14
  },
10
15
  paragraph: {
11
16
  marginBottom: '1em',
@@ -18,22 +23,18 @@ export const defaultSxRenderer: SxRenderer = {
18
23
  'heading-two': {
19
24
  marginTop: '0.5em',
20
25
  marginBottom: '0.5em',
21
- '&:first-of-type': { marginTop: 0 },
22
26
  },
23
27
  'heading-three': {
24
28
  marginTop: '0.5em',
25
29
  marginBottom: '0.5em',
26
- '&:first-of-type': { marginTop: 0 },
27
30
  },
28
31
  'heading-four': {
29
32
  marginTop: '0.5em',
30
33
  marginBottom: '0.5em',
31
- '&:first-of-type': { marginTop: 0 },
32
34
  },
33
35
  'heading-five': {
34
36
  marginTop: '0.5em',
35
37
  marginBottom: '0.5em',
36
- '&:first-of-type': { marginTop: 0 },
37
38
  },
38
39
  image: {
39
40
  width: '100%',
@@ -100,4 +101,7 @@ export const defaultSxRenderer: SxRenderer = {
100
101
  link: {
101
102
  wordBreak: 'break-word',
102
103
  },
104
+ underlined: {
105
+ textDecoration: 'underline',
106
+ },
103
107
  }
@@ -22,8 +22,11 @@ type BaseElementTypes =
22
22
  | 'table_row'
23
23
  | 'table_cell'
24
24
  | 'code'
25
+ | 'bold'
26
+ | 'italic'
27
+ | 'underlined'
25
28
 
26
- type SimpleElement = {
29
+ export type SimpleElement = {
27
30
  children: ElementOrTextNode[]
28
31
  type: LiteralUnion<BaseElementTypes, string>
29
32
  }
@@ -40,6 +43,7 @@ type LinkElement = {
40
43
  type: 'link'
41
44
  children: ElementOrTextNode[]
42
45
  href: string
46
+ openInNewTab?: boolean
43
47
  }
44
48
 
45
49
  type ImageElement = {
@@ -72,8 +76,8 @@ export type ElementNode = SimpleElement | LinkElement | ImageElement | VideoElem
72
76
  export type ElementOrTextNode = ElementNode | TextNode
73
77
 
74
78
  type RendererBase = { sx?: SxProps<Theme>; children?: React.ReactNode }
75
- type Renderer<P extends ElementNode> = (
76
- props: Omit<P, 'children'> & RendererBase,
79
+ export type Renderer<P extends ElementNode> = (
80
+ props: Omit<P, 'children' | 'type'> & RendererBase,
77
81
  ) => React.ReactElement | null
78
82
 
79
83
  export type Renderers = {
@@ -86,7 +90,12 @@ export type Renderers = {
86
90
  }
87
91
 
88
92
  export type SxRenderer = {
89
- [k in keyof Renderers | 'all']?: SxProps<Theme>
93
+ [k in keyof Renderers | 'all' | 'first' | 'last']?: SxProps<Theme>
90
94
  }
91
95
 
92
- export type AdditionalProps = { renderers: Renderers; sxRenderer: SxRenderer }
96
+ export type AdditionalProps = {
97
+ renderers: Renderers
98
+ sxRenderer: SxRenderer
99
+ first?: boolean
100
+ last?: boolean
101
+ }
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@graphcommerce/graphcms-ui",
3
3
  "homepage": "https://www.graphcommerce.org/",
4
4
  "repository": "github:graphcommerce-org/graphcommerce",
5
- "version": "3.0.5",
5
+ "version": "3.0.8",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,16 +12,16 @@
12
12
  }
13
13
  },
14
14
  "devDependencies": {
15
- "@graphcommerce/eslint-config-pwa": "^4.0.5",
16
- "@graphcommerce/prettier-config-pwa": "^4.0.3",
15
+ "@graphcommerce/eslint-config-pwa": "^4.1.3",
16
+ "@graphcommerce/prettier-config-pwa": "^4.0.5",
17
17
  "@graphcommerce/typescript-config-pwa": "^4.0.2",
18
- "@playwright/test": "^1.19.2"
18
+ "@playwright/test": "^1.20.1",
19
+ "type-fest": "2.12.1"
19
20
  },
20
21
  "dependencies": {
21
- "@graphcommerce/graphql": "^3.0.4",
22
- "@graphcommerce/image": "^3.1.1",
23
- "@graphcommerce/next-ui": "^4.2.4",
24
- "type-fest": "^2.12.0"
22
+ "@graphcommerce/graphql": "^3.0.6",
23
+ "@graphcommerce/image": "^3.1.2",
24
+ "@graphcommerce/next-ui": "^4.5.0"
25
25
  },
26
26
  "peerDependencies": {
27
27
  "@mui/material": "^5.4.1",