@graphcommerce/next-ui 4.14.0 → 4.16.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 +40 -0
- package/FramerScroller/SidebarGallery.tsx +3 -3
- package/JsonLd/JsonLd.tsx +10 -8
- package/JsonLd/safeJsonLdReplacer.ts +47 -0
- package/LayoutOverlay/test/LayoutOverlayDemo.tsx +1 -1
- package/Navigation/components/NavigationItem.tsx +51 -12
- package/Navigation/components/NavigationList.tsx +4 -3
- package/Navigation/components/NavigationOverlay.tsx +71 -16
- package/Navigation/components/NavigationProvider.tsx +7 -2
- package/Navigation/hooks/useNavigation.ts +2 -1
- package/Overlay/components/OverlayBase.tsx +4 -1
- package/RenderType/RenderType.tsx +7 -0
- package/RenderType/filterNonNullableKeys.ts +20 -0
- package/RenderType/index.ts +3 -0
- package/RenderType/nonNullable.ts +3 -0
- package/TextInputNumber/TextInputNumber.tsx +0 -1
- package/index.ts +1 -1
- package/package.json +2 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,45 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.16.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1573](https://github.com/graphcommerce-org/graphcommerce/pull/1573) [`1eb131766`](https://github.com/graphcommerce-org/graphcommerce/commit/1eb131766c32db6fcb0a8e83dba2c3d241658595) Thanks [@paales](https://github.com/paales)! - Solve issue where the products query would return multiple products while requesting a single url_key. Filter the result by findByTypename which finds the correct `typename` but also narrows the typescript type.
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- [#1573](https://github.com/graphcommerce-org/graphcommerce/pull/1573) [`87a188d6f`](https://github.com/graphcommerce-org/graphcommerce/commit/87a188d6f216b7f7b9ec95afbe74f1146cb07ce4) Thanks [@paales](https://github.com/paales)! - Sovle issue where changing images in the scroller causes issues rerendering
|
|
12
|
+
|
|
13
|
+
- Updated dependencies [[`87a188d6f`](https://github.com/graphcommerce-org/graphcommerce/commit/87a188d6f216b7f7b9ec95afbe74f1146cb07ce4)]:
|
|
14
|
+
- @graphcommerce/framer-scroller@2.1.27
|
|
15
|
+
|
|
16
|
+
## 4.15.1
|
|
17
|
+
|
|
18
|
+
### Patch Changes
|
|
19
|
+
|
|
20
|
+
- [#1570](https://github.com/graphcommerce-org/graphcommerce/pull/1570) [`a88f166f0`](https://github.com/graphcommerce-org/graphcommerce/commit/a88f166f0115c58254fe47171da51a5850658a32) Thanks [@paales](https://github.com/paales)! - Solve issue where chrome would report duplicate ids
|
|
21
|
+
|
|
22
|
+
- Updated dependencies []:
|
|
23
|
+
- @graphcommerce/framer-scroller@2.1.26
|
|
24
|
+
|
|
25
|
+
## 4.15.0
|
|
26
|
+
|
|
27
|
+
### Minor Changes
|
|
28
|
+
|
|
29
|
+
- [#1566](https://github.com/graphcommerce-org/graphcommerce/pull/1566) [`e167992df`](https://github.com/graphcommerce-org/graphcommerce/commit/e167992dfdc6964a392af719667f8a188626ab1b) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Introduced `@graphcommerce/next-ui/navigation` component.
|
|
30
|
+
|
|
31
|
+
- Navigation is always present in the DOM
|
|
32
|
+
- Configurable in LayoutNavigation.tsx
|
|
33
|
+
- Show categories directly, or nest them in a 'products' button
|
|
34
|
+
- Choose prefered mouseEvent: click or hover
|
|
35
|
+
|
|
36
|
+
* [#1566](https://github.com/graphcommerce-org/graphcommerce/pull/1566) [`9c2504b4e`](https://github.com/graphcommerce-org/graphcommerce/commit/9c2504b4ed75f41d3003c4d3339814010e85e37e) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - publish navigation
|
|
37
|
+
|
|
38
|
+
### Patch Changes
|
|
39
|
+
|
|
40
|
+
- Updated dependencies []:
|
|
41
|
+
- @graphcommerce/framer-scroller@2.1.25
|
|
42
|
+
|
|
3
43
|
## 4.14.0
|
|
4
44
|
|
|
5
45
|
### Minor Changes
|
|
@@ -211,7 +211,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
211
211
|
))}
|
|
212
212
|
</Scroller>
|
|
213
213
|
<MotionBox
|
|
214
|
-
layout
|
|
214
|
+
layout='position'
|
|
215
215
|
layoutDependency={zoomed}
|
|
216
216
|
className={classes.topRight}
|
|
217
217
|
sx={{
|
|
@@ -293,7 +293,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
293
293
|
}}
|
|
294
294
|
>
|
|
295
295
|
<ScrollerDots
|
|
296
|
-
layout
|
|
296
|
+
layout='position'
|
|
297
297
|
layoutDependency={zoomed}
|
|
298
298
|
sx={{ backgroundColor: 'background.paper', boxShadow: 6 }}
|
|
299
299
|
/>
|
|
@@ -328,7 +328,7 @@ export function SidebarGallery(props: SidebarGalleryProps) {
|
|
|
328
328
|
]}
|
|
329
329
|
>
|
|
330
330
|
<MotionBox
|
|
331
|
-
layout
|
|
331
|
+
layout='position'
|
|
332
332
|
layoutDependency={zoomed}
|
|
333
333
|
className={classes.sidebar}
|
|
334
334
|
sx={{
|
package/JsonLd/JsonLd.tsx
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
import Head from 'next/head'
|
|
2
|
-
import {
|
|
3
|
-
import { Thing, WithContext } from 'schema-dts'
|
|
2
|
+
import { safeJsonLdReplacer } from './safeJsonLdReplacer'
|
|
4
3
|
|
|
5
4
|
export * as SchemaDts from 'schema-dts'
|
|
6
5
|
|
|
7
|
-
export
|
|
8
|
-
item:
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function JsonLd<T extends Thing>(props: JsonLdProps<T>) {
|
|
6
|
+
export function JsonLd<T extends { '@type': string }>(props: {
|
|
7
|
+
item: T & { '@context': 'https://schema.org' }
|
|
8
|
+
}) {
|
|
12
9
|
const { item } = props
|
|
13
10
|
|
|
14
11
|
return (
|
|
15
12
|
<Head>
|
|
16
|
-
<script
|
|
13
|
+
<script
|
|
14
|
+
key='jsonld'
|
|
15
|
+
type='application/ld+json'
|
|
16
|
+
// eslint-disable-next-line react/no-danger
|
|
17
|
+
dangerouslySetInnerHTML={{ __html: JSON.stringify(item, safeJsonLdReplacer) }}
|
|
18
|
+
/>
|
|
17
19
|
</Head>
|
|
18
20
|
)
|
|
19
21
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
type JsonValueScalar = string | boolean | number
|
|
2
|
+
type JsonValue = JsonValueScalar | Array<JsonValue> | { [key: string]: JsonValue }
|
|
3
|
+
type JsonReplacer = (_: string, value: JsonValue) => JsonValue | undefined
|
|
4
|
+
|
|
5
|
+
const ESCAPE_ENTITIES = Object.freeze({
|
|
6
|
+
'&': '&',
|
|
7
|
+
'<': '<',
|
|
8
|
+
'>': '>',
|
|
9
|
+
'"': '"',
|
|
10
|
+
"'": ''',
|
|
11
|
+
})
|
|
12
|
+
const ESCAPE_REGEX = new RegExp(`[${Object.keys(ESCAPE_ENTITIES).join('')}]`, 'g')
|
|
13
|
+
const ESCAPE_REPLACER = (t: string): string => ESCAPE_ENTITIES[t as keyof typeof ESCAPE_ENTITIES]
|
|
14
|
+
|
|
15
|
+
// Utility: Assert never
|
|
16
|
+
function isNever(_: never): void {}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* A replacer for JSON.stringify to strip JSON-LD of illegal HTML entities per
|
|
20
|
+
* https://www.w3.org/TR/json-ld11/#restrictions-for-contents-of-json-ld-script-elements
|
|
21
|
+
*/
|
|
22
|
+
export const safeJsonLdReplacer: JsonReplacer = (
|
|
23
|
+
() =>
|
|
24
|
+
// Replace per https://www.w3.org/TR/json-ld11/#restrictions-for-contents-of-json-ld-script-elements
|
|
25
|
+
// Solution from https://stackoverflow.com/a/5499821/864313
|
|
26
|
+
(_: string, value: JsonValue): JsonValue | undefined => {
|
|
27
|
+
switch (typeof value) {
|
|
28
|
+
case 'object':
|
|
29
|
+
// Omit null values.
|
|
30
|
+
if (value === null) return undefined
|
|
31
|
+
return value // JSON.stringify will recursively call replacer.
|
|
32
|
+
case 'number':
|
|
33
|
+
case 'boolean':
|
|
34
|
+
case 'bigint':
|
|
35
|
+
return value // These values are not risky.
|
|
36
|
+
case 'string':
|
|
37
|
+
return value.replace(ESCAPE_REGEX, ESCAPE_REPLACER)
|
|
38
|
+
default: {
|
|
39
|
+
// We shouldn't expect other types.
|
|
40
|
+
isNever(value)
|
|
41
|
+
|
|
42
|
+
// JSON.stringify will remove this element.
|
|
43
|
+
return undefined
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
)()
|
|
@@ -3,7 +3,7 @@ import { LayoutOverlay, LayoutOverlayProps } from '../components/LayoutOverlay'
|
|
|
3
3
|
|
|
4
4
|
export type LayoutOverlayState = Omit<
|
|
5
5
|
LayoutOverlayProps,
|
|
6
|
-
'children' | 'sx' | 'sxBackdrop' | 'mdSpacingTop' | 'smSpacingTop'
|
|
6
|
+
'children' | 'sx' | 'sxBackdrop' | 'mdSpacingTop' | 'smSpacingTop' | 'overlayPaneProps'
|
|
7
7
|
>
|
|
8
8
|
|
|
9
9
|
export function useLayoutState() {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-use-before-define */
|
|
2
|
-
import { Box, ListItemButton, styled, useEventCallback } from '@mui/material'
|
|
2
|
+
import { Box, ListItemButton, styled, Theme, useEventCallback, useMediaQuery } from '@mui/material'
|
|
3
3
|
import PageLink from 'next/link'
|
|
4
|
+
import { useEffect } from 'react'
|
|
4
5
|
import { IconSvg } from '../../IconSvg'
|
|
5
6
|
import { extendableComponent } from '../../Styles/extendableComponent'
|
|
6
7
|
import { iconChevronRight } from '../../icons'
|
|
@@ -26,7 +27,12 @@ type NavigationItemProps = NavigationNode & {
|
|
|
26
27
|
parentPath: NavigationPath
|
|
27
28
|
idx: number
|
|
28
29
|
NavigationList: typeof NavigationList
|
|
29
|
-
} & OwnerState
|
|
30
|
+
} & OwnerState &
|
|
31
|
+
mouseEventPref
|
|
32
|
+
|
|
33
|
+
export type mouseEventPref = {
|
|
34
|
+
mouseEvent: 'click' | 'hover'
|
|
35
|
+
}
|
|
30
36
|
|
|
31
37
|
const componentName = 'NavigationItem'
|
|
32
38
|
const parts = ['li', 'ul', 'item'] as const
|
|
@@ -39,10 +45,10 @@ const { withState } = extendableComponent<OwnerState, typeof componentName, type
|
|
|
39
45
|
const NavigationLI = styled('li')({ display: 'contents' })
|
|
40
46
|
|
|
41
47
|
export function NavigationItem(props: NavigationItemProps) {
|
|
42
|
-
const { id, parentPath, idx, first, last, NavigationList } = props
|
|
48
|
+
const { id, parentPath, idx, first, last, NavigationList, mouseEvent } = props
|
|
43
49
|
|
|
44
50
|
const row = idx + 1
|
|
45
|
-
const { selected, select, hideRootOnNavigate, onClose } = useNavigation()
|
|
51
|
+
const { selected, select, hideRootOnNavigate, onClose, animating } = useNavigation()
|
|
46
52
|
|
|
47
53
|
const itemPath = [...parentPath, id]
|
|
48
54
|
const isSelected = selected.slice(0, itemPath.length).join('/') === itemPath.join('/')
|
|
@@ -59,6 +65,8 @@ export function NavigationItem(props: NavigationItemProps) {
|
|
|
59
65
|
onClose?.(e, href)
|
|
60
66
|
})
|
|
61
67
|
|
|
68
|
+
const isDesktop = useMediaQuery<Theme>((theme) => theme.breakpoints.up('md'))
|
|
69
|
+
|
|
62
70
|
if (isNavigationButton(props)) {
|
|
63
71
|
const { childItems, name } = props
|
|
64
72
|
return (
|
|
@@ -66,18 +74,44 @@ export function NavigationItem(props: NavigationItemProps) {
|
|
|
66
74
|
<ListItemButton
|
|
67
75
|
className={classes.item}
|
|
68
76
|
role='button'
|
|
69
|
-
sx={
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
77
|
+
sx={[
|
|
78
|
+
(theme) => ({
|
|
79
|
+
gridRowStart: row,
|
|
80
|
+
gridColumnStart: column,
|
|
81
|
+
gap: theme.spacings.xxs,
|
|
82
|
+
display: hideItem ? 'none' : 'flex',
|
|
83
|
+
'&.Mui-disabled': {
|
|
84
|
+
opacity: 1,
|
|
85
|
+
background: theme.palette.action.hover,
|
|
86
|
+
},
|
|
87
|
+
}),
|
|
88
|
+
mouseEvent === 'hover'
|
|
89
|
+
? {
|
|
90
|
+
'&.Mui-disabled': {
|
|
91
|
+
cursor: 'pointer',
|
|
92
|
+
pointerEvents: 'auto',
|
|
93
|
+
},
|
|
94
|
+
}
|
|
95
|
+
: {},
|
|
96
|
+
]}
|
|
75
97
|
disabled={isSelected}
|
|
76
98
|
tabIndex={selected.join(',').includes(parentPath.join(',')) ? undefined : -1}
|
|
77
99
|
onClick={(e) => {
|
|
78
100
|
e.preventDefault()
|
|
79
|
-
if (!isSelected)
|
|
101
|
+
if (!isSelected && animating.current === false) {
|
|
102
|
+
select(itemPath)
|
|
103
|
+
}
|
|
80
104
|
}}
|
|
105
|
+
onMouseEnter={
|
|
106
|
+
itemPath.length > 1 && mouseEvent === 'hover'
|
|
107
|
+
? (e) => {
|
|
108
|
+
if (isDesktop && animating.current === false && !isSelected) {
|
|
109
|
+
e.preventDefault()
|
|
110
|
+
setTimeout(() => select(itemPath), 0)
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
: undefined
|
|
114
|
+
}
|
|
81
115
|
>
|
|
82
116
|
<Box
|
|
83
117
|
component='span'
|
|
@@ -93,7 +127,12 @@ export function NavigationItem(props: NavigationItemProps) {
|
|
|
93
127
|
<IconSvg src={iconChevronRight} sx={{ flexShrink: 0 }} />
|
|
94
128
|
</ListItemButton>
|
|
95
129
|
|
|
96
|
-
<NavigationList
|
|
130
|
+
<NavigationList
|
|
131
|
+
items={childItems}
|
|
132
|
+
selected={isSelected}
|
|
133
|
+
parentPath={itemPath}
|
|
134
|
+
mouseEvent={mouseEvent}
|
|
135
|
+
/>
|
|
97
136
|
</NavigationLI>
|
|
98
137
|
)
|
|
99
138
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { styled } from '@mui/material'
|
|
2
2
|
import { extendableComponent } from '../../Styles/extendableComponent'
|
|
3
3
|
import { NavigationNode, NavigationPath } from '../hooks/useNavigation'
|
|
4
|
-
import { NavigationItem } from './NavigationItem'
|
|
4
|
+
import { NavigationItem, mouseEventPref } from './NavigationItem'
|
|
5
5
|
|
|
6
6
|
const NavigationUList = styled('ul')({})
|
|
7
7
|
|
|
@@ -9,7 +9,7 @@ type NavigationItemsProps = {
|
|
|
9
9
|
parentPath?: NavigationPath
|
|
10
10
|
items: NavigationNode[]
|
|
11
11
|
selected?: boolean
|
|
12
|
-
}
|
|
12
|
+
} & mouseEventPref
|
|
13
13
|
|
|
14
14
|
type OwnerState = {
|
|
15
15
|
column: number
|
|
@@ -23,7 +23,7 @@ const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>
|
|
|
23
23
|
// const parts = ['li', 'ul', 'item'] as const
|
|
24
24
|
|
|
25
25
|
export function NavigationList(props: NavigationItemsProps) {
|
|
26
|
-
const { items, parentPath = [], selected = false } = props
|
|
26
|
+
const { items, parentPath = [], selected = false, mouseEvent } = props
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
29
|
<NavigationUList
|
|
@@ -43,6 +43,7 @@ export function NavigationList(props: NavigationItemsProps) {
|
|
|
43
43
|
first={idx === 0}
|
|
44
44
|
last={idx === items.length - 1}
|
|
45
45
|
column={0}
|
|
46
|
+
mouseEvent={mouseEvent}
|
|
46
47
|
/>
|
|
47
48
|
))}
|
|
48
49
|
</NavigationUList>
|
|
@@ -3,6 +3,7 @@ import { i18n } from '@lingui/core'
|
|
|
3
3
|
import { Trans } from '@lingui/react'
|
|
4
4
|
import { Box, Fab, SxProps, Theme, useEventCallback, useMediaQuery } from '@mui/material'
|
|
5
5
|
import { m } from 'framer-motion'
|
|
6
|
+
import { useState } from 'react'
|
|
6
7
|
import { IconSvg, useIconSvgSize } from '../../IconSvg'
|
|
7
8
|
import { LayoutHeaderContent } from '../../Layout/components/LayoutHeaderContent'
|
|
8
9
|
import { LayoutTitle } from '../../Layout/components/LayoutTitle'
|
|
@@ -18,14 +19,26 @@ import {
|
|
|
18
19
|
NavigationNodeHref,
|
|
19
20
|
useNavigation,
|
|
20
21
|
} from '../hooks/useNavigation'
|
|
22
|
+
import { mouseEventPref } from './NavigationItem'
|
|
21
23
|
import { NavigationList } from './NavigationList'
|
|
22
24
|
|
|
25
|
+
type LayoutOverlayVariant = 'left' | 'bottom' | 'right'
|
|
26
|
+
type LayoutOverlaySize = 'floating' | 'minimal' | 'full'
|
|
27
|
+
type LayoutOverlayAlign = 'start' | 'end' | 'center' | 'stretch'
|
|
28
|
+
|
|
23
29
|
type NavigationOverlayProps = {
|
|
24
30
|
active: boolean
|
|
25
31
|
sx?: SxProps<Theme>
|
|
26
32
|
stretchColumns?: boolean
|
|
27
|
-
|
|
28
|
-
|
|
33
|
+
variantSm: LayoutOverlayVariant
|
|
34
|
+
variantMd: LayoutOverlayVariant
|
|
35
|
+
sizeSm?: LayoutOverlaySize
|
|
36
|
+
sizeMd?: LayoutOverlaySize
|
|
37
|
+
justifySm?: LayoutOverlayAlign
|
|
38
|
+
justifyMd?: LayoutOverlayAlign
|
|
39
|
+
itemWidthSm?: string
|
|
40
|
+
itemWidthMd?: string
|
|
41
|
+
} & mouseEventPref
|
|
29
42
|
|
|
30
43
|
function findCurrent(
|
|
31
44
|
items: NavigationContextType['items'],
|
|
@@ -55,8 +68,21 @@ const parts = ['root', 'navigation', 'header', 'column'] as const
|
|
|
55
68
|
const { classes } = extendableComponent(componentName, parts)
|
|
56
69
|
|
|
57
70
|
export function NavigationOverlay(props: NavigationOverlayProps) {
|
|
58
|
-
const {
|
|
59
|
-
|
|
71
|
+
const {
|
|
72
|
+
active,
|
|
73
|
+
sx,
|
|
74
|
+
stretchColumns,
|
|
75
|
+
variantMd,
|
|
76
|
+
variantSm,
|
|
77
|
+
justifyMd,
|
|
78
|
+
justifySm,
|
|
79
|
+
sizeMd,
|
|
80
|
+
sizeSm,
|
|
81
|
+
itemWidthSm,
|
|
82
|
+
itemWidthMd,
|
|
83
|
+
mouseEvent,
|
|
84
|
+
} = props
|
|
85
|
+
const { selected, select, items, onClose, animating } = useNavigation()
|
|
60
86
|
|
|
61
87
|
const fabSize = useFabSize('responsive')
|
|
62
88
|
const svgSize = useIconSvgSize('large')
|
|
@@ -74,12 +100,20 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
|
|
|
74
100
|
className={classes.root}
|
|
75
101
|
active={active}
|
|
76
102
|
onClosed={onClose}
|
|
77
|
-
variantSm=
|
|
78
|
-
sizeSm=
|
|
79
|
-
justifySm=
|
|
80
|
-
variantMd=
|
|
81
|
-
sizeMd=
|
|
82
|
-
justifyMd=
|
|
103
|
+
variantSm={variantSm}
|
|
104
|
+
sizeSm={sizeSm}
|
|
105
|
+
justifySm={justifySm}
|
|
106
|
+
variantMd={variantMd}
|
|
107
|
+
sizeMd={sizeMd}
|
|
108
|
+
justifyMd={justifyMd}
|
|
109
|
+
overlayPaneProps={{
|
|
110
|
+
onLayoutAnimationStart: () => {
|
|
111
|
+
animating.current = true
|
|
112
|
+
},
|
|
113
|
+
onLayoutAnimationComplete: () => {
|
|
114
|
+
animating.current = false
|
|
115
|
+
},
|
|
116
|
+
}}
|
|
83
117
|
sx={{
|
|
84
118
|
zIndex: 'drawer',
|
|
85
119
|
'& .LayoutOverlayBase-overlayPane': {
|
|
@@ -151,14 +185,35 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
|
|
|
151
185
|
sx={(theme) => ({
|
|
152
186
|
display: 'grid',
|
|
153
187
|
alignItems: !stretchColumns ? 'start' : undefined,
|
|
154
|
-
|
|
188
|
+
'& .NavigationItem-item': {
|
|
189
|
+
// eslint-disable-next-line no-nested-ternary
|
|
190
|
+
width: itemWidthMd
|
|
191
|
+
? selected.length >= 1
|
|
192
|
+
? `calc(${itemWidthMd} + 1px)`
|
|
193
|
+
: itemWidthMd
|
|
194
|
+
: 'auto',
|
|
195
|
+
},
|
|
155
196
|
[theme.breakpoints.down('md')]: {
|
|
197
|
+
width:
|
|
198
|
+
sizeSm !== 'floating'
|
|
199
|
+
? `calc(${itemWidthSm || '100vw'} + ${selected.length}px)`
|
|
200
|
+
: `calc(${itemWidthSm || '100vw'} - ${theme.page.horizontal} - ${
|
|
201
|
+
theme.page.horizontal
|
|
202
|
+
})`,
|
|
203
|
+
minWidth: 200,
|
|
156
204
|
overflow: 'hidden',
|
|
157
205
|
scrollSnapType: 'x mandatory',
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
206
|
+
'& .NavigationItem-item': {
|
|
207
|
+
width:
|
|
208
|
+
sizeSm !== 'floating'
|
|
209
|
+
? `calc(${itemWidthSm || '100vw'} - ${theme.spacings.md} - ${
|
|
210
|
+
theme.spacings.md
|
|
211
|
+
} + ${selected.length}px)`
|
|
212
|
+
: `calc(${itemWidthSm || '100vw'} - ${theme.spacings.md} - ${
|
|
213
|
+
theme.spacings.md
|
|
214
|
+
} - ${theme.page.horizontal} - ${theme.page.horizontal})`,
|
|
215
|
+
minWidth: `calc(${200}px - ${theme.spacings.md} - ${theme.spacings.md})`,
|
|
216
|
+
},
|
|
162
217
|
},
|
|
163
218
|
})}
|
|
164
219
|
>
|
|
@@ -228,7 +283,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
|
|
|
228
283
|
/>
|
|
229
284
|
)}
|
|
230
285
|
|
|
231
|
-
<NavigationList items={items} selected />
|
|
286
|
+
<NavigationList items={items} selected mouseEvent={mouseEvent} />
|
|
232
287
|
</Box>
|
|
233
288
|
</Box>
|
|
234
289
|
</MotionDiv>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEventCallback } from '@mui/material'
|
|
2
2
|
import { MotionConfig } from 'framer-motion'
|
|
3
|
-
import { useState, useMemo } from 'react'
|
|
3
|
+
import { useState, useMemo, SetStateAction, useRef } from 'react'
|
|
4
4
|
import { isElement } from 'react-is'
|
|
5
5
|
import {
|
|
6
6
|
NavigationNode,
|
|
@@ -16,6 +16,8 @@ export type NavigationProviderProps = {
|
|
|
16
16
|
closeAfterNavigate?: boolean
|
|
17
17
|
children?: React.ReactNode
|
|
18
18
|
animationDuration?: number
|
|
19
|
+
selected: NavigationPath
|
|
20
|
+
setSelected: (value: SetStateAction<NavigationPath>) => void
|
|
19
21
|
onChange?: NavigationSelect
|
|
20
22
|
onClose?: NavigationContextType['onClose']
|
|
21
23
|
}
|
|
@@ -31,9 +33,11 @@ export function NavigationProvider(props: NavigationProviderProps) {
|
|
|
31
33
|
animationDuration = 0.275,
|
|
32
34
|
children,
|
|
33
35
|
onClose: onCloseUnstable,
|
|
36
|
+
selected,
|
|
37
|
+
setSelected,
|
|
34
38
|
} = props
|
|
35
39
|
|
|
36
|
-
const
|
|
40
|
+
const animating = useRef(false)
|
|
37
41
|
|
|
38
42
|
const select = useEventCallback((incomming: NavigationPath) => {
|
|
39
43
|
setSelected(incomming)
|
|
@@ -50,6 +54,7 @@ export function NavigationProvider(props: NavigationProviderProps) {
|
|
|
50
54
|
hideRootOnNavigate,
|
|
51
55
|
selected,
|
|
52
56
|
select,
|
|
57
|
+
animating,
|
|
53
58
|
items: items
|
|
54
59
|
.map((item, index) => (isElement(item) ? { id: item.key ?? index, component: item } : item))
|
|
55
60
|
.filter(nonNullable),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createContext, useContext } from 'react'
|
|
1
|
+
import { createContext, MutableRefObject, SetStateAction, useContext } from 'react'
|
|
2
2
|
|
|
3
3
|
export type NavigationId = string | number
|
|
4
4
|
export type NavigationPath = NavigationId[]
|
|
@@ -17,6 +17,7 @@ export type NavigationContextType = {
|
|
|
17
17
|
items: NavigationNode[]
|
|
18
18
|
hideRootOnNavigate: boolean
|
|
19
19
|
onClose: NavigationOnClose
|
|
20
|
+
animating: MutableRefObject<boolean>
|
|
20
21
|
}
|
|
21
22
|
|
|
22
23
|
type NavigationNodeBase = {
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
useIsomorphicLayoutEffect,
|
|
6
6
|
} from '@graphcommerce/framer-utils'
|
|
7
7
|
import { Box, styled, SxProps, Theme, useTheme, useThemeProps } from '@mui/material'
|
|
8
|
-
import { m, useDomEvent, useMotionValue, useTransform } from 'framer-motion'
|
|
8
|
+
import { m, MotionProps, useDomEvent, useMotionValue, useTransform } from 'framer-motion'
|
|
9
9
|
import React, { useCallback, useEffect, useRef } from 'react'
|
|
10
10
|
import { LayoutProvider } from '../../Layout/components/LayoutProvider'
|
|
11
11
|
import { ExtendableComponent, extendableComponent } from '../../Styles'
|
|
@@ -40,6 +40,7 @@ export type LayoutOverlayBaseProps = {
|
|
|
40
40
|
offsetPageY: number
|
|
41
41
|
isPresent: boolean
|
|
42
42
|
safeToRemove: (() => void) | null | undefined
|
|
43
|
+
overlayPaneProps?: MotionProps
|
|
43
44
|
} & StyleProps &
|
|
44
45
|
OverridableProps
|
|
45
46
|
|
|
@@ -86,6 +87,7 @@ export function OverlayBase(incommingProps: LayoutOverlayBaseProps) {
|
|
|
86
87
|
offsetPageY,
|
|
87
88
|
isPresent,
|
|
88
89
|
safeToRemove,
|
|
90
|
+
overlayPaneProps,
|
|
89
91
|
} = props
|
|
90
92
|
|
|
91
93
|
const th = useTheme()
|
|
@@ -367,6 +369,7 @@ export function OverlayBase(incommingProps: LayoutOverlayBaseProps) {
|
|
|
367
369
|
})}
|
|
368
370
|
>
|
|
369
371
|
<MotionDiv
|
|
372
|
+
{...overlayPaneProps}
|
|
370
373
|
layout
|
|
371
374
|
className={classes.overlayPane}
|
|
372
375
|
sx={(theme) => ({
|
|
@@ -38,3 +38,10 @@ export function RenderType<
|
|
|
38
38
|
|
|
39
39
|
return <TypeItem {...typeItemProps} __typename={__typename} />
|
|
40
40
|
}
|
|
41
|
+
|
|
42
|
+
export function findByTypename<T extends TypeObject, Typename extends T['__typename']>(
|
|
43
|
+
type: (T | undefined | null)[] | undefined | null,
|
|
44
|
+
typename: Typename,
|
|
45
|
+
): FilterTypeByTypename<T, Typename> {
|
|
46
|
+
return type?.find((item) => item?.__typename === typename) as FilterTypeByTypename<T, Typename>
|
|
47
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { OptionalKeysOf, Simplify } from 'type-fest'
|
|
2
|
+
|
|
3
|
+
export function filterNonNullableKeys<
|
|
4
|
+
T extends Record<string, unknown>,
|
|
5
|
+
Keys extends OptionalKeysOf<T>,
|
|
6
|
+
>(items: (T | null | undefined)[] | null | undefined, values: Keys[]) {
|
|
7
|
+
if (!items) return []
|
|
8
|
+
|
|
9
|
+
type ResultWithRequired = Simplify<
|
|
10
|
+
Omit<T, Keys> & {
|
|
11
|
+
[K in Keys]: NonNullable<T[K]>
|
|
12
|
+
}
|
|
13
|
+
>
|
|
14
|
+
|
|
15
|
+
const result = items.filter(
|
|
16
|
+
(item) => item !== null && typeof item !== 'undefined' && values.every((v) => item?.[v]),
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
return result as ResultWithRequired[]
|
|
20
|
+
}
|
package/index.ts
CHANGED
|
@@ -38,7 +38,7 @@ export * from './Page'
|
|
|
38
38
|
export * from './PageLoadIndicator/PageLoadIndicator'
|
|
39
39
|
export * from './PageMeta/PageMeta'
|
|
40
40
|
export * from './Pagination/Pagination'
|
|
41
|
-
export * from './RenderType
|
|
41
|
+
export * from './RenderType'
|
|
42
42
|
export * from './Row'
|
|
43
43
|
export * from './SectionContainer/SectionContainer'
|
|
44
44
|
export * from './SectionHeader/SectionHeader'
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/next-ui",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "4.
|
|
5
|
+
"version": "4.16.0",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"sideEffects": false,
|
|
@@ -20,12 +20,11 @@
|
|
|
20
20
|
"@emotion/server": "^11.4.0",
|
|
21
21
|
"@emotion/styled": "^11.9.3",
|
|
22
22
|
"@graphcommerce/framer-next-pages": "3.2.4",
|
|
23
|
-
"@graphcommerce/framer-scroller": "2.1.
|
|
23
|
+
"@graphcommerce/framer-scroller": "2.1.27",
|
|
24
24
|
"@graphcommerce/framer-utils": "3.1.4",
|
|
25
25
|
"@graphcommerce/image": "3.1.7",
|
|
26
26
|
"cookie": "^0.5.0",
|
|
27
27
|
"react-is": "^18.2.0",
|
|
28
|
-
"react-schemaorg": "^2.0.0",
|
|
29
28
|
"schema-dts": "^1.1.0"
|
|
30
29
|
},
|
|
31
30
|
"peerDependencies": {
|