@graphcommerce/next-ui 4.25.0 → 4.27.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/ActionCard/ActionCard.tsx +215 -131
- package/ActionCard/ActionCardList.tsx +92 -51
- package/ActionCard/ActionCardListForm.tsx +11 -11
- package/Button/Button.tsx +6 -2
- package/CHANGELOG.md +24 -0
- package/FramerScroller/SidebarGallery.tsx +1 -1
- package/RenderType/RenderType.tsx +8 -1
- package/RenderType/filterNonNullableKeys.ts +1 -1
- package/Row/ButtonLinkList/ButtonLinkListItem.tsx +23 -16
- package/Row/IconBlocks/IconBlock.tsx +31 -53
- package/package.json +2 -2
|
@@ -1,9 +1,25 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { alpha, Box, BoxProps, ButtonBase, ButtonProps, SxProps, Theme } from '@mui/material'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { extendableComponent } from '../Styles'
|
|
4
4
|
import { breakpointVal } from '../Styles/breakpointVal'
|
|
5
5
|
|
|
6
|
+
type Variants = 'outlined' | 'default'
|
|
7
|
+
type Size = 'large' | 'medium' | 'small'
|
|
8
|
+
type Color = 'primary' | 'secondary' | 'success' | 'error' | 'info' | 'warning'
|
|
9
|
+
type Layout = 'inline' | 'grid' | 'list' | 'stack'
|
|
10
|
+
|
|
11
|
+
function isButtonProps(props: ButtonProps<'div'> | BoxProps<'div'>): props is ButtonProps<'div'> {
|
|
12
|
+
return props.onClick !== undefined
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const RenderComponent = (props: ButtonProps<'div'> | BoxProps<'div'>) =>
|
|
16
|
+
isButtonProps(props) ? <ButtonBase component='div' {...props} /> : <Box {...props} />
|
|
17
|
+
|
|
6
18
|
export type ActionCardProps = {
|
|
19
|
+
variant?: Variants
|
|
20
|
+
size?: Size
|
|
21
|
+
color?: Color
|
|
22
|
+
layout?: Layout
|
|
7
23
|
sx?: SxProps<Theme>
|
|
8
24
|
title?: string | React.ReactNode
|
|
9
25
|
image?: React.ReactNode
|
|
@@ -14,10 +30,10 @@ export type ActionCardProps = {
|
|
|
14
30
|
secondaryAction?: React.ReactNode
|
|
15
31
|
onClick?: (event: React.MouseEvent<HTMLElement>, value: string | number) => void
|
|
16
32
|
selected?: boolean
|
|
17
|
-
hidden?: boolean
|
|
18
33
|
value: string | number
|
|
19
34
|
reset?: React.ReactNode
|
|
20
35
|
disabled?: boolean
|
|
36
|
+
error?: boolean
|
|
21
37
|
}
|
|
22
38
|
|
|
23
39
|
const parts = [
|
|
@@ -34,10 +50,14 @@ const parts = [
|
|
|
34
50
|
const name = 'ActionCard'
|
|
35
51
|
|
|
36
52
|
type StateProps = {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
53
|
+
variant: Variants
|
|
54
|
+
size: Size
|
|
55
|
+
color: Color
|
|
56
|
+
layout: Layout
|
|
57
|
+
selected: boolean
|
|
58
|
+
disabled: boolean
|
|
59
|
+
image: boolean
|
|
60
|
+
error: boolean
|
|
41
61
|
}
|
|
42
62
|
|
|
43
63
|
const { withState, selectors } = extendableComponent<StateProps, typeof name, typeof parts>(
|
|
@@ -60,99 +80,131 @@ export function ActionCard(props: ActionCardProps) {
|
|
|
60
80
|
onClick,
|
|
61
81
|
value,
|
|
62
82
|
selected = false,
|
|
63
|
-
hidden = false,
|
|
64
83
|
reset,
|
|
65
84
|
disabled = false,
|
|
85
|
+
size = 'medium',
|
|
86
|
+
color = 'primary',
|
|
87
|
+
variant = 'outlined',
|
|
88
|
+
layout = 'list',
|
|
89
|
+
error = false,
|
|
66
90
|
} = props
|
|
67
91
|
|
|
68
|
-
const classes = withState({
|
|
69
|
-
|
|
70
|
-
|
|
92
|
+
const classes = withState({
|
|
93
|
+
disabled,
|
|
94
|
+
selected,
|
|
95
|
+
image: Boolean(image),
|
|
96
|
+
variant,
|
|
97
|
+
size,
|
|
98
|
+
color,
|
|
99
|
+
layout,
|
|
100
|
+
error,
|
|
101
|
+
})
|
|
71
102
|
|
|
72
103
|
return (
|
|
73
|
-
<
|
|
74
|
-
component='div'
|
|
104
|
+
<RenderComponent
|
|
75
105
|
className={classes.root}
|
|
76
|
-
onClick={
|
|
106
|
+
onClick={onClick && ((event) => onClick?.(event, value))}
|
|
77
107
|
disabled={disabled}
|
|
78
108
|
sx={[
|
|
79
109
|
(theme) => ({
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
"image title action"
|
|
85
|
-
"image details ${price ? 'price' : 'details'}"
|
|
86
|
-
"image secondaryAction additionalDetails"
|
|
87
|
-
"after after after"
|
|
88
|
-
`,
|
|
89
|
-
justifyContent: 'unset',
|
|
90
|
-
typography: 'body1',
|
|
91
|
-
// textAlign: 'left',
|
|
92
|
-
background: theme.palette.background.paper,
|
|
93
|
-
padding: `calc(${theme.spacings.xxs} + 1px) calc(${theme.spacings.xs} + 1px)`,
|
|
94
|
-
columnGap: theme.spacings.xxs,
|
|
95
|
-
border: `1px solid ${theme.palette.divider}`,
|
|
96
|
-
borderBottomColor: `transparent`,
|
|
97
|
-
'&:first-of-type': {
|
|
98
|
-
...breakpointVal(
|
|
99
|
-
'borderTopLeftRadius',
|
|
100
|
-
theme.shape.borderRadius * 3,
|
|
101
|
-
theme.shape.borderRadius * 4,
|
|
102
|
-
theme.breakpoints.values,
|
|
103
|
-
),
|
|
104
|
-
...breakpointVal(
|
|
105
|
-
'borderTopRightRadius',
|
|
106
|
-
theme.shape.borderRadius * 3,
|
|
107
|
-
theme.shape.borderRadius * 4,
|
|
108
|
-
theme.breakpoints.values,
|
|
109
|
-
),
|
|
110
|
+
'&.sizeSmall': {
|
|
111
|
+
padding: `5px 10px`,
|
|
112
|
+
display: 'flex',
|
|
113
|
+
typography: 'body2',
|
|
110
114
|
},
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
theme.breakpoints.values,
|
|
117
|
-
),
|
|
118
|
-
...breakpointVal(
|
|
119
|
-
'borderBottomRightRadius',
|
|
120
|
-
theme.shape.borderRadius * 3,
|
|
121
|
-
theme.shape.borderRadius * 4,
|
|
122
|
-
theme.breakpoints.values,
|
|
123
|
-
),
|
|
124
|
-
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
115
|
+
|
|
116
|
+
'&.sizeMedium': {
|
|
117
|
+
padding: `10px 12px`,
|
|
118
|
+
typography: 'body2',
|
|
119
|
+
display: 'block',
|
|
125
120
|
},
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
gridTemplateColumns: 'auto auto',
|
|
129
|
-
gridTemplateAreas: `
|
|
130
|
-
"title action"
|
|
131
|
-
"details ${price ? 'price' : 'details'}"
|
|
132
|
-
"secondaryAction additionalDetails"
|
|
133
|
-
"after after"
|
|
134
|
-
`,
|
|
135
|
-
},
|
|
136
|
-
hidden && {
|
|
137
|
-
display: 'none',
|
|
138
|
-
},
|
|
139
|
-
selected &&
|
|
140
|
-
((theme) => ({
|
|
141
|
-
border: `2px solid ${theme.palette.secondary.main} !important`,
|
|
142
|
-
boxShadow: `0 0 0 4px ${alpha(
|
|
143
|
-
theme.palette.secondary.main,
|
|
144
|
-
theme.palette.action.hoverOpacity,
|
|
145
|
-
)} !important`,
|
|
146
|
-
...breakpointVal(
|
|
147
|
-
'borderRadius',
|
|
148
|
-
theme.shape.borderRadius * 3,
|
|
149
|
-
theme.shape.borderRadius * 4,
|
|
150
|
-
theme.breakpoints.values,
|
|
151
|
-
),
|
|
121
|
+
|
|
122
|
+
'&.sizeLarge': {
|
|
152
123
|
padding: `${theme.spacings.xxs} ${theme.spacings.xs}`,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
124
|
+
display: 'block',
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
'&.variantDefault': {
|
|
128
|
+
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
129
|
+
'&.selected': {
|
|
130
|
+
borderBottom: `2px solid ${theme.palette[color].main}`,
|
|
131
|
+
marginBottom: '-1px',
|
|
132
|
+
backgroundColor: `${theme.palette[color].main}10`,
|
|
133
|
+
},
|
|
134
|
+
'&.error': {
|
|
135
|
+
borderBottom: `2px solid ${theme.palette.error.main}`,
|
|
136
|
+
marginBottom: '-1px',
|
|
137
|
+
backgroundColor: `${theme.palette.error.main}10`,
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
|
|
141
|
+
'&.variantOutlined': {
|
|
142
|
+
backgroundColor: theme.palette.background.paper,
|
|
143
|
+
border: `1px solid ${theme.palette.divider}`,
|
|
144
|
+
'&:not(:last-of-type)': {
|
|
145
|
+
marginBottom: '-1px',
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
'&.layoutList': {
|
|
149
|
+
'&:first-of-type, &.selected': {
|
|
150
|
+
...breakpointVal(
|
|
151
|
+
'borderTopLeftRadius',
|
|
152
|
+
theme.shape.borderRadius * 3,
|
|
153
|
+
theme.shape.borderRadius * 4,
|
|
154
|
+
theme.breakpoints.values,
|
|
155
|
+
),
|
|
156
|
+
...breakpointVal(
|
|
157
|
+
'borderTopRightRadius',
|
|
158
|
+
theme.shape.borderRadius * 3,
|
|
159
|
+
theme.shape.borderRadius * 4,
|
|
160
|
+
theme.breakpoints.values,
|
|
161
|
+
),
|
|
162
|
+
},
|
|
163
|
+
'&:last-of-type, &.selected': {
|
|
164
|
+
...breakpointVal(
|
|
165
|
+
'borderBottomLeftRadius',
|
|
166
|
+
theme.shape.borderRadius * 3,
|
|
167
|
+
theme.shape.borderRadius * 4,
|
|
168
|
+
theme.breakpoints.values,
|
|
169
|
+
),
|
|
170
|
+
...breakpointVal(
|
|
171
|
+
'borderBottomRightRadius',
|
|
172
|
+
theme.shape.borderRadius * 3,
|
|
173
|
+
theme.shape.borderRadius * 4,
|
|
174
|
+
theme.breakpoints.values,
|
|
175
|
+
),
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
'&:not(.layoutList)': {
|
|
179
|
+
...breakpointVal(
|
|
180
|
+
'borderRadius',
|
|
181
|
+
theme.shape.borderRadius * 3,
|
|
182
|
+
theme.shape.borderRadius * 4,
|
|
183
|
+
theme.breakpoints.values,
|
|
184
|
+
),
|
|
185
|
+
},
|
|
186
|
+
|
|
187
|
+
'&.selected': {
|
|
188
|
+
border: `2px solid ${theme.palette[color].main}`,
|
|
189
|
+
boxShadow: `0 0 0 4px ${alpha(
|
|
190
|
+
theme.palette[color].main,
|
|
191
|
+
theme.palette.action.hoverOpacity,
|
|
192
|
+
)}`,
|
|
193
|
+
|
|
194
|
+
'&.sizeSmall': { padding: `4px 9px` },
|
|
195
|
+
'&.sizeMedium': { padding: `9px 11px` },
|
|
196
|
+
'&.sizeLarge': {
|
|
197
|
+
padding: `calc(${theme.spacings.xxs} - 1px) calc(${theme.spacings.xs} - 1px)`,
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
'&.error': {
|
|
201
|
+
border: `2px solid ${theme.palette.error.main}`,
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
'&.selected': {
|
|
205
|
+
zIndex: 1,
|
|
206
|
+
},
|
|
207
|
+
'&.disabled': {
|
|
156
208
|
'& *': {
|
|
157
209
|
opacity: theme.palette.action.disabledOpacity,
|
|
158
210
|
},
|
|
@@ -160,64 +212,96 @@ export function ActionCard(props: ActionCardProps) {
|
|
|
160
212
|
theme.palette.action.disabledBackground,
|
|
161
213
|
theme.palette.action.disabledOpacity / 10,
|
|
162
214
|
),
|
|
163
|
-
}
|
|
164
|
-
|
|
215
|
+
},
|
|
216
|
+
}),
|
|
165
217
|
...(Array.isArray(sx) ? sx : [sx]),
|
|
166
218
|
]}
|
|
167
219
|
>
|
|
168
|
-
|
|
220
|
+
<Box
|
|
221
|
+
sx={{
|
|
222
|
+
display: 'flex',
|
|
223
|
+
flexDirection: 'row',
|
|
224
|
+
width: '100%',
|
|
225
|
+
justifyContent: 'space-between',
|
|
226
|
+
}}
|
|
227
|
+
>
|
|
169
228
|
<Box
|
|
170
|
-
className={classes.image}
|
|
171
229
|
sx={{
|
|
172
|
-
gridArea: 'image',
|
|
173
230
|
display: 'flex',
|
|
231
|
+
flexDirection: 'row',
|
|
232
|
+
justifyContent: 'space-between',
|
|
174
233
|
}}
|
|
175
234
|
>
|
|
176
|
-
{image
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
235
|
+
{image && (
|
|
236
|
+
<Box
|
|
237
|
+
className={classes.image}
|
|
238
|
+
sx={{ display: 'flex', paddingRight: '15px', alignSelf: 'center' }}
|
|
239
|
+
>
|
|
240
|
+
{image}
|
|
241
|
+
</Box>
|
|
242
|
+
)}
|
|
243
|
+
|
|
244
|
+
<Box
|
|
245
|
+
sx={{
|
|
246
|
+
display: 'flex',
|
|
247
|
+
justifyContent: 'center',
|
|
248
|
+
flexDirection: 'column',
|
|
249
|
+
alignItems: 'flex-start',
|
|
250
|
+
}}
|
|
251
|
+
>
|
|
252
|
+
{title && (
|
|
253
|
+
<Box
|
|
254
|
+
className={classes.title}
|
|
255
|
+
sx={{
|
|
256
|
+
typography: 'subtitle2',
|
|
257
|
+
'&.sizeMedium': { typographty: 'subtitle1' },
|
|
258
|
+
'&.sizeLarge': { typography: 'h6' },
|
|
259
|
+
}}
|
|
260
|
+
>
|
|
261
|
+
{title}
|
|
262
|
+
</Box>
|
|
263
|
+
)}
|
|
264
|
+
|
|
265
|
+
{details && (
|
|
266
|
+
<Box className={classes.details} sx={{ color: 'text.secondary' }}>
|
|
267
|
+
{details}
|
|
268
|
+
</Box>
|
|
269
|
+
)}
|
|
270
|
+
|
|
271
|
+
{secondaryAction && <Box className={classes.secondaryAction}>{secondaryAction}</Box>}
|
|
272
|
+
</Box>
|
|
199
273
|
</Box>
|
|
200
|
-
)}
|
|
201
274
|
|
|
202
|
-
{price && !disabled && (
|
|
203
275
|
<Box
|
|
204
|
-
|
|
205
|
-
|
|
276
|
+
sx={{
|
|
277
|
+
display: 'flex',
|
|
278
|
+
flexDirection: 'column',
|
|
279
|
+
justifyContent: 'space-between',
|
|
280
|
+
alignItems: 'flex-end',
|
|
281
|
+
}}
|
|
206
282
|
>
|
|
207
|
-
{
|
|
208
|
-
|
|
209
|
-
|
|
283
|
+
{action && (
|
|
284
|
+
<Box className={classes.action} sx={{ marginBottom: '5px' }}>
|
|
285
|
+
{!selected ? action : reset}
|
|
286
|
+
</Box>
|
|
287
|
+
)}
|
|
210
288
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
289
|
+
{price && !disabled && (
|
|
290
|
+
<Box
|
|
291
|
+
className={classes.price}
|
|
292
|
+
sx={{
|
|
293
|
+
textAlign: 'right',
|
|
294
|
+
typography: 'body1',
|
|
295
|
+
'&.sizeMedium': { typographty: 'subtitle1' },
|
|
296
|
+
'&.sizeLarge': { typography: 'h6' },
|
|
297
|
+
}}
|
|
298
|
+
>
|
|
299
|
+
{price}
|
|
300
|
+
</Box>
|
|
301
|
+
)}
|
|
219
302
|
</Box>
|
|
220
|
-
|
|
221
|
-
|
|
303
|
+
</Box>
|
|
304
|
+
{after && <Box className={classes.after}>{after}</Box>}
|
|
305
|
+
</RenderComponent>
|
|
222
306
|
)
|
|
223
307
|
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { Alert, Box } from '@mui/material'
|
|
1
|
+
import { Alert, Box, SxProps, Theme } from '@mui/material'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { isFragment } from 'react-is'
|
|
4
|
+
import { extendableComponent } from '../Styles'
|
|
4
5
|
import { ActionCardProps } from './ActionCard'
|
|
5
6
|
|
|
6
7
|
type MultiSelect = {
|
|
7
8
|
multiple: true
|
|
9
|
+
collapse?: false
|
|
8
10
|
value: (string | number)[]
|
|
9
11
|
|
|
10
12
|
onChange?: (event: React.MouseEvent<HTMLElement>, value: MultiSelect['value']) => void
|
|
@@ -12,6 +14,7 @@ type MultiSelect = {
|
|
|
12
14
|
type Select = {
|
|
13
15
|
multiple?: false
|
|
14
16
|
value: string | number
|
|
17
|
+
collapse?: boolean
|
|
15
18
|
|
|
16
19
|
/** Value is null when deselected when not required */
|
|
17
20
|
onChange?: (event: React.MouseEvent<HTMLElement>, value: Select['value'] | null) => void
|
|
@@ -22,7 +25,9 @@ export type ActionCardListProps<SelectOrMulti = MultiSelect | Select> = {
|
|
|
22
25
|
required?: boolean
|
|
23
26
|
error?: boolean
|
|
24
27
|
errorMessage?: string
|
|
25
|
-
|
|
28
|
+
sx?: SxProps<Theme>
|
|
29
|
+
} & SelectOrMulti &
|
|
30
|
+
HoistedActionCardProps
|
|
26
31
|
|
|
27
32
|
function isMulti(props: ActionCardListProps): props is ActionCardListProps<MultiSelect> {
|
|
28
33
|
return props.multiple === true
|
|
@@ -37,9 +42,30 @@ function isValueSelected(
|
|
|
37
42
|
return value === candidate
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
type HoistedActionCardProps = Pick<ActionCardProps, 'color' | 'variant' | 'size' | 'layout'>
|
|
46
|
+
|
|
47
|
+
const parts = ['root'] as const
|
|
48
|
+
const name = 'ActionCardList'
|
|
49
|
+
const { withState, selectors } = extendableComponent<
|
|
50
|
+
HoistedActionCardProps,
|
|
51
|
+
typeof name,
|
|
52
|
+
typeof parts
|
|
53
|
+
>(name, parts)
|
|
54
|
+
|
|
40
55
|
export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListProps>(
|
|
41
56
|
(props, ref) => {
|
|
42
|
-
const {
|
|
57
|
+
const {
|
|
58
|
+
children,
|
|
59
|
+
required,
|
|
60
|
+
error = false,
|
|
61
|
+
errorMessage,
|
|
62
|
+
size = 'medium',
|
|
63
|
+
color = 'primary',
|
|
64
|
+
variant = 'outlined',
|
|
65
|
+
layout = 'list',
|
|
66
|
+
collapse = false,
|
|
67
|
+
sx = [],
|
|
68
|
+
} = props
|
|
43
69
|
|
|
44
70
|
const handleChange: ActionCardProps['onClick'] = isMulti(props)
|
|
45
71
|
? (event, v) => {
|
|
@@ -65,8 +91,10 @@ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListPro
|
|
|
65
91
|
}
|
|
66
92
|
|
|
67
93
|
type ActionCardLike = React.ReactElement<
|
|
68
|
-
Pick<ActionCardProps, 'value' | 'selected' | 'disabled' | 'onClick' | '
|
|
94
|
+
Pick<ActionCardProps, 'value' | 'selected' | 'disabled' | 'onClick' | 'error' | 'onClick'> &
|
|
95
|
+
HoistedActionCardProps
|
|
69
96
|
>
|
|
97
|
+
|
|
70
98
|
function isActionCardLike(el: React.ReactElement): el is ActionCardLike {
|
|
71
99
|
const hasValue = (el as ActionCardLike).props.value
|
|
72
100
|
|
|
@@ -100,55 +128,68 @@ export const ActionCardList = React.forwardRef<HTMLDivElement, ActionCardListPro
|
|
|
100
128
|
(child) => child.props.value === props.value && child.props.disabled !== true,
|
|
101
129
|
)?.props.value
|
|
102
130
|
|
|
131
|
+
const classes = withState({ size, color, variant, layout })
|
|
132
|
+
|
|
103
133
|
return (
|
|
104
|
-
<
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
134
|
+
<div>
|
|
135
|
+
<Box
|
|
136
|
+
className={classes.root}
|
|
137
|
+
ref={ref}
|
|
138
|
+
sx={[
|
|
139
|
+
(theme) => ({
|
|
140
|
+
'&.layoutStack': {
|
|
141
|
+
display: 'grid',
|
|
142
|
+
height: 'min-content',
|
|
143
|
+
gap: theme.spacings.xxs,
|
|
144
|
+
},
|
|
145
|
+
'&.layoutList': {
|
|
146
|
+
display: 'grid',
|
|
147
|
+
height: 'min-content',
|
|
148
|
+
},
|
|
149
|
+
'&.layoutGrid': {
|
|
150
|
+
display: 'grid',
|
|
151
|
+
gridTemplateColumns: 'repeat(2, 1fr)',
|
|
152
|
+
gap: theme.spacings.xxs,
|
|
153
|
+
},
|
|
154
|
+
'&.layoutInline': {
|
|
155
|
+
display: 'flex',
|
|
156
|
+
flexWrap: 'wrap',
|
|
157
|
+
gap: theme.spacings.xxs,
|
|
158
|
+
},
|
|
159
|
+
}),
|
|
160
|
+
|
|
161
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
162
|
+
]}
|
|
163
|
+
>
|
|
164
|
+
{childReactNodes.map((child) => {
|
|
165
|
+
if (collapse && Boolean(value) && !isValueSelected(child.props.value, value))
|
|
166
|
+
return null
|
|
167
|
+
return React.cloneElement(child, {
|
|
168
|
+
onClick: handleChange,
|
|
169
|
+
error: child.props.error ?? error,
|
|
170
|
+
color: child.props.color ?? color,
|
|
171
|
+
variant: child.props.variant ?? variant,
|
|
172
|
+
size: child.props.size ?? size,
|
|
173
|
+
layout: child.props.layout ?? layout,
|
|
174
|
+
selected:
|
|
175
|
+
child.props.selected === undefined
|
|
176
|
+
? isValueSelected(child.props.value, value)
|
|
177
|
+
: child.props.selected,
|
|
178
|
+
})
|
|
179
|
+
})}
|
|
180
|
+
</Box>
|
|
181
|
+
{error && errorMessage && (
|
|
182
|
+
<Alert
|
|
183
|
+
severity='error'
|
|
184
|
+
variant='standard'
|
|
185
|
+
sx={(theme) => ({
|
|
186
|
+
marginTop: theme.spacings.xxs,
|
|
187
|
+
})}
|
|
188
|
+
>
|
|
189
|
+
{errorMessage}
|
|
190
|
+
</Alert>
|
|
150
191
|
)}
|
|
151
|
-
</
|
|
192
|
+
</div>
|
|
152
193
|
)
|
|
153
194
|
},
|
|
154
195
|
)
|
|
@@ -6,37 +6,37 @@ import { ActionCardList, ActionCardListProps } from './ActionCardList'
|
|
|
6
6
|
|
|
7
7
|
export type ActionCardItemBase = Pick<ActionCardProps, 'value'>
|
|
8
8
|
|
|
9
|
-
export type ActionCardItemRenderProps<T> =
|
|
10
|
-
ActionCardProps,
|
|
11
|
-
'selected' | 'hidden' | 'value'
|
|
12
|
-
> & {
|
|
9
|
+
export type ActionCardItemRenderProps<T> = ActionCardProps & {
|
|
13
10
|
onReset: MouseEventHandler<HTMLAnchorElement> & MouseEventHandler<HTMLSpanElement>
|
|
14
11
|
} & T
|
|
15
12
|
|
|
16
13
|
export type ActionCardListFormProps<T extends ActionCardItemBase> = Omit<
|
|
17
14
|
ActionCardListProps,
|
|
18
|
-
'value'
|
|
15
|
+
'value' | 'error' | 'onChange' | 'children' | 'multiple'
|
|
19
16
|
> &
|
|
20
|
-
Omit<ControllerProps<any>, 'render'> & {
|
|
17
|
+
Omit<ControllerProps<any>, 'render' | 'shouldUnregister'> & {
|
|
21
18
|
items: T[]
|
|
22
|
-
render: React.
|
|
19
|
+
render: React.FC<ActionCardItemRenderProps<T>>
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
export function ActionCardListForm<T extends ActionCardItemBase>(
|
|
26
23
|
props: ActionCardListFormProps<T>,
|
|
27
24
|
) {
|
|
28
|
-
const { required, rules, items, render, control, name, errorMessage } =
|
|
29
|
-
|
|
25
|
+
const { required, rules, items, render, control, name, errorMessage, defaultValue, ...other } =
|
|
26
|
+
props
|
|
27
|
+
const RenderItem = render as React.FC<ActionCardItemRenderProps<ActionCardItemBase>>
|
|
30
28
|
|
|
31
29
|
return (
|
|
32
30
|
<Controller
|
|
33
31
|
{...props}
|
|
34
32
|
control={control}
|
|
35
33
|
name={name}
|
|
36
|
-
|
|
34
|
+
defaultValue={defaultValue}
|
|
35
|
+
rules={{ required: errorMessage || required, ...rules }}
|
|
37
36
|
render={({ field: { onChange, value, ref }, fieldState, formState }) => (
|
|
38
37
|
<ActionCardList
|
|
39
|
-
|
|
38
|
+
{...other}
|
|
39
|
+
required={required}
|
|
40
40
|
value={value}
|
|
41
41
|
ref={ref}
|
|
42
42
|
onChange={(_, incomming) => onChange(incomming)}
|
package/Button/Button.tsx
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
/* eslint-disable react/forbid-foreign-prop-types */
|
|
2
|
-
import { LoadingButton as Button, LoadingButtonProps } from '@mui/lab'
|
|
2
|
+
import { LoadingButton as Button, LoadingButtonProps, LoadingButtonTypeMap } from '@mui/lab'
|
|
3
|
+
|
|
4
|
+
export type ButtonProps<
|
|
5
|
+
D extends React.ElementType = LoadingButtonTypeMap['defaultComponent'],
|
|
6
|
+
P = {},
|
|
7
|
+
> = LoadingButtonProps<D, P>
|
|
3
8
|
|
|
4
|
-
export type ButtonProps = LoadingButtonProps
|
|
5
9
|
export { Button }
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
## 4.27.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#1642](https://github.com/graphcommerce-org/graphcommerce/pull/1642) [`ad63ebf4e`](https://github.com/graphcommerce-org/graphcommerce/commit/ad63ebf4e33bfb0e5c9e5e68ab69b14775f3f8a8) Thanks [@paales](https://github.com/paales)! - Introduced `<AddProductsToCartForm/>`, which is allows for adding all product types to the cart with a single react-hook-form form.
|
|
8
|
+
|
|
9
|
+
Which allows you to fully compose the form on the product page without having to modify the page.
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Updated dependencies []:
|
|
14
|
+
- @graphcommerce/framer-scroller@2.1.39
|
|
15
|
+
|
|
16
|
+
## 4.26.0
|
|
17
|
+
|
|
18
|
+
### Minor Changes
|
|
19
|
+
|
|
20
|
+
- [#1651](https://github.com/graphcommerce-org/graphcommerce/pull/1651) [`42e7fac75`](https://github.com/graphcommerce-org/graphcommerce/commit/42e7fac75712f9bda7a6b919ede14b3c75d07771) Thanks [@ErwinOtten](https://github.com/ErwinOtten)! - Correct component usage in /service
|
|
21
|
+
|
|
22
|
+
### Patch Changes
|
|
23
|
+
|
|
24
|
+
- Updated dependencies []:
|
|
25
|
+
- @graphcommerce/framer-scroller@2.1.38
|
|
26
|
+
|
|
3
27
|
## 4.25.0
|
|
4
28
|
|
|
5
29
|
### Minor Changes
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { Fab, useTheme, Box, styled, SxProps, Theme } from '@mui/material'
|
|
11
11
|
import { m, useDomEvent, useMotionValue } from 'framer-motion'
|
|
12
12
|
import { useRouter } from 'next/router'
|
|
13
|
-
import React, { useEffect, useRef } from 'react'
|
|
13
|
+
import React, { useEffect, useMemo, useRef, useState } from 'react'
|
|
14
14
|
import { IconSvg } from '../IconSvg'
|
|
15
15
|
import { Row } from '../Row/Row'
|
|
16
16
|
import { extendableComponent } from '../Styles'
|
|
@@ -42,6 +42,13 @@ export function RenderType<
|
|
|
42
42
|
export function findByTypename<T extends TypeObject, Typename extends T['__typename']>(
|
|
43
43
|
type: (T | undefined | null)[] | undefined | null,
|
|
44
44
|
typename: Typename,
|
|
45
|
-
): FilterTypeByTypename<T, Typename> {
|
|
45
|
+
): FilterTypeByTypename<T, Typename> | undefined {
|
|
46
46
|
return type?.find((item) => item?.__typename === typename) as FilterTypeByTypename<T, Typename>
|
|
47
47
|
}
|
|
48
|
+
|
|
49
|
+
export function isTypename<T extends TypeObject, Typenames extends T['__typename'][]>(
|
|
50
|
+
type: FilterTypeByTypename<T, T['__typename']>,
|
|
51
|
+
typename: Typenames,
|
|
52
|
+
): type is FilterTypeByTypename<T, Typenames[number]> {
|
|
53
|
+
return typename.includes(type.__typename)
|
|
54
|
+
}
|
|
@@ -3,7 +3,7 @@ import type { OptionalKeysOf, Simplify } from 'type-fest'
|
|
|
3
3
|
export function filterNonNullableKeys<
|
|
4
4
|
T extends Record<string, unknown>,
|
|
5
5
|
Keys extends OptionalKeysOf<T>,
|
|
6
|
-
>(items: (T | null | undefined)[] | null | undefined, values: Keys[]) {
|
|
6
|
+
>(items: (T | null | undefined)[] | null | undefined, values: Keys[] = []) {
|
|
7
7
|
if (!items) return []
|
|
8
8
|
|
|
9
9
|
type ResultWithRequired = Simplify<
|
|
@@ -1,29 +1,36 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ListItemButtonProps, ListItemButton, ListItemIcon, ListItemText } from '@mui/material'
|
|
2
2
|
import PageLink from 'next/link'
|
|
3
3
|
import React from 'react'
|
|
4
4
|
import { IconSvg } from '../../IconSvg'
|
|
5
5
|
import { iconChevronRight } from '../../icons'
|
|
6
6
|
|
|
7
|
-
export type ButtonLinkListItemProps = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
textDecoration: 'none',
|
|
12
|
-
padding: `${theme.spacings.xs} 0`,
|
|
13
|
-
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
14
|
-
borderRadius: 0,
|
|
15
|
-
justifyContent: 'space-between',
|
|
16
|
-
typography: 'body1',
|
|
17
|
-
}))
|
|
7
|
+
export type ButtonLinkListItemProps = {
|
|
8
|
+
url: string
|
|
9
|
+
endIcon?: React.ReactNode
|
|
10
|
+
} & ListItemButtonProps
|
|
18
11
|
|
|
19
12
|
export function ButtonLinkListItem(props: ButtonLinkListItemProps) {
|
|
20
|
-
const {
|
|
13
|
+
const {
|
|
14
|
+
children,
|
|
15
|
+
url,
|
|
16
|
+
endIcon = <IconSvg src={iconChevronRight} />,
|
|
17
|
+
...ButtonLinkListItemProps
|
|
18
|
+
} = props
|
|
21
19
|
|
|
22
20
|
return (
|
|
23
21
|
<PageLink href={url} passHref>
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
<ListItemButton
|
|
23
|
+
LinkComponent='a'
|
|
24
|
+
sx={(theme) => ({
|
|
25
|
+
padding: `${theme.spacings.xxs} 0`,
|
|
26
|
+
borderBottom: `1px solid ${theme.palette.divider}`,
|
|
27
|
+
justifyContent: 'space-between',
|
|
28
|
+
})}
|
|
29
|
+
{...ButtonLinkListItemProps}
|
|
30
|
+
>
|
|
31
|
+
<ListItemText>{children}</ListItemText>
|
|
32
|
+
<ListItemIcon>{endIcon}</ListItemIcon>
|
|
33
|
+
</ListItemButton>
|
|
27
34
|
</PageLink>
|
|
28
35
|
)
|
|
29
36
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Typography, Button, SxProps, Theme, Box } from '@mui/material'
|
|
1
|
+
import { Typography, Button, SxProps, Theme, Box, ButtonProps } from '@mui/material'
|
|
2
2
|
import React from 'react'
|
|
3
3
|
import { extendableComponent } from '../../Styles'
|
|
4
4
|
|
|
@@ -8,65 +8,43 @@ export type IconBlockProps = {
|
|
|
8
8
|
children: React.ReactNode
|
|
9
9
|
href?: string
|
|
10
10
|
sx?: SxProps<Theme>
|
|
11
|
-
}
|
|
11
|
+
} & ButtonProps
|
|
12
12
|
|
|
13
13
|
const name = 'IconBlock' as const
|
|
14
14
|
const parts = ['block', 'link', 'title'] as const
|
|
15
15
|
const { classes } = extendableComponent(name, parts)
|
|
16
16
|
|
|
17
17
|
export const IconBlock = React.forwardRef<HTMLAnchorElement, IconBlockProps>((props, ref) => {
|
|
18
|
-
const { title, children, icon, href, sx = [] } = props
|
|
19
|
-
|
|
20
|
-
const content = (
|
|
21
|
-
<>
|
|
22
|
-
{icon}
|
|
23
|
-
<Typography
|
|
24
|
-
variant='subtitle1'
|
|
25
|
-
className={classes.title}
|
|
26
|
-
sx={(theme) => ({ fontWeight: theme.typography.fontWeightBold })}
|
|
27
|
-
component='span'
|
|
28
|
-
>
|
|
29
|
-
{title}
|
|
30
|
-
</Typography>
|
|
31
|
-
{children}
|
|
32
|
-
</>
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
const blockSx: SxProps<Theme> = [
|
|
36
|
-
(theme) => ({
|
|
37
|
-
border: `1px solid ${theme.palette.divider}`,
|
|
38
|
-
padding: `${theme.spacings.sm}`,
|
|
39
|
-
borderRadius: '6px',
|
|
40
|
-
textAlign: 'center',
|
|
41
|
-
color: theme.palette.text.primary,
|
|
42
|
-
'& > *': {
|
|
43
|
-
display: 'grid',
|
|
44
|
-
gridAutoFlow: 'row',
|
|
45
|
-
justifyItems: 'center',
|
|
46
|
-
gap: `${theme.spacings.xxs}`,
|
|
47
|
-
},
|
|
48
|
-
}),
|
|
49
|
-
...(Array.isArray(sx) ? sx : [sx]),
|
|
50
|
-
]
|
|
51
|
-
|
|
52
|
-
if (href) {
|
|
53
|
-
return (
|
|
54
|
-
<Button
|
|
55
|
-
href={href}
|
|
56
|
-
variant='text'
|
|
57
|
-
color='primary'
|
|
58
|
-
className={classes.block}
|
|
59
|
-
ref={ref}
|
|
60
|
-
sx={blockSx}
|
|
61
|
-
>
|
|
62
|
-
<div>{content}</div>
|
|
63
|
-
</Button>
|
|
64
|
-
)
|
|
65
|
-
}
|
|
18
|
+
const { title, children, icon, href = '#', sx = [], ...buttonProps } = props
|
|
66
19
|
|
|
67
20
|
return (
|
|
68
|
-
<
|
|
69
|
-
{
|
|
70
|
-
|
|
21
|
+
<Button
|
|
22
|
+
href={href}
|
|
23
|
+
variant='outlined'
|
|
24
|
+
color='primary'
|
|
25
|
+
className={classes.block}
|
|
26
|
+
{...buttonProps}
|
|
27
|
+
sx={[
|
|
28
|
+
(theme) => ({
|
|
29
|
+
padding: `${theme.spacings.sm}`,
|
|
30
|
+
textAlign: 'center',
|
|
31
|
+
'& > *': {
|
|
32
|
+
display: 'grid',
|
|
33
|
+
gridAutoFlow: 'row',
|
|
34
|
+
justifyItems: 'center',
|
|
35
|
+
gap: `${theme.spacings.xxs}`,
|
|
36
|
+
},
|
|
37
|
+
}),
|
|
38
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
39
|
+
]}
|
|
40
|
+
>
|
|
41
|
+
<Box>
|
|
42
|
+
{icon}
|
|
43
|
+
<Typography variant='subtitle1' className={classes.title} component='span'>
|
|
44
|
+
{title}
|
|
45
|
+
</Typography>
|
|
46
|
+
{children}
|
|
47
|
+
</Box>
|
|
48
|
+
</Button>
|
|
71
49
|
)
|
|
72
50
|
})
|
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.27.0",
|
|
6
6
|
"author": "",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"sideEffects": false,
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@emotion/server": "^11.4.0",
|
|
21
21
|
"@emotion/styled": "^11.9.3",
|
|
22
22
|
"@graphcommerce/framer-next-pages": "3.3.0",
|
|
23
|
-
"@graphcommerce/framer-scroller": "2.1.
|
|
23
|
+
"@graphcommerce/framer-scroller": "2.1.39",
|
|
24
24
|
"@graphcommerce/framer-utils": "3.2.0",
|
|
25
25
|
"@graphcommerce/image": "3.1.9",
|
|
26
26
|
"cookie": "^0.5.0",
|