@graphcommerce/graphcms-ui 9.0.0-canary.98 → 9.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/index.ts CHANGED
@@ -1,3 +1 @@
1
- export * from './components'
2
- export * from './graphql'
3
- export * from './lib'
1
+ export * from '@graphcommerce/hygraph-ui'
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": "9.0.0-canary.98",
5
+ "version": "9.0.0",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -12,16 +12,6 @@
12
12
  }
13
13
  },
14
14
  "peerDependencies": {
15
- "@graphcommerce/ecommerce-ui": "^9.0.0-canary.98",
16
- "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.98",
17
- "@graphcommerce/graphql": "^9.0.0-canary.98",
18
- "@graphcommerce/image": "^9.0.0-canary.98",
19
- "@graphcommerce/next-ui": "^9.0.0-canary.98",
20
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.98",
21
- "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.98",
22
- "@mui/material": "^5.10.16",
23
- "next": "*",
24
- "react": "^18.2.0",
25
- "react-dom": "^18.2.0"
15
+ "@graphcommerce/hygraph-ui": "^9.0.0"
26
16
  }
27
17
  }
package/Config.graphqls DELETED
@@ -1,17 +0,0 @@
1
- extend input GraphCommerceConfig {
2
- """
3
- The HyGraph endpoint.
4
-
5
- > Read-only endpoint that allows low latency and high read-throughput content delivery.
6
-
7
- Project settings -> API Access -> High Performance Read-only Content API
8
- """
9
- hygraphEndpoint: String!
10
- }
11
-
12
- extend input GraphCommerceStorefrontConfig {
13
- """
14
- Add a gcms-locales header to make sure queries return in a certain language, can be an array to define fallbacks.
15
- """
16
- hygraphLocales: [String!]
17
- }
package/README.md DELETED
@@ -1,4 +0,0 @@
1
- ## Configuration
2
-
3
- Configure the following ([configuration values](./Config.graphqls)) in your
4
- graphcommerce.config.js
@@ -1,7 +0,0 @@
1
- fragment Asset on Asset {
2
- url
3
- width
4
- height
5
- mimeType
6
- size
7
- }
@@ -1,59 +0,0 @@
1
- import { Image, ImageProps } from '@graphcommerce/image'
2
- import { styled, SxProps, Theme } from '@mui/material'
3
- import { memo } from 'react'
4
- import { AssetFragment } from './Asset.gql'
5
-
6
- export type { AssetFragment } from './Asset.gql'
7
-
8
- type ImageAsset = Omit<AssetFragment, 'width' | 'height'> & {
9
- width: number
10
- height: number
11
- }
12
-
13
- function isImage(asset: AssetFragment): asset is ImageAsset {
14
- return !!(asset.width && asset.height)
15
- }
16
-
17
- type AssetProps = {
18
- asset: AssetFragment
19
- sx?: SxProps<Theme>
20
- } & Omit<ImageProps, 'src' | 'width' | 'height' | 'alt' | 'sx'>
21
-
22
- export const Asset = memo<AssetProps>((props) => {
23
- const { asset, sx = [], ...imgProps } = props
24
-
25
- if (isImage(asset)) {
26
- const { url, height, mimeType, size, width, alt, ...assetProps } = asset
27
- return (
28
- <Image
29
- src={url}
30
- height={height}
31
- width={width}
32
- alt={alt ?? undefined}
33
- {...imgProps}
34
- {...assetProps}
35
- unoptimized={mimeType === 'image/svg+xml'}
36
- sx={[...(Array.isArray(sx) ? sx : [sx])]}
37
- />
38
- )
39
- }
40
-
41
- if (asset.mimeType === 'video/mp4') {
42
- const Video = styled('video')({})
43
-
44
- return (
45
- <Video
46
- src={asset.url}
47
- autoPlay
48
- muted
49
- loop
50
- playsInline
51
- disableRemotePlayback
52
- sx={[...(Array.isArray(sx) ? sx : [sx])]}
53
- />
54
- )
55
- }
56
-
57
- if (process.env.NODE_ENV !== 'production') return <div>{asset.mimeType} not supported</div>
58
- return null
59
- })
@@ -1,199 +0,0 @@
1
- /* eslint-disable @typescript-eslint/no-use-before-define */
2
- import { SxProps, Theme } from '@mui/material'
3
- import React from 'react'
4
- import { defaultRenderers } from './defaultRenderers'
5
- import { defaultSxRenderer } from './defaultSxRenderer'
6
- import {
7
- AdditionalProps,
8
- Renderers,
9
- Renderer,
10
- SxRenderer,
11
- TextNode,
12
- ElementOrTextNode,
13
- ElementNode,
14
- SimpleElement,
15
- } from './types'
16
-
17
- const sxArr = (sxAny?: SxProps<Theme> | false) => {
18
- if (!sxAny) return []
19
- return Array.isArray(sxAny) ? sxAny : [sxAny]
20
- }
21
-
22
- function useRenderProps(
23
- { first, last, sxRenderer }: Pick<AdditionalProps, 'first' | 'last' | 'sxRenderer'>,
24
- type?: ElementNode['type'],
25
- ) {
26
- if (!type) return []
27
- const sx: SxProps<Theme> = sxRenderer?.[type] ?? []
28
-
29
- return [
30
- ...sxArr(sxRenderer.all),
31
- ...sxArr(sx),
32
- ...sxArr(first && sxRenderer.first),
33
- ...sxArr(last && sxRenderer.last),
34
- ]
35
- }
36
-
37
- function LineBreakToBr(props: { text: string }) {
38
- const { text } = props
39
-
40
- const textA = text.split('\n')
41
- const textArray: React.ReactNode[] = []
42
- textA.forEach((val, index) => {
43
- textArray.push(val)
44
- if (index < textA.length - 1) textArray.push(<br />)
45
- })
46
-
47
- // eslint-disable-next-line react/no-array-index-key
48
- return textArray.map((val, idx) => <React.Fragment key={idx}>{val}</React.Fragment>)
49
- }
50
-
51
- function RenderText({
52
- text,
53
- renderers,
54
- sxRenderer,
55
- first,
56
- last,
57
- ...textProps
58
- }: TextNode & AdditionalProps) {
59
- let type: 'bold' | 'italic' | 'underlined' | undefined
60
-
61
- if (textProps.bold) type = 'bold'
62
- if (textProps.italic) type = 'italic'
63
- if (textProps.underlined) type = 'underlined'
64
-
65
- const sx = useRenderProps({ first, last, sxRenderer }, type)
66
-
67
- if (!type) return <LineBreakToBr text={text} />
68
- const Component: Renderer<SimpleElement> = renderers[type]
69
- return (
70
- <Component sx={sx}>
71
- <LineBreakToBr text={text} />
72
- </Component>
73
- )
74
- }
75
-
76
- export function isTextNode(node: ElementOrTextNode): node is TextNode {
77
- return (node as TextNode).text !== undefined
78
- }
79
-
80
- export function isElementNode(node: ElementOrTextNode): node is ElementNode {
81
- return (node as ElementNode).children !== undefined
82
- }
83
-
84
- function RenderNode(node: ElementOrTextNode & AdditionalProps) {
85
- if (isTextNode(node)) {
86
- return <RenderText {...node} />
87
- }
88
- if (isElementNode(node)) {
89
- // eslint-disable-next-line @typescript-eslint/no-use-before-define
90
- return <RenderElement {...node} />
91
- }
92
-
93
- if (process.env.NODE_ENV !== 'production') {
94
- console.error(node)
95
- throw Error(`RichText: Node not recognized`)
96
- }
97
-
98
- return null
99
- }
100
-
101
- function RenderChildren({
102
- childNodes,
103
- noMargin,
104
- ...props
105
- }: { childNodes: ElementNode['children']; noMargin?: boolean } & AdditionalProps) {
106
- return (
107
- <>
108
- {childNodes.map((node, key) => (
109
- <RenderNode
110
- {...node}
111
- {...props}
112
- // Since we don't know any unique identifiers of the element and since this doesn't rerender often this is fine.
113
- // eslint-disable-next-line react/no-array-index-key
114
- key={key}
115
- first={noMargin && key === 0}
116
- last={noMargin && key === childNodes.length - 1}
117
- />
118
- ))}
119
- </>
120
- )
121
- }
122
-
123
- function RenderElement(element: ElementNode & AdditionalProps) {
124
- const { type, children, sxRenderer, renderers, first, last, ...props } = element
125
-
126
- // todo: this has the any type, could be improved
127
- const Component: Renderer<SimpleElement> = renderers[type]
128
- const sx = useRenderProps({ first, last, sxRenderer }, type)
129
-
130
- if (Component) {
131
- return (
132
- <Component {...props} sx={sx}>
133
- <RenderChildren childNodes={children} sxRenderer={sxRenderer} renderers={renderers} />
134
- </Component>
135
- )
136
- }
137
-
138
- if (process.env.NODE_ENV !== 'production') {
139
- console.error(element)
140
- throw Error(`RichText: Unknown Element: ${type}`)
141
- }
142
- return <RenderChildren childNodes={children} sxRenderer={sxRenderer} renderers={renderers} />
143
- }
144
-
145
- function mergeSxRenderer(base: SxRenderer, sxRenderer?: SxRenderer) {
146
- if (!sxRenderer) return base
147
-
148
- return Object.fromEntries(
149
- Object.entries<SxProps<Theme>>(base).map(([key, sx]) => {
150
- const sxOverride: SxProps<Theme> = sxRenderer?.[key]
151
-
152
- return sxOverride
153
- ? [
154
- key,
155
- [
156
- ...(Array.isArray(sx) ? sx : [sx]),
157
- ...(Array.isArray(sxOverride) ? sxOverride : [sxOverride]),
158
- ],
159
- ]
160
- : [key, sx]
161
- }),
162
- ) as SxRenderer
163
- }
164
-
165
- export type RichTextProps = { raw: ElementNode } & {
166
- renderers?: Partial<Renderers>
167
- /**
168
- * Allows you to theme all the types of components
169
- *
170
- * ```tsx
171
- * function MyComponent()f {
172
- * return <RichText
173
- * sxRenderer={{
174
- * paragraph: (theme) => ({
175
- * columnCount: { xs: 1, md: getColumnCount(props, 2) },
176
- * columnGap: theme.spacings.md,
177
- * }),
178
- * //other props here
179
- * }}
180
- * />
181
- * }
182
- * ```
183
- */
184
- sxRenderer?: SxRenderer
185
-
186
- /** By default the component will render the first and last element without any margins */
187
- withMargin?: boolean
188
- }
189
-
190
- export function RichText({ raw, sxRenderer, renderers, withMargin = false }: RichTextProps) {
191
- return (
192
- <RenderChildren
193
- childNodes={raw.children}
194
- sxRenderer={mergeSxRenderer(defaultSxRenderer, sxRenderer)}
195
- renderers={{ ...defaultRenderers, ...renderers }}
196
- noMargin={!withMargin}
197
- />
198
- )
199
- }
@@ -1,58 +0,0 @@
1
- import { Box, Typography, Link } from '@mui/material'
2
- import { Asset } from '../Asset/Asset'
3
- import { Renderers } from './types'
4
-
5
- export const defaultRenderers: Renderers = {
6
- 'heading-one': (props) => <Typography variant='h1' {...props} />,
7
- 'heading-two': (props) => <Typography variant='h2' {...props} />,
8
- 'heading-three': (props) => <Typography variant='h3' {...props} />,
9
- 'heading-four': (props) => <Typography variant='h4' {...props} />,
10
- 'heading-five': (props) => <Typography variant='h5' {...props} />,
11
- 'heading-six': (props) => <Typography variant='h6' {...props} />,
12
- paragraph: (props) => <Typography variant='body1' gutterBottom {...props} />,
13
- 'bulleted-list': (props) => <Box component='ul' {...props} />,
14
- 'numbered-list': (props) => <Box component='ol' {...props} />,
15
- 'list-item': (props) => <Box component='li' {...props} />,
16
- 'list-item-child': (props) => <Box component='span' {...props} />,
17
- 'block-quote': (props) => <Box component='blockquote' {...props} />,
18
- iframe: (props) => {
19
- const { url, width, height, sx = [] } = props
20
- return (
21
- // todo add security attributes to iframe
22
- // todo make iframe responsive (generic IFrame component?)
23
- <Box
24
- component='iframe'
25
- src={url}
26
- loading='lazy'
27
- sx={[
28
- { aspectRatio: `${width} / ${height}`, width: '100%' },
29
- ...(Array.isArray(sx) ? sx : [sx]),
30
- ]}
31
- />
32
- )
33
- },
34
- image: ({ src, width, height, title, altText, mimeType, sx }) => (
35
- <Box sx={sx}>
36
- <Asset asset={{ url: src, alt: altText ?? title, width, height, mimeType }} />
37
- </Box>
38
- ),
39
- video: ({ src, width, height, title, mimeType, sx }) => (
40
- <Box sx={sx}>
41
- <Asset asset={{ url: src, alt: title, width, height, mimeType }} />
42
- </Box>
43
- ),
44
- link: ({ href, openInNewTab, ...props }) => (
45
- <Link href={href} underline='hover' {...props} target={openInNewTab ? '_blank' : undefined} />
46
- ),
47
- table: (props) => <Box component='table' {...props} />,
48
- table_head: (props) => <Box component='thead' {...props} />,
49
- table_header_cell: (props) => <Box component='th' {...props} />,
50
- table_body: (props) => <Box component='tbody' {...props} />,
51
- table_row: (props) => <Box component='tr' {...props} />,
52
- table_cell: (props) => <Box component='td' {...props} />,
53
- code: (props) => <Box component='code' {...props} />,
54
- bold: (props) => <Box component='strong' fontWeight='bold' {...props} />,
55
- italic: (props) => <Box component='em' fontStyle='italic' {...props} />,
56
- underlined: (props) => <Box component='span' {...props} />,
57
- class: (props) => <Box component='div' {...props} />,
58
- }
@@ -1,108 +0,0 @@
1
- import { SxRenderer } from './types'
2
-
3
- export const defaultSxRenderer: SxRenderer = {
4
- all: {
5
- '&:empty:not(iframe)': {
6
- display: 'none',
7
- },
8
- },
9
- first: {
10
- marginTop: 0,
11
- },
12
- last: {
13
- marginBottom: 0,
14
- },
15
- paragraph: {
16
- marginBottom: '1em',
17
- wordBreak: 'break-word',
18
- },
19
- 'heading-one': {
20
- marginTop: '0.5em',
21
- marginBottom: '0.5em',
22
- },
23
- 'heading-two': {
24
- marginTop: '0.5em',
25
- marginBottom: '0.5em',
26
- },
27
- 'heading-three': {
28
- marginTop: '0.5em',
29
- marginBottom: '0.5em',
30
- },
31
- 'heading-four': {
32
- marginTop: '0.5em',
33
- marginBottom: '0.5em',
34
- },
35
- 'heading-five': {
36
- marginTop: '0.5em',
37
- marginBottom: '0.5em',
38
- },
39
- image: {
40
- width: '100%',
41
- height: 'auto',
42
- },
43
- video: {
44
- width: '100%',
45
- height: 'auto',
46
- },
47
- 'block-quote': (theme) => ({
48
- paddingLeft: theme.spacings.sm,
49
- margin: `${theme.spacings.md} 0`,
50
- }),
51
- 'bulleted-list': {
52
- marginBottom: '1em',
53
- },
54
- 'numbered-list': {
55
- marginBottom: '1em',
56
- },
57
- code: {
58
- width: 'fit-content',
59
- maxWidth: '100%',
60
- padding: 5,
61
- overflow: 'scroll',
62
- },
63
- table: (theme) => ({
64
- display: 'table',
65
- width: '100%',
66
- borderSpacing: '2px',
67
- borderCollapse: 'collapse',
68
- marginTop: theme.spacings.md,
69
- marginBottom: theme.spacings.sm,
70
- '& thead, tbody': {
71
- '& td': {
72
- padding: '10px 20px',
73
- },
74
- },
75
- '& thead': {
76
- '& tr': {
77
- '& td': {
78
- '& p': {
79
- fontWeight: theme.typography.fontWeightBold,
80
- },
81
- },
82
- },
83
- },
84
- '& tbody': {
85
- display: 'table-row-group',
86
- verticalAlign: 'center',
87
- borderColor: 'inherit',
88
- '& tr': {
89
- '&:nth-of-type(odd)': {
90
- background: theme.palette.background.paper,
91
- },
92
- },
93
- '& td': {
94
- [theme.breakpoints.up('sm')]: {
95
- minWidth: '150px',
96
- },
97
- '& p': {},
98
- },
99
- },
100
- }),
101
- link: {
102
- wordBreak: 'break-word',
103
- },
104
- underlined: {
105
- textDecoration: 'underline',
106
- },
107
- iframe: {},
108
- }
@@ -1,11 +0,0 @@
1
- import { isElementNode, isTextNode } from './RichText'
2
- import { ElementOrTextNode } from './types'
3
-
4
- export function getNodeLength(node: ElementOrTextNode): number {
5
- if (isElementNode(node))
6
- return node.children.map(getNodeLength).reduce<number>((prev, curr) => prev + curr, 0)
7
-
8
- if (isTextNode(node)) return node.text.length
9
-
10
- return 0
11
- }
@@ -1,2 +0,0 @@
1
- export * from './RichText'
2
- export * from './getNodeLength'
@@ -1,117 +0,0 @@
1
- import { SxProps, Theme } from '@mui/material'
2
- import type { 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
- | 'list-item'
16
- | 'list-item-child'
17
- | 'table'
18
- | 'table_head'
19
- | 'table_header_cell'
20
- | 'table_body'
21
- | 'table_row'
22
- | 'table_cell'
23
- | 'code'
24
- | 'bold'
25
- | 'italic'
26
- | 'underlined'
27
-
28
- export type SimpleElement = {
29
- children: ElementOrTextNode[]
30
- type: LiteralUnion<BaseElementTypes, string>
31
- }
32
-
33
- export type TextNode = {
34
- text: string
35
- bold?: true
36
- italic?: true
37
- underlined?: true
38
- [key: string]: unknown
39
- }
40
-
41
- type LinkElement = {
42
- type: 'link'
43
- children: ElementOrTextNode[]
44
- href: string
45
- openInNewTab?: boolean
46
- }
47
-
48
- type ClassElement = {
49
- type: 'class'
50
- children: ElementOrTextNode[]
51
- className: string
52
- }
53
-
54
- type ImageElement = {
55
- type: 'image'
56
- children: ElementOrTextNode[]
57
- src: string
58
- title: string
59
- altText: string
60
- width: number
61
- height: number
62
- mimeType: string
63
- }
64
-
65
- type VideoElement = {
66
- type: 'image'
67
- children: ElementOrTextNode[]
68
- src: string
69
- title: string
70
- width: number
71
- height: number
72
- mimeType: string
73
- }
74
-
75
- type IframeElement = {
76
- type: 'iframe'
77
- children: ElementOrTextNode[]
78
- url: string
79
- width?: number
80
- height?: number
81
- }
82
-
83
- export type ElementNode =
84
- | SimpleElement
85
- | LinkElement
86
- | ImageElement
87
- | VideoElement
88
- | IframeElement
89
- | ClassElement
90
- export type ElementOrTextNode = ElementNode | TextNode
91
-
92
- type RendererBase = { sx?: SxProps<Theme>; children?: React.ReactNode }
93
- export type Renderer<P extends ElementNode> = (
94
- props: Omit<P, 'children' | 'type'> & RendererBase,
95
- ) => React.ReactElement | null
96
-
97
- export type Renderers = {
98
- [k in BaseElementTypes]: Renderer<SimpleElement>
99
- } & {
100
- link: Renderer<LinkElement>
101
- image: Renderer<ImageElement>
102
- video: Renderer<VideoElement>
103
- iframe: Renderer<IframeElement>
104
- class: Renderer<ClassElement>
105
- }
106
-
107
- export type SxRenderer = {
108
- [k in keyof Renderers | 'all' | 'first' | 'last']?: SxProps<Theme>
109
- }
110
-
111
- export type AdditionalProps = {
112
- renderers: Renderers
113
- sxRenderer: SxRenderer
114
- first?: boolean
115
- last?: boolean
116
- className?: string
117
- }
@@ -1,2 +0,0 @@
1
- export * from './RichText'
2
- export * from './Asset/Asset'
@@ -1,11 +0,0 @@
1
- query HygraphAllPages($first: Int = 100, $skip: Int) {
2
- pages(first: $first, skip: $skip) {
3
- url
4
- }
5
-
6
- pagesConnection {
7
- aggregate {
8
- count
9
- }
10
- }
11
- }
@@ -1,16 +0,0 @@
1
- fragment HygraphPage on Page {
2
- title
3
- metaTitle
4
- metaDescription
5
- metaRobots
6
- url
7
- author
8
- date
9
- relatedPages {
10
- title
11
- url
12
- }
13
- asset {
14
- ...Asset
15
- }
16
- }
@@ -1,7 +0,0 @@
1
- query HygraphPages($url: String!) {
2
- pages(where: { url: $url }) {
3
- id
4
- __typename
5
- ...HygraphPage
6
- }
7
- }
@@ -1,11 +0,0 @@
1
- query HygraphStaticPaths($pageSize: Int!, $skip: Int, $where: PageWhereInput) {
2
- pages(first: $pageSize, skip: $skip, where: $where) {
3
- url
4
- }
5
-
6
- pagesConnection {
7
- aggregate {
8
- count
9
- }
10
- }
11
- }
@@ -1,10 +0,0 @@
1
- fragment PageLink on PageLink {
2
- title
3
- url
4
- description {
5
- raw
6
- }
7
- asset {
8
- ...Asset
9
- }
10
- }