@graphcommerce/next-ui 4.19.0 → 4.22.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.
Files changed (41) hide show
  1. package/ActionCard/ActionCard.tsx +46 -12
  2. package/ActionCard/ActionCardList.tsx +17 -15
  3. package/ActionCard/ActionCardListForm.tsx +1 -2
  4. package/AnimatedRow/AnimatedRow.tsx +3 -3
  5. package/Blog/BlogHeader/BlogHeader.tsx +7 -1
  6. package/Blog/BlogListItem/BlogListItem.tsx +5 -1
  7. package/Blog/BlogTags/BlogTag.tsx +2 -3
  8. package/CHANGELOG.md +57 -0
  9. package/Footer/Footer.tsx +3 -2
  10. package/Form/Form.tsx +7 -1
  11. package/Form/FormActions.tsx +1 -1
  12. package/FramerScroller/SidebarGallery.tsx +1 -5
  13. package/IconSvg/IconSvg.tsx +4 -4
  14. package/Layout/components/LayoutHeaderClose.tsx +2 -0
  15. package/Layout/components/LayoutHeaderContent.tsx +3 -1
  16. package/LayoutDefault/components/LayoutDefault.tsx +3 -3
  17. package/LayoutOverlay/components/LayoutOverlay.tsx +2 -1
  18. package/LayoutParts/DesktopHeaderBadge.tsx +3 -3
  19. package/Navigation/components/NavigationItem.tsx +31 -17
  20. package/Navigation/components/NavigationList.tsx +21 -15
  21. package/Navigation/components/NavigationOverlay.tsx +48 -27
  22. package/Navigation/components/NavigationProvider.tsx +12 -30
  23. package/Navigation/hooks/useNavigation.ts +33 -6
  24. package/Overlay/components/Overlay.tsx +1 -2
  25. package/Overlay/components/OverlayBase.tsx +27 -23
  26. package/Overlay/hooks/useOverlayPosition.ts +6 -1
  27. package/Row/HeroBanner/HeroBanner.tsx +7 -2
  28. package/Row/ImageText/ImageText.tsx +10 -3
  29. package/Row/ImageTextBoxed/ImageTextBoxed.tsx +7 -1
  30. package/Row/ParagraphWithSidebarSlide/ParagraphWithSidebarSlide.tsx +4 -2
  31. package/Row/SpecialBanner/SpecialBanner.tsx +10 -2
  32. package/Snackbar/MessageSnackbarImpl.tsx +9 -5
  33. package/Stepper/Stepper.tsx +1 -1
  34. package/Styles/breakpointVal.tsx +1 -1
  35. package/TextInputNumber/TextInputNumber.tsx +5 -4
  36. package/Theme/MuiButton.ts +12 -3
  37. package/Theme/MuiFab.ts +2 -2
  38. package/ToggleButton/ToggleButton.tsx +15 -5
  39. package/hooks/index.ts +1 -0
  40. package/hooks/useMemoDeep.ts +15 -0
  41. package/package.json +6 -6
@@ -1,38 +1,40 @@
1
1
  import { styled } from '@mui/material'
2
+ import React from 'react'
2
3
  import { extendableComponent } from '../../Styles/extendableComponent'
3
- import { NavigationNode, NavigationPath } from '../hooks/useNavigation'
4
+ import { NavigationNode } from '../hooks/useNavigation'
4
5
  import { NavigationItem, mouseEventPref } from './NavigationItem'
5
6
 
6
- const NavigationUList = styled('ul')({})
7
+ const NavigationUList = styled('ul')({
8
+ display: 'block',
9
+ position: 'absolute',
10
+ left: '-10000px',
11
+ top: '-10000px',
12
+ '&.selected': {
13
+ display: 'contents',
14
+ },
15
+ })
7
16
 
8
17
  type NavigationItemsProps = {
9
- parentPath?: NavigationPath
18
+ parentPath?: string
10
19
  items: NavigationNode[]
11
20
  selected?: boolean
12
21
  } & mouseEventPref
13
22
 
14
23
  type OwnerState = {
15
24
  column: number
25
+ selected: boolean
16
26
  }
17
27
 
18
28
  const name = 'NavigationList'
19
29
  const parts = ['root'] as const
20
30
  const { withState } = extendableComponent<OwnerState, typeof name, typeof parts>(name, parts)
21
31
 
22
- // const componentName = 'NavigationItem'
23
- // const parts = ['li', 'ul', 'item'] as const
24
-
25
- export function NavigationList(props: NavigationItemsProps) {
26
- const { items, parentPath = [], selected = false, mouseEvent } = props
32
+ export const NavigationList = React.memo<NavigationItemsProps>((props) => {
33
+ const { items, parentPath = '', selected = false, mouseEvent } = props
27
34
 
35
+ const classes = withState({ column: 0, selected })
28
36
  return (
29
- <NavigationUList
30
- sx={[
31
- { display: 'block', position: 'absolute', left: '-10000px', top: '-10000px' },
32
- selected && { display: 'contents' },
33
- ]}
34
- className={withState({ column: 0 }).root}
35
- >
37
+ <NavigationUList className={classes.root}>
36
38
  {items.map((item, idx) => (
37
39
  <NavigationItem
38
40
  NavigationList={NavigationList}
@@ -48,4 +50,8 @@ export function NavigationList(props: NavigationItemsProps) {
48
50
  ))}
49
51
  </NavigationUList>
50
52
  )
53
+ })
54
+
55
+ if (process.env.NODE_ENV !== 'production') {
56
+ NavigationList.displayName = 'NavigationList'
51
57
  }
@@ -1,9 +1,10 @@
1
1
  import styled from '@emotion/styled'
2
+ import { useMotionValueValue, useMotionSelector } from '@graphcommerce/framer-utils'
2
3
  import { i18n } from '@lingui/core'
3
4
  import { Trans } from '@lingui/react'
4
5
  import { Box, Fab, SxProps, Theme, useEventCallback, useMediaQuery } from '@mui/material'
5
- import { m } from 'framer-motion'
6
- import { useEffect, useState } from 'react'
6
+ import { m, useMotionValue } from 'framer-motion'
7
+ import React, { startTransition, useEffect, useRef, useState } from 'react'
7
8
  import { IconSvg, useIconSvgSize } from '../../IconSvg'
8
9
  import { LayoutHeaderContent } from '../../Layout/components/LayoutHeaderContent'
9
10
  import { LayoutTitle } from '../../Layout/components/LayoutTitle'
@@ -17,6 +18,7 @@ import {
17
18
  NavigationContextType,
18
19
  NavigationNodeButton,
19
20
  NavigationNodeHref,
21
+ NavigationPath,
20
22
  useNavigation,
21
23
  } from '../hooks/useNavigation'
22
24
  import { mouseEventPref } from './NavigationItem'
@@ -27,7 +29,6 @@ type LayoutOverlaySize = 'floating' | 'minimal' | 'full'
27
29
  type LayoutOverlayAlign = 'start' | 'end' | 'center' | 'stretch'
28
30
 
29
31
  type NavigationOverlayProps = {
30
- active: boolean
31
32
  sx?: SxProps<Theme>
32
33
  stretchColumns?: boolean
33
34
  variantSm: LayoutOverlayVariant
@@ -42,8 +43,9 @@ type NavigationOverlayProps = {
42
43
 
43
44
  function findCurrent(
44
45
  items: NavigationContextType['items'],
45
- selected: NavigationContextType['selected'],
46
+ selected: NavigationPath | false,
46
47
  ): NavigationNodeHref | NavigationNodeButton | undefined {
48
+ if (selected === false) return undefined
47
49
  const lastItem = selected.slice(-1)[0]
48
50
 
49
51
  if (!lastItem) return undefined
@@ -67,9 +69,8 @@ const componentName = 'Navigation'
67
69
  const parts = ['root', 'navigation', 'header', 'column'] as const
68
70
  const { classes } = extendableComponent(componentName, parts)
69
71
 
70
- export function NavigationOverlay(props: NavigationOverlayProps) {
72
+ export const NavigationOverlay = React.memo<NavigationOverlayProps>((props) => {
71
73
  const {
72
- active,
73
74
  sx,
74
75
  stretchColumns,
75
76
  variantMd,
@@ -82,28 +83,42 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
82
83
  itemWidthMd,
83
84
  mouseEvent,
84
85
  } = props
85
- const { selected, select, items, onClose, animating } = useNavigation()
86
+ const { selection, items, animating, closing } = useNavigation()
86
87
 
87
88
  const fabSize = useFabSize('responsive')
88
89
  const svgSize = useIconSvgSize('large')
89
90
 
90
91
  const isMobile = useMediaQuery<Theme>((theme) => theme.breakpoints.down('md'))
91
92
  const handleOnBack = useEventCallback(() => {
92
- if (isMobile) select(selected.slice(0, -1))
93
- else select([])
93
+ if (isMobile) {
94
+ const current = selection.get()
95
+ selection.set(current !== false ? current.slice(0, -1) : false)
96
+ } else selection.set([])
94
97
  })
95
98
 
99
+ const selectedLevel = useMotionValueValue(selection, (s) => (s === false ? -1 : s.length))
100
+ const activeAndNotClosing = useMotionSelector([selection, closing], ([s, c]) =>
101
+ c ? false : s !== false,
102
+ )
103
+
96
104
  useEffect(() => {
97
- animating.current = false
98
- }, [active, animating])
105
+ animating.set(false)
106
+ }, [activeAndNotClosing, animating])
99
107
 
100
- const showBack = selected.length > 0
108
+ const afterClose = useEventCallback(() => {
109
+ if (!closing.get()) return
110
+ closing.set(false)
111
+ selection.set(false)
112
+ })
113
+
114
+ const handleClose = useEventCallback(() => closing.set(true))
101
115
 
102
116
  return (
103
117
  <Overlay
104
118
  className={classes.root}
105
- active={active}
106
- onClosed={onClose}
119
+ active={activeAndNotClosing}
120
+ safeToRemove={afterClose}
121
+ onClosed={handleClose}
107
122
  variantSm={variantSm}
108
123
  sizeSm={sizeSm}
109
124
  justifySm={justifySm}
@@ -111,11 +126,13 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
111
126
  sizeMd={sizeMd}
112
127
  justifyMd={justifyMd}
113
128
  overlayPaneProps={{
129
+ layout: true,
130
+ initial: false,
114
131
  onLayoutAnimationStart: () => {
115
- animating.current = true
132
+ animating.set(true)
116
133
  },
117
134
  onLayoutAnimationComplete: () => {
118
- animating.current = false
135
+ animating.set(false)
119
136
  },
120
137
  }}
121
138
  sx={{
@@ -145,7 +162,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
145
162
  switchPoint={0}
146
163
  layout='position'
147
164
  left={
148
- showBack && (
165
+ selectedLevel > 0 && (
149
166
  <Fab
150
167
  color='inherit'
151
168
  onClick={handleOnBack}
@@ -164,7 +181,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
164
181
  right={
165
182
  <Fab
166
183
  color='inherit'
167
- onClick={() => onClose()}
184
+ onClick={handleClose}
168
185
  sx={{
169
186
  boxShadow: 'none',
170
187
  marginLeft: `calc((${fabSize} - ${svgSize}) * -0.5)`,
@@ -178,7 +195,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
178
195
  }
179
196
  >
180
197
  <LayoutTitle size='small' component='span'>
181
- {findCurrent(items, selected)?.name ?? <Trans id='Menu' />}
198
+ {findCurrent(items, selection.get())?.name ?? <Trans id='Menu' />}
182
199
  </LayoutTitle>
183
200
  </LayoutHeaderContent>
184
201
  </Box>
@@ -192,15 +209,15 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
192
209
  '& .NavigationItem-item': {
193
210
  // eslint-disable-next-line no-nested-ternary
194
211
  width: itemWidthMd
195
- ? selected.length >= 1
212
+ ? selectedLevel >= 1
196
213
  ? `calc(${itemWidthMd} + 1px)`
197
214
  : itemWidthMd
198
- : 'auto',
215
+ : 'stretch',
199
216
  },
200
217
  [theme.breakpoints.down('md')]: {
201
218
  width:
202
219
  sizeSm !== 'floating'
203
- ? `calc(${itemWidthSm || '100vw'} + ${selected.length}px)`
220
+ ? `calc(${itemWidthSm || '100vw'} + ${selectedLevel}px)`
204
221
  : `calc(${itemWidthSm || '100vw'} - ${theme.page.horizontal} - ${
205
222
  theme.page.horizontal
206
223
  })`,
@@ -212,7 +229,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
212
229
  sizeSm !== 'floating'
213
230
  ? `calc(${itemWidthSm || '100vw'} - ${theme.spacings.md} - ${
214
231
  theme.spacings.md
215
- } + ${selected.length}px)`
232
+ } + ${selectedLevel}px)`
216
233
  : `calc(${itemWidthSm || '100vw'} - ${theme.spacings.md} - ${
217
234
  theme.spacings.md
218
235
  } - ${theme.page.horizontal} - ${theme.page.horizontal})`,
@@ -250,7 +267,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
250
267
  ...(Array.isArray(sx) ? sx : [sx]),
251
268
  ]}
252
269
  >
253
- {selected.length >= 0 && (
270
+ {selectedLevel >= 0 && (
254
271
  <Box
255
272
  sx={(theme) => ({
256
273
  gridArea: '1 / 1 / 999 / 2',
@@ -259,7 +276,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
259
276
  className={classes.column}
260
277
  />
261
278
  )}
262
- {selected.length >= 1 && (
279
+ {selectedLevel >= 1 && (
263
280
  <Box
264
281
  sx={(theme) => ({
265
282
  gridArea: '1 / 2 / 999 / 3',
@@ -268,7 +285,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
268
285
  className={classes.column}
269
286
  />
270
287
  )}
271
- {selected.length >= 2 && (
288
+ {selectedLevel >= 2 && (
272
289
  <Box
273
290
  sx={(theme) => ({
274
291
  gridArea: '1 / 3 / 999 / 4',
@@ -277,7 +294,7 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
277
294
  className={classes.column}
278
295
  />
279
296
  )}
280
- {selected.length >= 3 && (
297
+ {selectedLevel >= 3 && (
281
298
  <Box
282
299
  sx={(theme) => ({
283
300
  gridArea: '1 / 4 / 999 / 5',
@@ -293,4 +310,8 @@ export function NavigationOverlay(props: NavigationOverlayProps) {
293
310
  </MotionDiv>
294
311
  </Overlay>
295
312
  )
313
+ })
314
+
315
+ if (process.env.NODE_ENV !== 'production') {
316
+ NavigationOverlay.displayName = 'NavigationOverlay'
296
317
  }
@@ -1,13 +1,11 @@
1
- import { useEventCallback } from '@mui/material'
2
- import { MotionConfig } from 'framer-motion'
3
- import { useState, useMemo, SetStateAction, useRef } from 'react'
1
+ import { MotionConfig, useMotionValue } from 'framer-motion'
2
+ import React, { useMemo, useRef } from 'react'
4
3
  import { isElement } from 'react-is'
5
4
  import {
6
5
  NavigationNode,
7
- NavigationPath,
8
6
  NavigationContextType,
9
7
  NavigationContext,
10
- NavigationSelect,
8
+ UseNavigationSelection,
11
9
  } from '../hooks/useNavigation'
12
10
 
13
11
  export type NavigationProviderProps = {
@@ -16,51 +14,35 @@ export type NavigationProviderProps = {
16
14
  closeAfterNavigate?: boolean
17
15
  children?: React.ReactNode
18
16
  animationDuration?: number
19
- selected: NavigationPath
20
- setSelected: (value: SetStateAction<NavigationPath>) => void
21
- onChange?: NavigationSelect
22
- onClose?: NavigationContextType['onClose']
17
+ selection: UseNavigationSelection
23
18
  }
24
19
 
25
20
  const nonNullable = <T,>(value: T): value is NonNullable<T> => value !== null && value !== undefined
26
21
 
27
- export function NavigationProvider(props: NavigationProviderProps) {
22
+ export const NavigationProvider = React.memo<NavigationProviderProps>((props) => {
28
23
  const {
29
24
  items,
30
- onChange,
31
25
  hideRootOnNavigate = true,
32
26
  closeAfterNavigate = false,
33
27
  animationDuration = 0.275,
34
28
  children,
35
- onClose: onCloseUnstable,
36
- selected,
37
- setSelected,
29
+ selection,
38
30
  } = props
39
31
 
40
- const animating = useRef(false)
41
-
42
- const select = useEventCallback((incomming: NavigationPath) => {
43
- setSelected(incomming)
44
- onChange?.(incomming)
45
- })
46
-
47
- const onClose: NavigationContextType['onClose'] = useEventCallback((e, href) => {
48
- onCloseUnstable?.(e, href)
49
- setTimeout(() => select([]), animationDuration * 1000)
50
- })
32
+ const animating = useMotionValue(false)
33
+ const closing = useMotionValue(false)
51
34
 
52
35
  const value = useMemo<NavigationContextType>(
53
36
  () => ({
54
37
  hideRootOnNavigate,
55
- selected,
56
- select,
38
+ selection,
57
39
  animating,
40
+ closing,
58
41
  items: items
59
42
  .map((item, index) => (isElement(item) ? { id: item.key ?? index, component: item } : item))
60
43
  .filter(nonNullable),
61
- onClose,
62
44
  }),
63
- [hideRootOnNavigate, selected, select, items, onClose],
45
+ [hideRootOnNavigate, selection, animating, closing, items],
64
46
  )
65
47
 
66
48
  return (
@@ -68,4 +50,4 @@ export function NavigationProvider(props: NavigationProviderProps) {
68
50
  <NavigationContext.Provider value={value}>{children}</NavigationContext.Provider>
69
51
  </MotionConfig>
70
52
  )
71
- }
53
+ })
@@ -1,23 +1,24 @@
1
- import { createContext, MutableRefObject, SetStateAction, useContext } from 'react'
1
+ import { MotionValue, useMotionValue } from 'framer-motion'
2
+ import { createContext, MutableRefObject, useContext } from 'react'
2
3
 
3
4
  export type NavigationId = string | number
4
5
  export type NavigationPath = NavigationId[]
5
- export type NavigationSelect = (selected: NavigationPath) => void
6
6
  export type NavigationRender = React.FC<
7
7
  (NavigationNodeComponent | NavigationNodeHref) & { children?: React.ReactNode }
8
8
  >
9
9
 
10
+ export type UseNavigationSelection = MotionValue<NavigationPath | false>
11
+
10
12
  export type NavigationOnClose = (
11
13
  event?: React.MouseEvent<HTMLAnchorElement>,
12
14
  href?: string | undefined,
13
15
  ) => void
14
16
  export type NavigationContextType = {
15
- selected: NavigationPath
16
- select: NavigationSelect
17
+ selection: UseNavigationSelection
17
18
  items: NavigationNode[]
18
19
  hideRootOnNavigate: boolean
19
- onClose: NavigationOnClose
20
- animating: MutableRefObject<boolean>
20
+ animating: MotionValue<boolean>
21
+ closing: MotionValue<boolean>
21
22
  }
22
23
 
23
24
  type NavigationNodeBase = {
@@ -57,3 +58,29 @@ export const NavigationContext = createContext(undefined as unknown as Navigatio
57
58
  export function useNavigation() {
58
59
  return useContext(NavigationContext)
59
60
  }
61
+
62
+ /**
63
+ * To prevent excessive rerenders we're not using plain React useState, but we're using a reactive
64
+ * motion value (could easily be any other reactive variable like Zustand, MobX, etc).
65
+ *
66
+ * Usage:
67
+ *
68
+ * ```tsx
69
+ * const selection = useNavigationSelection()
70
+ *
71
+ * function onClose() {
72
+ * selection.set(false)
73
+ * }
74
+ *
75
+ * function openRoot() {
76
+ * selection.set([])
77
+ * }
78
+ *
79
+ * function openPath() {
80
+ * selection.set(['my-path'])
81
+ * }
82
+ * ```
83
+ */
84
+ export function useNavigationSelection(): UseNavigationSelection {
85
+ return useMotionValue<NavigationPath | false>(false)
86
+ }
@@ -6,7 +6,7 @@ import { OverlayBase, LayoutOverlayBaseProps } from './OverlayBase'
6
6
 
7
7
  export type OverlayProps = Omit<
8
8
  SetOptional<LayoutOverlayBaseProps, 'variantSm' | 'variantMd'>,
9
- 'direction' | 'offsetPageY' | 'isPresent' | 'safeToRemove'
9
+ 'direction' | 'offsetPageY' | 'isPresent'
10
10
  >
11
11
 
12
12
  export function Overlay(props: OverlayProps) {
@@ -50,7 +50,6 @@ export function Overlay(props: OverlayProps) {
50
50
  direction={1}
51
51
  active={active}
52
52
  isPresent={active}
53
- safeToRemove={undefined}
54
53
  {...otherProps}
55
54
  >
56
55
  {children}
@@ -39,7 +39,7 @@ export type LayoutOverlayBaseProps = {
39
39
  onClosed: () => void
40
40
  offsetPageY: number
41
41
  isPresent: boolean
42
- safeToRemove: (() => void) | null | undefined
42
+ safeToRemove?: (() => void) | null | undefined
43
43
  overlayPaneProps?: MotionProps
44
44
  } & StyleProps &
45
45
  OverridableProps
@@ -115,14 +115,7 @@ export function OverlayBase(incommingProps: LayoutOverlayBaseProps) {
115
115
  useIsomorphicLayoutEffect(() => {
116
116
  const scroller = scrollerRef.current
117
117
 
118
- if (!scroller) return undefined
119
-
120
- if (!isPresent && position.get() === OverlayPosition.UNOPENED) {
121
- scroller.scrollLeft = positions.closed.x.get()
122
- scroller.scrollTop = positions.closed.y.get()
123
- }
124
-
125
- if (!isPresent) return undefined
118
+ if (!scroller || !isPresent) return undefined
126
119
 
127
120
  const open = { x: positions.open.x.get(), y: positions.open.y.get() }
128
121
 
@@ -151,10 +144,15 @@ export function OverlayBase(incommingProps: LayoutOverlayBaseProps) {
151
144
  if (!scroller) return () => {}
152
145
 
153
146
  const resize = () => {
154
- if (positions.open.visible.get() !== 1) return
147
+ if (positions.open.visible.get() === 1) {
148
+ scroller.scrollLeft = positions.open.x.get()
149
+ scroller.scrollTop = positions.open.y.get()
150
+ }
155
151
 
156
- scroller.scrollLeft = positions.open.x.get()
157
- scroller.scrollTop = positions.open.y.get()
152
+ if (positions.open.visible.get() === 0) {
153
+ scroller.scrollLeft = positions.closed.x.get()
154
+ scroller.scrollTop = positions.closed.y.get()
155
+ }
158
156
  }
159
157
 
160
158
  window.addEventListener('resize', resize)
@@ -165,16 +163,23 @@ export function OverlayBase(incommingProps: LayoutOverlayBaseProps) {
165
163
 
166
164
  // When the overlay is closed by navigating away, we're closing the overlay.
167
165
  useEffect(() => {
168
- if (isPresent || position.get() === OverlayPosition.UNOPENED) return
169
- position.set(OverlayPosition.CLOSED)
170
- clearScrollLock()
166
+ const scroller = scrollerRef.current
167
+ if (isPresent || !scroller) return
171
168
 
172
- // eslint-disable-next-line @typescript-eslint/no-floating-promises
173
- scrollTo({
174
- x: positions.closed.x.get(),
175
- y: positions.closed.y.get(),
176
- }).then(() => safeToRemove?.())
177
- }, [isPresent, position, positions, safeToRemove, scrollTo])
169
+ if (position.get() === OverlayPosition.UNOPENED) {
170
+ position.set(OverlayPosition.CLOSED)
171
+ clearScrollLock()
172
+ scroller.scrollLeft = positions.closed.x.get()
173
+ scroller.scrollTop = positions.closed.y.get()
174
+ safeToRemove?.()
175
+ } else {
176
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
177
+ scrollTo({
178
+ x: positions.closed.x.get(),
179
+ y: positions.closed.y.get(),
180
+ }).then(() => safeToRemove?.())
181
+ }
182
+ }, [isPresent, position, positions, safeToRemove, scrollTo, scrollerRef])
178
183
 
179
184
  // Only go back to a previous page if the overlay isn't closed.
180
185
  const closeOverlay = useCallback(() => {
@@ -370,7 +375,6 @@ export function OverlayBase(incommingProps: LayoutOverlayBaseProps) {
370
375
  >
371
376
  <MotionDiv
372
377
  {...overlayPaneProps}
373
- layout
374
378
  className={classes.overlayPane}
375
379
  sx={(theme) => ({
376
380
  pointerEvents: 'all',
@@ -380,7 +384,7 @@ export function OverlayBase(incommingProps: LayoutOverlayBaseProps) {
380
384
  [theme.breakpoints.down('md')]: {
381
385
  minWidth: '80vw',
382
386
  '&:not(.sizeMdFull)': {
383
- width: 'max-content',
387
+ width: 'auto',
384
388
  },
385
389
 
386
390
  '&.variantSmBottom.sizeSmFull': {
@@ -26,6 +26,7 @@ export function useOverlayPosition() {
26
26
 
27
27
  const measure = () => {
28
28
  const positions = getScrollSnapPositions()
29
+
29
30
  state.open.x.set(positions.x[1] ?? 0)
30
31
  state.closed.x.set(positions.x[0])
31
32
  state.open.y.set(positions.y[1] ?? 0)
@@ -50,10 +51,14 @@ export function useOverlayPosition() {
50
51
 
51
52
  const xC = state.closed.x.get()
52
53
  const xO = state.open.x.get()
54
+
53
55
  const visX = xO === xC ? 1 : Math.max(0, Math.min(1, (x - xC) / (xO - xC)))
54
56
 
57
+ let vis = visY * visX
58
+ if (xC === 0 && xO === 0 && yC === 0 && yO === 0) vis = 0
59
+
55
60
  // todo: visibility sometimes flickers
56
- state.open.visible.set(visY * visX)
61
+ state.open.visible.set(vis)
57
62
  }
58
63
 
59
64
  const cancelY = scroll.y.onChange(calc)
@@ -3,6 +3,7 @@ import { m, useTransform } from 'framer-motion'
3
3
  import React from 'react'
4
4
  import { useScrollY } from '../../Layout/hooks/useScrollY'
5
5
  import { extendableComponent } from '../../Styles'
6
+ import { breakpointVal } from '../../Styles/breakpointVal'
6
7
  import { responsiveVal } from '../../Styles/responsiveVal'
7
8
  import { Row } from '../Row'
8
9
 
@@ -84,9 +85,11 @@ export function HeroBanner(props: HeroBannerProps) {
84
85
  width: '100%',
85
86
  height: '100%',
86
87
  [theme.breakpoints.down('md')]: {
87
- borderRadius: responsiveVal(
88
+ ...breakpointVal(
89
+ 'borderRadius',
88
90
  theme.shape.borderRadius * 2,
89
91
  theme.shape.borderRadius * 3,
92
+ theme.breakpoints.values,
90
93
  ),
91
94
  },
92
95
  },
@@ -99,9 +102,11 @@ export function HeroBanner(props: HeroBannerProps) {
99
102
  style={{ width: !matches ? width : 0, borderRadius }}
100
103
  className={classes.animated}
101
104
  sx={(theme) => ({
102
- borderRadius: responsiveVal(
105
+ ...breakpointVal(
106
+ 'borderRadius',
103
107
  theme.shape.borderRadius * 2,
104
108
  theme.shape.borderRadius * 3,
109
+ theme.breakpoints.values,
105
110
  ),
106
111
  overflow: 'hidden',
107
112
  transform: 'translateZ(0)',
@@ -1,7 +1,7 @@
1
1
  import { Box, SxProps, Theme } from '@mui/material'
2
2
  import React from 'react'
3
3
  import { extendableComponent } from '../../Styles'
4
- import { responsiveVal } from '../../Styles/responsiveVal'
4
+ import { breakpointVal } from '../../Styles/breakpointVal'
5
5
  import { Row } from '../Row'
6
6
 
7
7
  export type ImageTextProps = {
@@ -37,7 +37,12 @@ export function ImageText(props: ImageTextProps) {
37
37
  background: 'none',
38
38
  gridTemplateColumns: '1fr 1fr',
39
39
  },
40
- borderRadius: responsiveVal(theme.shape.borderRadius * 2, theme.shape.borderRadius * 3),
40
+ ...breakpointVal(
41
+ 'borderRadius',
42
+ theme.shape.borderRadius * 2,
43
+ theme.shape.borderRadius * 3,
44
+ theme.breakpoints.values,
45
+ ),
41
46
  })}
42
47
  >
43
48
  <Box
@@ -49,9 +54,11 @@ export function ImageText(props: ImageTextProps) {
49
54
  height: '100%',
50
55
  width: '100%',
51
56
  objectFit: 'cover',
52
- borderRadius: responsiveVal(
57
+ ...breakpointVal(
58
+ 'borderRadius',
53
59
  theme.shape.borderRadius * 2,
54
60
  theme.shape.borderRadius * 3,
61
+ theme.breakpoints.values,
55
62
  ),
56
63
  },
57
64
  })}
@@ -1,6 +1,7 @@
1
1
  import { Box, SxProps, Theme } from '@mui/material'
2
2
  import React from 'react'
3
3
  import { extendableComponent } from '../../Styles'
4
+ import { breakpointVal } from '../../Styles/breakpointVal'
4
5
  import { responsiveVal } from '../../Styles/responsiveVal'
5
6
  import { Row } from '../Row'
6
7
 
@@ -32,7 +33,12 @@ export function ImageTextBoxed(props: ImageTextBoxedProps) {
32
33
  gridTemplateColumns: '1fr auto',
33
34
  columnGap: `${theme.spacings.lg}`,
34
35
  },
35
- borderRadius: responsiveVal(theme.shape.borderRadius * 2, theme.shape.borderRadius * 3),
36
+ ...breakpointVal(
37
+ 'borderRadius',
38
+ theme.shape.borderRadius * 2,
39
+ theme.shape.borderRadius * 3,
40
+ theme.breakpoints.values,
41
+ ),
36
42
  overflow: 'hidden',
37
43
  })}
38
44
  >
@@ -1,6 +1,6 @@
1
1
  import { Box, ContainerProps } from '@mui/material'
2
2
  import { extendableComponent } from '../../Styles'
3
- import { responsiveVal } from '../../Styles/responsiveVal'
3
+ import { breakpointVal } from '../../Styles/breakpointVal'
4
4
  import { Row } from '../Row'
5
5
 
6
6
  export type ParagraphWithSidebarSlideProps = ContainerProps & {
@@ -46,9 +46,11 @@ export function ParagraphWithSidebarSlide(props: ParagraphWithSidebarSlideProps)
46
46
  filter: 'brightness(100%)',
47
47
  height: '100%',
48
48
  },
49
- borderRadius: responsiveVal(
49
+ ...breakpointVal(
50
+ 'borderRadius',
50
51
  theme.shape.borderRadius * 2,
51
52
  theme.shape.borderRadius * 3,
53
+ theme.breakpoints.values,
52
54
  ),
53
55
  },
54
56
  })}