@graphcommerce/next-ui 9.0.0-canary.78 → 9.0.0-canary.80

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.
@@ -213,7 +213,7 @@ export function ActionCard(props: ActionCardProps) {
213
213
  backgroundColor: theme.palette.background.paper,
214
214
  boxShadow: `inset 0 0 0 1px ${theme.palette.divider}`,
215
215
  '&:not(:last-of-type)': {
216
- marginBottom: '-1px',
216
+ marginBottom: '-2px',
217
217
  },
218
218
  '&.layoutList': {
219
219
  borderRadius: 0,
@@ -251,7 +251,7 @@ export function ActionCard(props: ActionCardProps) {
251
251
  borderColor: 'transparent',
252
252
  boxShadow: `inset 0 0 0 2px ${theme.palette[color].main}`,
253
253
  },
254
- '&.selected:focus': {
254
+ '&.selected:focus, &.error:focus': {
255
255
  borderColor: 'transparent',
256
256
  boxShadow: `inset 0 0 0 2px ${theme.palette[color].main}, 0 0 0 4px ${alpha(
257
257
  theme.palette[color].main,
@@ -266,12 +266,15 @@ export function ActionCard(props: ActionCardProps) {
266
266
  },
267
267
 
268
268
  '&.error': {
269
- boxShadow: `0 0 0 2px ${theme.palette.error.main}`,
269
+ boxShadow: `inset 0 0 0 2px ${theme.palette.error.main}`,
270
270
  },
271
271
  },
272
272
  '&.selected': {
273
273
  zIndex: 1,
274
274
  },
275
+ '&:focus, &.selected:focus, &.error:focus': {
276
+ zIndex: 2,
277
+ },
275
278
  '&.disabled': {
276
279
  background: theme.palette.action.disabledBackground,
277
280
  opacity: theme.palette.action.disabledOpacity,
@@ -6,7 +6,7 @@ import { ActionCardProps } from './ActionCard'
6
6
  export type ActionCardLayoutProps = {
7
7
  children?: React.ReactNode
8
8
  } & Pick<ActionCardProps, 'layout'> &
9
- Pick<BoxProps, 'sx' | 'className'>
9
+ Pick<BoxProps, 'sx' | 'className' | 'tabIndex'>
10
10
 
11
11
  const parts = ['root'] as const
12
12
  const name = 'ActionCardLayout'
@@ -138,8 +138,8 @@ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListPro
138
138
  const classes = withState({ size, color, variant, layout })
139
139
 
140
140
  return (
141
- <div ref={ref}>
142
- <ActionCardLayout sx={sx} className={classes.root} layout={layout}>
141
+ <div>
142
+ <ActionCardLayout sx={sx} className={classes.root} layout={layout} ref={ref} tabIndex={0}>
143
143
  {childActionCards.map((child, index) => {
144
144
  if (collapse && Boolean(value) && !isValueSelected(child.props.value, value))
145
145
  return null
@@ -2,4 +2,3 @@ export * from './ActionCard'
2
2
  export * from './ActionCardAccordion'
3
3
  export * from './ActionCardLayout'
4
4
  export * from './ActionCardList'
5
- export * from './ActionCardListForm'
package/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Change Log
2
2
 
3
+ ## 9.0.0-canary.80
4
+
5
+ ### Patch Changes
6
+
7
+ - [#2341](https://github.com/graphcommerce-org/graphcommerce/pull/2341) [`c57614d`](https://github.com/graphcommerce-org/graphcommerce/commit/c57614d47675cec2a0bf290371f11441495e10fe) - ActionCardList can now recieve focus, allowing form submissions to scroll to the field. Focussed fields now are now highlighted even when there is an error. ([@Giovanni-Schroevers](https://github.com/Giovanni-Schroevers))
8
+
9
+ ## 9.0.0-canary.79
10
+
11
+ ### Patch Changes
12
+
13
+ - [#2356](https://github.com/graphcommerce-org/graphcommerce/pull/2356) [`d283901`](https://github.com/graphcommerce-org/graphcommerce/commit/d283901cb537c3e7bf6f5500e9f52f47f452cf10) - Loading an overlay page directly would animate in the overlay instead of directly showing it. ([@paales](https://github.com/paales))
14
+
3
15
  ## 9.0.0-canary.78
4
16
 
5
17
  ### Patch Changes
@@ -1,3 +1,4 @@
1
+ import { Direction } from '@graphcommerce/framer-next-pages'
1
2
  import { Scroller, useScrollerContext, useScrollTo } from '@graphcommerce/framer-scroller'
2
3
  import {
3
4
  dvh,
@@ -46,7 +47,7 @@ export type LayoutOverlayBaseProps = {
46
47
  sx?: SxProps<Theme>
47
48
  sxBackdrop?: SxProps<Theme>
48
49
  active: boolean
49
- direction?: 1 | -1
50
+ direction?: Direction
50
51
  onClosed: () => void
51
52
  offsetPageY?: number
52
53
  isPresent: boolean
@@ -123,7 +124,8 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
123
124
  props.smSpacingTop ?? ((theme) => `calc(${theme.appShell.headerHeightSm} * 0.5)`)
124
125
  )(th)
125
126
 
126
- const { scrollerRef, snap, scroll, getScrollSnapPositions, disableSnap } = useScrollerContext()
127
+ const { scrollerRef, snap, scroll, getScrollSnapPositions, disableSnap, enableSnap } =
128
+ useScrollerContext()
127
129
  const scrollTo = useScrollTo()
128
130
 
129
131
  const beforeRef = useRef<HTMLDivElement>(null)
@@ -137,7 +139,7 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
137
139
 
138
140
  const match = useMatchMedia()
139
141
  const positions = useConstant(() => ({
140
- open: { x: motionValue(0), y: motionValue(0), visible: motionValue(0) },
142
+ open: { x: motionValue(0), y: motionValue(0), visible: motionValue(direction === 0 ? 1 : 0) },
141
143
  closed: { x: motionValue(0), y: motionValue(0) },
142
144
  }))
143
145
 
@@ -277,17 +279,40 @@ export function OverlayBase(incomingProps: LayoutOverlayBaseProps) {
277
279
  useIsomorphicLayoutEffect(() => {
278
280
  const scroller = scrollerRef.current
279
281
 
280
- if (!scroller || !isPresent) return
282
+ if (!scroller || !isPresent || position.get() === OverlayPosition.OPENED) return
281
283
 
282
284
  if (variant() === 'right') document.body.style.overflow = 'hidden'
283
285
 
284
- if (position.get() !== OverlayPosition.OPENED && !scroll.animating.get()) {
286
+ if (direction === 0) {
287
+ disableSnap()
288
+ scroller.scrollTop = positions.open.y.get()
289
+ scroller.scrollLeft = positions.open.x.get()
290
+ scroll.y.set(positions.open.y.get())
291
+ scroll.x.set(positions.open.x.get())
292
+ position.set(OverlayPosition.OPENED)
293
+ enableSnap()
294
+ } else if (!scroll.animating.get()) {
285
295
  // eslint-disable-next-line @typescript-eslint/no-floating-promises
286
296
  scrollTo(openClosePositions().open, { stopAnimationOnScroll: false }).then(() =>
287
297
  position.set(OverlayPosition.OPENED),
288
298
  )
289
299
  }
290
- }, [isPresent, openClosePositions, position, scroll.animating, scrollTo, scrollerRef, variant])
300
+ }, [
301
+ direction,
302
+ disableSnap,
303
+ enableSnap,
304
+ isPresent,
305
+ openClosePositions,
306
+ position,
307
+ positions.open.x,
308
+ positions.open.y,
309
+ scroll.animating,
310
+ scroll.x,
311
+ scroll.y,
312
+ scrollTo,
313
+ scrollerRef,
314
+ variant,
315
+ ])
291
316
 
292
317
  // When the overlay is closed by navigating away, we're closing the overlay.
293
318
  useEffect(() => {
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": "9.0.0-canary.78",
5
+ "version": "9.0.0-canary.80",
6
6
  "sideEffects": false,
7
7
  "prettier": "@graphcommerce/prettier-config-pwa",
8
8
  "eslintConfig": {
@@ -26,13 +26,13 @@
26
26
  "typescript": "5.5.3"
27
27
  },
28
28
  "peerDependencies": {
29
- "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.78",
30
- "@graphcommerce/framer-next-pages": "^9.0.0-canary.78",
31
- "@graphcommerce/framer-scroller": "^9.0.0-canary.78",
32
- "@graphcommerce/framer-utils": "^9.0.0-canary.78",
33
- "@graphcommerce/image": "^9.0.0-canary.78",
34
- "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.78",
35
- "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.78",
29
+ "@graphcommerce/eslint-config-pwa": "^9.0.0-canary.80",
30
+ "@graphcommerce/framer-next-pages": "^9.0.0-canary.80",
31
+ "@graphcommerce/framer-scroller": "^9.0.0-canary.80",
32
+ "@graphcommerce/framer-utils": "^9.0.0-canary.80",
33
+ "@graphcommerce/image": "^9.0.0-canary.80",
34
+ "@graphcommerce/prettier-config-pwa": "^9.0.0-canary.80",
35
+ "@graphcommerce/typescript-config-pwa": "^9.0.0-canary.80",
36
36
  "@lingui/core": "^4.2.1",
37
37
  "@lingui/macro": "^4.2.1",
38
38
  "@lingui/react": "^4.2.1",
@@ -1,88 +0,0 @@
1
- /* eslint-disable import/no-extraneous-dependencies */
2
- import {
3
- Controller,
4
- ControllerProps,
5
- FieldValues,
6
- useController,
7
- } from '@graphcommerce/react-hook-form'
8
- import React, { MouseEventHandler } from 'react'
9
- import { ActionCardProps } from './ActionCard'
10
- import { ActionCardList, ActionCardListProps } from './ActionCardList'
11
-
12
- export type ActionCardItemBase = Pick<ActionCardProps, 'value'>
13
-
14
- export type ActionCardItemRenderProps<T> = ActionCardProps & {
15
- onReset: MouseEventHandler<HTMLAnchorElement> & MouseEventHandler<HTMLSpanElement>
16
- } & T
17
-
18
- export type ActionCardListFormProps<A, F extends FieldValues = FieldValues> = Omit<
19
- ActionCardListProps,
20
- 'value' | 'error' | 'onChange' | 'children'
21
- > &
22
- Omit<ControllerProps<F>, 'render'> & {
23
- items: A[]
24
- render: React.FC<ActionCardItemRenderProps<A>>
25
- }
26
-
27
- export function ActionCardListForm<
28
- T extends ActionCardItemBase,
29
- F extends FieldValues = FieldValues,
30
- >(props: ActionCardListFormProps<T, F>) {
31
- const {
32
- required,
33
- rules,
34
- items,
35
- render,
36
- control,
37
- name,
38
- errorMessage,
39
- defaultValue,
40
- multiple,
41
- ...other
42
- } = props
43
- const RenderItem = render as React.FC<ActionCardItemRenderProps<ActionCardItemBase>>
44
-
45
- function onSelect(itemValue: unknown, selectValues: unknown) {
46
- return multiple
47
- ? Array.isArray(selectValues) && selectValues.some((selectValue) => selectValue === itemValue)
48
- : selectValues === itemValue
49
- }
50
-
51
- const {
52
- field: { onChange, value, ref },
53
- fieldState,
54
- formState,
55
- } = useController({
56
- ...props,
57
- control,
58
- name,
59
- defaultValue,
60
- rules: { required: errorMessage || required, ...rules },
61
- })
62
-
63
- return (
64
- <ActionCardList
65
- {...other}
66
- multiple={multiple}
67
- required={required}
68
- value={value}
69
- ref={ref}
70
- onChange={(_, incomming) => onChange(incomming)}
71
- error={formState.isSubmitted && !!fieldState.error}
72
- errorMessage={fieldState.error?.message}
73
- >
74
- {items.map((item) => (
75
- <RenderItem
76
- {...item}
77
- key={`${item.value}`}
78
- value={item.value}
79
- selected={onSelect(item.value, value)}
80
- onReset={(e) => {
81
- e.preventDefault()
82
- onChange(null)
83
- }}
84
- />
85
- ))}
86
- </ActionCardList>
87
- )
88
- }