@graphcommerce/ecommerce-ui 8.1.0-canary.2 → 8.1.0-canary.5
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 +91 -1
- package/components/FormComponents/CheckboxButtonGroup.tsx +1 -0
- package/components/FormComponents/CheckboxElement.tsx +6 -4
- package/components/FormComponents/MultiSelectElement.tsx +20 -19
- package/components/FormComponents/NumberFieldElement.tsx +113 -108
- package/components/FormComponents/PasswordRepeatElement.tsx +1 -1
- package/components/FormComponents/RadioButtonGroup.tsx +1 -0
- package/components/FormComponents/SelectElement.tsx +65 -42
- package/components/FormComponents/SliderElement.tsx +3 -7
- package/components/FormComponents/TextFieldElement.tsx +39 -35
- package/components/FormComponents/ToggleButtonGroup.tsx +1 -0
- package/components/WaitForQueries/WaitForQueries.tsx +7 -8
- package/package.json +7 -7
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,96 @@
|
|
|
1
1
|
# @graphcommerce/ecommerce-ui
|
|
2
2
|
|
|
3
|
-
## 8.1.0-canary.
|
|
3
|
+
## 8.1.0-canary.5
|
|
4
|
+
|
|
5
|
+
## 8.0.6-canary.4
|
|
6
|
+
|
|
7
|
+
## 8.0.6-canary.3
|
|
8
|
+
|
|
9
|
+
## 8.0.6-canary.2
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`0767bc4`](https://github.com/graphcommerce-org/graphcommerce/commit/0767bc40f7b596209f24ca4e745ff0441f3275c9) - Upgrade input components to no longer use muiRegister, which improves INP scores
|
|
14
|
+
([@FrankHarland](https://github.com/FrankHarland))
|
|
15
|
+
|
|
16
|
+
- [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`43bd04a`](https://github.com/graphcommerce-org/graphcommerce/commit/43bd04a777c5800cc7e01bee1e123a5aad82f194) - Make sure the TextFieldElement doesn’t give a uncontrolled to controlled warning.
|
|
17
|
+
Convert SelectElement to useController instead of a separate Controller component.
|
|
18
|
+
Make sure the original endAdornment is always shown only until the value is valid ([@FrankHarland](https://github.com/FrankHarland))
|
|
19
|
+
|
|
20
|
+
- [#2234](https://github.com/graphcommerce-org/graphcommerce/pull/2234) [`d4e693d`](https://github.com/graphcommerce-org/graphcommerce/commit/d4e693d553198c9a1ef398d000ca23d209e6c2ba) - The `<WaitForQueries/>` component now uses the useIsSSR hook which prevents loading spinners when navigating on the client, which make all account/cart/checkout pages faster.
|
|
21
|
+
([@FrankHarland](https://github.com/FrankHarland))
|
|
22
|
+
|
|
23
|
+
## 8.0.6-canary.1
|
|
24
|
+
|
|
25
|
+
## 8.0.6-canary.0
|
|
26
|
+
|
|
27
|
+
## 8.0.5
|
|
28
|
+
|
|
29
|
+
## 8.0.5-canary.10
|
|
30
|
+
|
|
31
|
+
## 8.0.5-canary.9
|
|
32
|
+
|
|
33
|
+
## 8.0.5-canary.8
|
|
34
|
+
|
|
35
|
+
## 8.0.5-canary.7
|
|
36
|
+
|
|
37
|
+
## 8.0.5-canary.6
|
|
38
|
+
|
|
39
|
+
## 8.0.5-canary.5
|
|
40
|
+
|
|
41
|
+
## 8.0.5-canary.4
|
|
42
|
+
|
|
43
|
+
## 8.0.5-canary.3
|
|
44
|
+
|
|
45
|
+
## 8.0.5-canary.2
|
|
46
|
+
|
|
47
|
+
## 8.0.5-canary.1
|
|
48
|
+
|
|
49
|
+
## 8.0.5-canary.0
|
|
50
|
+
|
|
51
|
+
## 8.0.4
|
|
52
|
+
|
|
53
|
+
## 8.0.4-canary.1
|
|
54
|
+
|
|
55
|
+
## 8.0.4-canary.0
|
|
56
|
+
|
|
57
|
+
## 8.0.3
|
|
58
|
+
|
|
59
|
+
### Patch Changes
|
|
60
|
+
|
|
61
|
+
- [#2212](https://github.com/graphcommerce-org/graphcommerce/pull/2212) [`e12d1dc`](https://github.com/graphcommerce-org/graphcommerce/commit/e12d1dc201bf7b23a996bd58a256a117b91a9334) - Rename validation to rules for all Form field components and deprecate validation
|
|
62
|
+
([@paales](https://github.com/paales))
|
|
63
|
+
|
|
64
|
+
- [#2203](https://github.com/graphcommerce-org/graphcommerce/pull/2203) [`7ef7dc7`](https://github.com/graphcommerce-org/graphcommerce/commit/7ef7dc7631f61a2feba67a531a210df9c22fed4b) - CheckboxElement, MultiSelectElement, NumberFieldElement, SelectElement, SliderElement and TextFieldElement have their inputRef passed, allowing focus to be set by the form.
|
|
65
|
+
([@Jessevdpoel](https://github.com/Jessevdpoel))
|
|
66
|
+
|
|
67
|
+
- [#2205](https://github.com/graphcommerce-org/graphcommerce/pull/2205) [`eb14696`](https://github.com/graphcommerce-org/graphcommerce/commit/eb14696fc65e084a06790c88a8218fb3003f7c2c) - `<WaitForQueries/>` will default to loading, restoring the previous behavior. This might introduce , this might introduce an additional spinner but prevents a flash where it is shown that there is no cart
|
|
68
|
+
([@paales](https://github.com/paales))
|
|
69
|
+
|
|
70
|
+
## 8.0.3-canary.6
|
|
71
|
+
|
|
72
|
+
## 8.0.3-canary.5
|
|
73
|
+
|
|
74
|
+
### Patch Changes
|
|
75
|
+
|
|
76
|
+
- [#2212](https://github.com/graphcommerce-org/graphcommerce/pull/2212) [`e12d1dc`](https://github.com/graphcommerce-org/graphcommerce/commit/e12d1dc201bf7b23a996bd58a256a117b91a9334) - Rename validation to rules for all Form field components and deprecate validation
|
|
77
|
+
([@paales](https://github.com/paales))
|
|
78
|
+
|
|
79
|
+
## 8.0.3-canary.4
|
|
80
|
+
|
|
81
|
+
### Patch Changes
|
|
82
|
+
|
|
83
|
+
- [#2203](https://github.com/graphcommerce-org/graphcommerce/pull/2203) [`7ef7dc7`](https://github.com/graphcommerce-org/graphcommerce/commit/7ef7dc7631f61a2feba67a531a210df9c22fed4b) - CheckboxElement, MultiSelectElement, NumberFieldElement, SelectElement, SliderElement and TextFieldElement have their inputRef passed, allowing focus to be set by the form.
|
|
84
|
+
([@Jessevdpoel](https://github.com/Jessevdpoel))
|
|
85
|
+
|
|
86
|
+
## 8.0.3-canary.3
|
|
87
|
+
|
|
88
|
+
## 8.0.3-canary.2
|
|
89
|
+
|
|
90
|
+
### Patch Changes
|
|
91
|
+
|
|
92
|
+
- [#2205](https://github.com/graphcommerce-org/graphcommerce/pull/2205) [`eb14696`](https://github.com/graphcommerce-org/graphcommerce/commit/eb14696fc65e084a06790c88a8218fb3003f7c2c) - `<WaitForQueries/>` will default to loading, restoring the previous behavior. This might introduce , this might introduce an additional spinner but prevents a flash where it is shown that there is no cart
|
|
93
|
+
([@paales](https://github.com/paales))
|
|
4
94
|
|
|
5
95
|
## 8.0.3-canary.1
|
|
6
96
|
|
|
@@ -21,6 +21,7 @@ export type CheckboxButtonGroupProps<T extends FieldValues> = {
|
|
|
21
21
|
options: { id: string | number; label: string }[] | any[]
|
|
22
22
|
helperText?: string
|
|
23
23
|
required?: boolean
|
|
24
|
+
/** @deprecated Form value parsing should happen in the handleSubmit function of the form */
|
|
24
25
|
parseError?: (error: FieldError) => string
|
|
25
26
|
label?: string
|
|
26
27
|
labelKey?: string
|
|
@@ -19,6 +19,7 @@ import {
|
|
|
19
19
|
} from '@mui/material'
|
|
20
20
|
|
|
21
21
|
export type CheckboxElementProps<T extends FieldValues> = Omit<CheckboxProps, 'name'> & {
|
|
22
|
+
/** @deprecated Form value parsing should happen in the handleSubmit function of the form */
|
|
22
23
|
parseError?: (error: FieldError) => string
|
|
23
24
|
label?: FormControlLabelProps['label']
|
|
24
25
|
helperText?: string
|
|
@@ -47,7 +48,8 @@ export function CheckboxElement<TFieldValues extends FieldValues>({
|
|
|
47
48
|
name={name}
|
|
48
49
|
rules={rules}
|
|
49
50
|
control={control}
|
|
50
|
-
render={({ field: { value, onChange }, fieldState: { invalid, error } }) => {
|
|
51
|
+
render={({ field: { value, onChange, ref, ...field }, fieldState: { invalid, error } }) => {
|
|
52
|
+
// eslint-disable-next-line no-nested-ternary
|
|
51
53
|
const parsedHelperText = error
|
|
52
54
|
? typeof parseError === 'function'
|
|
53
55
|
? parseError(error)
|
|
@@ -61,6 +63,8 @@ export function CheckboxElement<TFieldValues extends FieldValues>({
|
|
|
61
63
|
control={
|
|
62
64
|
<Checkbox
|
|
63
65
|
{...rest}
|
|
66
|
+
{...field}
|
|
67
|
+
inputRef={ref}
|
|
64
68
|
color={rest.color || 'primary'}
|
|
65
69
|
sx={{
|
|
66
70
|
...(Array.isArray(sx) ? sx : [sx]),
|
|
@@ -68,9 +72,7 @@ export function CheckboxElement<TFieldValues extends FieldValues>({
|
|
|
68
72
|
}}
|
|
69
73
|
value={value}
|
|
70
74
|
checked={!!value}
|
|
71
|
-
onChange={() =>
|
|
72
|
-
onChange(!value)
|
|
73
|
-
}}
|
|
75
|
+
onChange={() => onChange(!value)}
|
|
74
76
|
/>
|
|
75
77
|
}
|
|
76
78
|
/>
|
|
@@ -27,6 +27,7 @@ export type MultiSelectElementProps<T extends FieldValues> = Omit<SelectProps, '
|
|
|
27
27
|
itemValue?: string
|
|
28
28
|
itemLabel?: string
|
|
29
29
|
required?: boolean
|
|
30
|
+
/** @deprecated Form value parsing should happen in the handleSubmit function of the form */
|
|
30
31
|
parseError?: (error: FieldError) => string
|
|
31
32
|
minWidth?: number
|
|
32
33
|
menuMaxHeight?: number
|
|
@@ -72,7 +73,7 @@ export function MultiSelectElement<TFieldValues extends FieldValues>(
|
|
|
72
73
|
name={name}
|
|
73
74
|
rules={rules}
|
|
74
75
|
control={control}
|
|
75
|
-
render={({ field: { value, onChange,
|
|
76
|
+
render={({ field: { value, onChange, ...field }, fieldState: { invalid, error } }) => {
|
|
76
77
|
helperText = error
|
|
77
78
|
? typeof parseError === 'function'
|
|
78
79
|
? parseError(error)
|
|
@@ -102,6 +103,7 @@ export function MultiSelectElement<TFieldValues extends FieldValues>(
|
|
|
102
103
|
)}
|
|
103
104
|
<Select
|
|
104
105
|
{...rest}
|
|
106
|
+
{...field}
|
|
105
107
|
id={rest.id || `select-multi-select-${name}`}
|
|
106
108
|
multiple
|
|
107
109
|
label={label || undefined}
|
|
@@ -109,7 +111,6 @@ export function MultiSelectElement<TFieldValues extends FieldValues>(
|
|
|
109
111
|
value={value || []}
|
|
110
112
|
required={required}
|
|
111
113
|
onChange={onChange}
|
|
112
|
-
onBlur={onBlur}
|
|
113
114
|
MenuProps={{
|
|
114
115
|
...rest.MenuProps,
|
|
115
116
|
PaperProps: {
|
|
@@ -126,23 +127,23 @@ export function MultiSelectElement<TFieldValues extends FieldValues>(
|
|
|
126
127
|
typeof rest.renderValue === 'function'
|
|
127
128
|
? rest.renderValue
|
|
128
129
|
: showChips
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
130
|
+
? (selected) => (
|
|
131
|
+
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
|
|
132
|
+
{((selected as any[]) || []).map((selectedValue) => (
|
|
133
|
+
<Chip
|
|
134
|
+
key={selectedValue}
|
|
135
|
+
label={selectedValue}
|
|
136
|
+
style={{ display: 'flex', flexWrap: 'wrap' }}
|
|
137
|
+
onDelete={() => {
|
|
138
|
+
onChange(value.filter((i: any) => i !== selectedValue))
|
|
139
|
+
// setValue(name, formValue.filter((i: any) => i !== value), { shouldValidate: true })
|
|
140
|
+
}}
|
|
141
|
+
deleteIcon={<IconSvg src={iconClose} />}
|
|
142
|
+
/>
|
|
143
|
+
))}
|
|
144
|
+
</div>
|
|
145
|
+
)
|
|
146
|
+
: (selected) => (Array.isArray(selected) ? selected.join(', ') : '')
|
|
146
147
|
}
|
|
147
148
|
>
|
|
148
149
|
{options.map((item) => {
|
|
@@ -5,7 +5,12 @@ import {
|
|
|
5
5
|
IconSvg,
|
|
6
6
|
responsiveVal,
|
|
7
7
|
} from '@graphcommerce/next-ui'
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Controller,
|
|
10
|
+
ControllerProps,
|
|
11
|
+
FieldValues,
|
|
12
|
+
useController,
|
|
13
|
+
} from '@graphcommerce/react-hook-form'
|
|
9
14
|
import { i18n } from '@lingui/core'
|
|
10
15
|
import { IconButtonProps, SxProps, Theme, TextField, TextFieldProps, Fab } from '@mui/material'
|
|
11
16
|
|
|
@@ -48,117 +53,117 @@ export function NumberFieldElement<T extends FieldValues>(props: NumberFieldElem
|
|
|
48
53
|
rules.required = i18n._(/* i18n */ 'This field is required')
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
const {
|
|
57
|
+
field: { value, onChange, ref, ...field },
|
|
58
|
+
fieldState: { invalid, error },
|
|
59
|
+
} = useController({
|
|
60
|
+
name,
|
|
61
|
+
control,
|
|
62
|
+
rules,
|
|
63
|
+
defaultValue,
|
|
64
|
+
})
|
|
59
65
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
const valueAsNumber = value ? parseFloat(value) : 0
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<TextField
|
|
70
|
+
{...textFieldProps}
|
|
71
|
+
{...field}
|
|
72
|
+
inputRef={ref}
|
|
73
|
+
value={value ?? ''}
|
|
74
|
+
onChange={(ev) => {
|
|
75
|
+
const newValue = (ev.target as HTMLInputElement).valueAsNumber
|
|
76
|
+
onChange(Number.isNaN(newValue) ? '' : newValue)
|
|
77
|
+
textFieldProps.onChange?.(ev)
|
|
78
|
+
}}
|
|
79
|
+
variant={variant}
|
|
80
|
+
required={required}
|
|
81
|
+
error={invalid}
|
|
82
|
+
helperText={error ? error.message : textFieldProps.helperText}
|
|
83
|
+
size={size}
|
|
84
|
+
type='number'
|
|
85
|
+
className={`${textFieldProps.className ?? ''} ${classes.quantity}`}
|
|
86
|
+
sx={[
|
|
87
|
+
{
|
|
88
|
+
width: responsiveVal(90, 120),
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
'& input[type=number]': {
|
|
92
|
+
MozAppearance: 'textfield',
|
|
93
|
+
},
|
|
94
|
+
'& .MuiOutlinedInput-root': {
|
|
95
|
+
px: '2px',
|
|
96
|
+
display: 'grid',
|
|
97
|
+
gridTemplateColumns: '1fr auto 1fr',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
variant === 'standard' && {
|
|
101
|
+
'& .MuiOutlinedInput-input': {
|
|
102
|
+
padding: 0,
|
|
103
|
+
},
|
|
104
|
+
'& .MuiOutlinedInput-notchedOutline': {
|
|
105
|
+
display: 'none',
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
...(Array.isArray(sx) ? sx : [sx]),
|
|
109
|
+
]}
|
|
110
|
+
autoComplete='off'
|
|
111
|
+
InputProps={{
|
|
112
|
+
...textFieldProps.InputProps,
|
|
113
|
+
startAdornment: (
|
|
114
|
+
<Fab
|
|
115
|
+
aria-label={i18n._(/* i18n */ 'Decrease')}
|
|
116
|
+
size='smaller'
|
|
117
|
+
onClick={() => {
|
|
118
|
+
if ((valueAsNumber || Infinity) <= inputProps.min) return
|
|
119
|
+
onChange(value - 1)
|
|
70
120
|
}}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
size={size}
|
|
76
|
-
type='number'
|
|
77
|
-
className={`${textFieldProps.className ?? ''} ${classes.quantity}`}
|
|
78
|
-
sx={[
|
|
79
|
-
{
|
|
80
|
-
width: responsiveVal(90, 120),
|
|
81
|
-
},
|
|
82
|
-
{
|
|
83
|
-
'& input[type=number]': {
|
|
84
|
-
MozAppearance: 'textfield',
|
|
85
|
-
},
|
|
86
|
-
'& .MuiOutlinedInput-root': {
|
|
87
|
-
px: '2px',
|
|
88
|
-
display: 'grid',
|
|
89
|
-
gridTemplateColumns: '1fr auto 1fr',
|
|
90
|
-
},
|
|
91
|
-
},
|
|
92
|
-
variant === 'standard' && {
|
|
93
|
-
'& .MuiOutlinedInput-input': {
|
|
94
|
-
padding: 0,
|
|
95
|
-
},
|
|
96
|
-
'& .MuiOutlinedInput-notchedOutline': {
|
|
97
|
-
display: 'none',
|
|
98
|
-
},
|
|
99
|
-
},
|
|
100
|
-
...(Array.isArray(sx) ? sx : [sx]),
|
|
101
|
-
]}
|
|
102
|
-
autoComplete='off'
|
|
103
|
-
InputProps={{
|
|
104
|
-
...textFieldProps.InputProps,
|
|
105
|
-
startAdornment: (
|
|
106
|
-
<Fab
|
|
107
|
-
aria-label={i18n._(/* i18n */ 'Decrease')}
|
|
108
|
-
size='smaller'
|
|
109
|
-
onClick={() => {
|
|
110
|
-
if ((valueAsNumber || Infinity) <= inputProps.min) return
|
|
111
|
-
onChange(value - 1)
|
|
112
|
-
}}
|
|
113
|
-
sx={{
|
|
114
|
-
boxShadow: variant === 'standard' ? 4 : 0,
|
|
115
|
-
minHeight: '30px',
|
|
116
|
-
minWidth: '30px',
|
|
117
|
-
}}
|
|
118
|
-
tabIndex={-1}
|
|
119
|
-
color='inherit'
|
|
120
|
-
{...DownProps}
|
|
121
|
-
className={`${classes.button} ${DownProps.className ?? ''}`}
|
|
122
|
-
>
|
|
123
|
-
{DownProps.children ?? <IconSvg src={iconMin} size='small' />}
|
|
124
|
-
</Fab>
|
|
125
|
-
),
|
|
126
|
-
endAdornment: (
|
|
127
|
-
<Fab
|
|
128
|
-
aria-label={i18n._(/* i18n */ 'Increase')}
|
|
129
|
-
size='smaller'
|
|
130
|
-
onClick={() => {
|
|
131
|
-
if (valueAsNumber >= (inputProps.max ?? Infinity)) return
|
|
132
|
-
onChange(valueAsNumber + 1)
|
|
133
|
-
}}
|
|
134
|
-
sx={{
|
|
135
|
-
boxShadow: variant === 'standard' ? 4 : 0,
|
|
136
|
-
minHeight: '30px',
|
|
137
|
-
minWidth: '30px',
|
|
138
|
-
}}
|
|
139
|
-
tabIndex={-1}
|
|
140
|
-
color='inherit'
|
|
141
|
-
{...UpProps}
|
|
142
|
-
className={`${classes.button} ${UpProps.className ?? ''}`}
|
|
143
|
-
>
|
|
144
|
-
{UpProps.children ?? <IconSvg src={iconPlus} size='small' />}
|
|
145
|
-
</Fab>
|
|
146
|
-
),
|
|
121
|
+
sx={{
|
|
122
|
+
boxShadow: variant === 'standard' ? 4 : 0,
|
|
123
|
+
minHeight: '30px',
|
|
124
|
+
minWidth: '30px',
|
|
147
125
|
}}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
126
|
+
tabIndex={-1}
|
|
127
|
+
color='inherit'
|
|
128
|
+
{...DownProps}
|
|
129
|
+
className={`${classes.button} ${DownProps.className ?? ''}`}
|
|
130
|
+
>
|
|
131
|
+
{DownProps.children ?? <IconSvg src={iconMin} size='small' />}
|
|
132
|
+
</Fab>
|
|
133
|
+
),
|
|
134
|
+
endAdornment: (
|
|
135
|
+
<Fab
|
|
136
|
+
aria-label={i18n._(/* i18n */ 'Increase')}
|
|
137
|
+
size='smaller'
|
|
138
|
+
onClick={() => {
|
|
139
|
+
if (valueAsNumber >= (inputProps.max ?? Infinity)) return
|
|
140
|
+
onChange(valueAsNumber + 1)
|
|
159
141
|
}}
|
|
160
|
-
|
|
161
|
-
|
|
142
|
+
sx={{
|
|
143
|
+
boxShadow: variant === 'standard' ? 4 : 0,
|
|
144
|
+
minHeight: '30px',
|
|
145
|
+
minWidth: '30px',
|
|
146
|
+
}}
|
|
147
|
+
tabIndex={-1}
|
|
148
|
+
color='inherit'
|
|
149
|
+
{...UpProps}
|
|
150
|
+
className={`${classes.button} ${UpProps.className ?? ''}`}
|
|
151
|
+
>
|
|
152
|
+
{UpProps.children ?? <IconSvg src={iconPlus} size='small' />}
|
|
153
|
+
</Fab>
|
|
154
|
+
),
|
|
155
|
+
}}
|
|
156
|
+
inputProps={{
|
|
157
|
+
'aria-label': i18n._(/* i18n */ 'Number'),
|
|
158
|
+
...inputProps,
|
|
159
|
+
className: `${inputProps?.className ?? ''} ${classes.quantityInput}`,
|
|
160
|
+
sx: {
|
|
161
|
+
typography: 'body1',
|
|
162
|
+
textAlign: 'center',
|
|
163
|
+
'&::-webkit-inner-spin-button,&::-webkit-outer-spin-button': {
|
|
164
|
+
appearance: 'none',
|
|
165
|
+
},
|
|
166
|
+
},
|
|
162
167
|
}}
|
|
163
168
|
/>
|
|
164
169
|
)
|
|
@@ -20,6 +20,7 @@ export type RadioButtonGroupProps<T extends FieldValues> = {
|
|
|
20
20
|
options: { label: string; id: string | number }[] | any[]
|
|
21
21
|
helperText?: string
|
|
22
22
|
required?: boolean
|
|
23
|
+
/** @deprecated Form value parsing should happen in the handleSubmit function of the form */
|
|
23
24
|
parseError?: (error: FieldError) => string
|
|
24
25
|
label?: string
|
|
25
26
|
labelKey?: string
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { InputCheckmark } from '@graphcommerce/next-ui'
|
|
2
|
+
import {
|
|
3
|
+
Controller,
|
|
4
|
+
ControllerProps,
|
|
5
|
+
FieldValues,
|
|
6
|
+
useController,
|
|
7
|
+
} from '@graphcommerce/react-hook-form'
|
|
2
8
|
import { i18n } from '@lingui/core'
|
|
3
9
|
import { MenuItem, TextField, TextFieldProps } from '@mui/material'
|
|
4
10
|
|
|
@@ -8,10 +14,12 @@ export type SelectElementProps<T extends FieldValues, O extends OptionBase> = Om
|
|
|
8
14
|
TextFieldProps,
|
|
9
15
|
'name' | 'type' | 'onChange' | 'defaultValue'
|
|
10
16
|
> & {
|
|
17
|
+
/** @deprecated Please use the rules props instead */
|
|
11
18
|
validation?: ControllerProps<T>['rules']
|
|
12
19
|
options?: O[]
|
|
13
20
|
type?: 'string' | 'number'
|
|
14
21
|
onChange?: (value: string | number) => void
|
|
22
|
+
showValid?: boolean
|
|
15
23
|
} & Omit<ControllerProps<T>, 'render'>
|
|
16
24
|
|
|
17
25
|
export function SelectElement<TFieldValues extends FieldValues, O extends OptionBase>({
|
|
@@ -19,57 +27,72 @@ export function SelectElement<TFieldValues extends FieldValues, O extends Option
|
|
|
19
27
|
required,
|
|
20
28
|
options = [],
|
|
21
29
|
type,
|
|
22
|
-
validation
|
|
30
|
+
validation,
|
|
23
31
|
control,
|
|
24
32
|
defaultValue,
|
|
33
|
+
rules = validation ?? {},
|
|
34
|
+
showValid,
|
|
35
|
+
disabled,
|
|
36
|
+
shouldUnregister,
|
|
25
37
|
...rest
|
|
26
38
|
}: SelectElementProps<TFieldValues, O>): JSX.Element {
|
|
27
39
|
const isNativeSelect = !!rest.SelectProps?.native
|
|
28
40
|
const ChildComponent = isNativeSelect ? 'option' : MenuItem
|
|
29
41
|
|
|
30
|
-
if (required && !
|
|
31
|
-
|
|
42
|
+
if (required && !rules.required) {
|
|
43
|
+
rules.required = i18n._(/* i18n */ 'This field is required')
|
|
32
44
|
}
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
+
const {
|
|
47
|
+
field: { onChange, value, ref, ...field },
|
|
48
|
+
fieldState: { invalid, error },
|
|
49
|
+
} = useController({
|
|
50
|
+
name,
|
|
51
|
+
rules,
|
|
52
|
+
control,
|
|
53
|
+
defaultValue,
|
|
54
|
+
disabled,
|
|
55
|
+
shouldUnregister,
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
// handle shrink on number input fields
|
|
59
|
+
if (type === 'number' && typeof value !== 'undefined') {
|
|
60
|
+
rest.InputLabelProps = rest.InputLabelProps || {}
|
|
61
|
+
rest.InputLabelProps.shrink = true
|
|
62
|
+
}
|
|
46
63
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
)
|
|
64
|
+
return (
|
|
65
|
+
<TextField
|
|
66
|
+
{...rest}
|
|
67
|
+
value={value ?? ''}
|
|
68
|
+
{...field}
|
|
69
|
+
inputRef={ref}
|
|
70
|
+
onChange={(event) => {
|
|
71
|
+
let item: number | string | O | undefined = event.target.value
|
|
72
|
+
if (type === 'number') item = Number(item)
|
|
73
|
+
rest.onChange?.(item)
|
|
74
|
+
onChange(item)
|
|
75
|
+
}}
|
|
76
|
+
select
|
|
77
|
+
required={required}
|
|
78
|
+
error={invalid}
|
|
79
|
+
helperText={error ? error.message : rest.helperText}
|
|
80
|
+
InputProps={{
|
|
81
|
+
...rest.InputProps,
|
|
82
|
+
endAdornment:
|
|
83
|
+
showValid && value && !error ? (
|
|
84
|
+
<InputCheckmark show={!error} />
|
|
85
|
+
) : (
|
|
86
|
+
rest.InputProps?.endAdornment
|
|
87
|
+
),
|
|
72
88
|
}}
|
|
73
|
-
|
|
89
|
+
>
|
|
90
|
+
{isNativeSelect && <option />}
|
|
91
|
+
{options.map((item) => (
|
|
92
|
+
<ChildComponent key={item.id} value={item.id}>
|
|
93
|
+
{item.label}
|
|
94
|
+
</ChildComponent>
|
|
95
|
+
))}
|
|
96
|
+
</TextField>
|
|
74
97
|
)
|
|
75
98
|
}
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
|
|
17
17
|
export type SliderElementProps<T extends FieldValues> = Omit<SliderProps, 'control'> & {
|
|
18
18
|
label?: string
|
|
19
|
+
/** @deprecated Form value parsing should happen in the handleSubmit function of the form */
|
|
19
20
|
parseError?: (error: FieldError) => string
|
|
20
21
|
required?: boolean
|
|
21
22
|
formControlProps?: FormControlProps
|
|
@@ -39,7 +40,7 @@ export function SliderElement<TFieldValues extends FieldValues>({
|
|
|
39
40
|
name={name}
|
|
40
41
|
control={control}
|
|
41
42
|
rules={rules}
|
|
42
|
-
render={({ field
|
|
43
|
+
render={({ field, fieldState: { invalid, error } }) => {
|
|
43
44
|
const parsedHelperText = error
|
|
44
45
|
? typeof parseError === 'function'
|
|
45
46
|
? parseError(error)
|
|
@@ -52,12 +53,7 @@ export function SliderElement<TFieldValues extends FieldValues>({
|
|
|
52
53
|
{label}
|
|
53
54
|
</FormLabel>
|
|
54
55
|
)}
|
|
55
|
-
<Slider
|
|
56
|
-
{...other}
|
|
57
|
-
value={value}
|
|
58
|
-
onChange={onChange}
|
|
59
|
-
valueLabelDisplay={other.valueLabelDisplay || 'auto'}
|
|
60
|
-
/>
|
|
56
|
+
<Slider {...other} {...field} valueLabelDisplay={other.valueLabelDisplay || 'auto'} />
|
|
61
57
|
{parsedHelperText && (
|
|
62
58
|
<FormHelperText error={invalid}>{parsedHelperText}</FormHelperText>
|
|
63
59
|
)}
|
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-nested-ternary */
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
FieldError,
|
|
5
|
-
FieldValues,
|
|
6
|
-
UseControllerProps,
|
|
7
|
-
} from '@graphcommerce/react-hook-form'
|
|
2
|
+
import { InputCheckmark } from '@graphcommerce/next-ui'
|
|
3
|
+
import { FieldValues, UseControllerProps, useController } from '@graphcommerce/react-hook-form'
|
|
8
4
|
import { i18n } from '@lingui/core'
|
|
9
5
|
import { TextField, TextFieldProps } from '@mui/material'
|
|
10
6
|
|
|
@@ -12,8 +8,11 @@ export type TextFieldElementProps<T extends FieldValues = FieldValues> = Omit<
|
|
|
12
8
|
TextFieldProps,
|
|
13
9
|
'name' | 'defaultValue'
|
|
14
10
|
> & {
|
|
11
|
+
/** @deprecated Please use the rules props instead */
|
|
15
12
|
validation?: UseControllerProps<T>['rules']
|
|
16
|
-
|
|
13
|
+
|
|
14
|
+
showValid?: boolean
|
|
15
|
+
} & UseControllerProps<T>
|
|
17
16
|
|
|
18
17
|
export function TextFieldElement<TFieldValues extends FieldValues>({
|
|
19
18
|
validation = {},
|
|
@@ -22,14 +21,16 @@ export function TextFieldElement<TFieldValues extends FieldValues>({
|
|
|
22
21
|
name,
|
|
23
22
|
control,
|
|
24
23
|
defaultValue,
|
|
24
|
+
rules = validation,
|
|
25
|
+
showValid,
|
|
25
26
|
...rest
|
|
26
27
|
}: TextFieldElementProps<TFieldValues>): JSX.Element {
|
|
27
|
-
if (required && !
|
|
28
|
-
|
|
28
|
+
if (required && !rules.required) {
|
|
29
|
+
rules.required = i18n._(/* i18n */ 'This field is required')
|
|
29
30
|
}
|
|
30
31
|
|
|
31
|
-
if (type === 'email' && !
|
|
32
|
-
|
|
32
|
+
if (type === 'email' && !rules.pattern) {
|
|
33
|
+
rules.pattern = {
|
|
33
34
|
// eslint-disable-next-line no-useless-escape
|
|
34
35
|
value:
|
|
35
36
|
/^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/,
|
|
@@ -37,31 +38,34 @@ export function TextFieldElement<TFieldValues extends FieldValues>({
|
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
40
|
|
|
41
|
+
const {
|
|
42
|
+
field: { onChange, ref, value = '', ...field },
|
|
43
|
+
fieldState: { error },
|
|
44
|
+
} = useController({ name, control, rules, defaultValue })
|
|
45
|
+
|
|
40
46
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
/>
|
|
64
|
-
)}
|
|
47
|
+
<TextField
|
|
48
|
+
{...rest}
|
|
49
|
+
{...field}
|
|
50
|
+
value={value}
|
|
51
|
+
onChange={(ev) => {
|
|
52
|
+
onChange(type === 'number' && ev.target.value ? Number(ev.target.value) : ev.target.value)
|
|
53
|
+
rest.onChange?.(ev)
|
|
54
|
+
}}
|
|
55
|
+
inputRef={ref}
|
|
56
|
+
required={required}
|
|
57
|
+
type={type}
|
|
58
|
+
error={Boolean(error) || rest.error}
|
|
59
|
+
helperText={error ? error.message : rest.helperText}
|
|
60
|
+
InputProps={{
|
|
61
|
+
...rest.InputProps,
|
|
62
|
+
endAdornment:
|
|
63
|
+
showValid && value && !error ? (
|
|
64
|
+
<InputCheckmark show={!error} />
|
|
65
|
+
) : (
|
|
66
|
+
rest.InputProps?.endAdornment
|
|
67
|
+
),
|
|
68
|
+
}}
|
|
65
69
|
/>
|
|
66
70
|
)
|
|
67
71
|
}
|
|
@@ -25,6 +25,7 @@ type SingleToggleButtonProps = Omit<ToggleButtonProps, 'value' | 'children'> & {
|
|
|
25
25
|
export type ToggleButtonGroupElementProps<T extends FieldValues> = ToggleButtonGroupProps & {
|
|
26
26
|
required?: boolean
|
|
27
27
|
label?: string
|
|
28
|
+
/** @deprecated Form value parsing should happen in the handleSubmit function of the form */
|
|
28
29
|
parseError?: (error: FieldError) => string
|
|
29
30
|
options: SingleToggleButtonProps[]
|
|
30
31
|
formLabelProps?: FormLabelProps
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { QueryResult } from '@graphcommerce/graphql'
|
|
2
|
-
import
|
|
2
|
+
import { useIsSSR } from '@graphcommerce/next-ui'
|
|
3
|
+
import React from 'react'
|
|
3
4
|
|
|
4
5
|
export type WaitForQueriesProps = {
|
|
5
6
|
waitFor: QueryResult<any, any> | boolean | (QueryResult<any, any> | boolean)[] | undefined
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Will be automatically correct.
|
|
9
|
+
*/
|
|
6
10
|
noSsr?: boolean
|
|
7
11
|
children: React.ReactNode
|
|
8
12
|
fallback?: React.ReactNode
|
|
@@ -10,14 +14,9 @@ export type WaitForQueriesProps = {
|
|
|
10
14
|
|
|
11
15
|
/** Shows the fallback during: SSR, Hydration and Query Loading. */
|
|
12
16
|
export const WaitForQueries = (props: WaitForQueriesProps) => {
|
|
13
|
-
const { waitFor, fallback, children
|
|
17
|
+
const { waitFor, fallback, children } = props
|
|
14
18
|
|
|
15
|
-
|
|
16
|
-
// Make sure we we use startTransition to make sure we don't get into trouble with Suspense.
|
|
17
|
-
const [mounted, setMounted] = useState(!noSsr)
|
|
18
|
-
useEffect(() => {
|
|
19
|
-
if (noSsr) startTransition(() => setMounted(true))
|
|
20
|
-
}, [noSsr])
|
|
19
|
+
const mounted = !useIsSSR()
|
|
21
20
|
|
|
22
21
|
// We are done when all queries either have data or an error.
|
|
23
22
|
const isDone = (Array.isArray(waitFor) ? waitFor : [waitFor]).every((res) => {
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@graphcommerce/ecommerce-ui",
|
|
3
3
|
"homepage": "https://www.graphcommerce.org/",
|
|
4
4
|
"repository": "github:graphcommerce-org/graphcommerce",
|
|
5
|
-
"version": "8.1.0-canary.
|
|
5
|
+
"version": "8.1.0-canary.5",
|
|
6
6
|
"sideEffects": false,
|
|
7
7
|
"prettier": "@graphcommerce/prettier-config-pwa",
|
|
8
8
|
"eslintConfig": {
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
}
|
|
13
13
|
},
|
|
14
14
|
"peerDependencies": {
|
|
15
|
-
"@graphcommerce/eslint-config-pwa": "^8.1.0-canary.
|
|
16
|
-
"@graphcommerce/graphql": "^8.1.0-canary.
|
|
17
|
-
"@graphcommerce/next-ui": "^8.1.0-canary.
|
|
18
|
-
"@graphcommerce/prettier-config-pwa": "^8.1.0-canary.
|
|
19
|
-
"@graphcommerce/react-hook-form": "^8.1.0-canary.
|
|
20
|
-
"@graphcommerce/typescript-config-pwa": "^8.1.0-canary.
|
|
15
|
+
"@graphcommerce/eslint-config-pwa": "^8.1.0-canary.5",
|
|
16
|
+
"@graphcommerce/graphql": "^8.1.0-canary.5",
|
|
17
|
+
"@graphcommerce/next-ui": "^8.1.0-canary.5",
|
|
18
|
+
"@graphcommerce/prettier-config-pwa": "^8.1.0-canary.5",
|
|
19
|
+
"@graphcommerce/react-hook-form": "^8.1.0-canary.5",
|
|
20
|
+
"@graphcommerce/typescript-config-pwa": "^8.1.0-canary.5",
|
|
21
21
|
"@lingui/core": "^4.2.1",
|
|
22
22
|
"@lingui/macro": "^4.2.1",
|
|
23
23
|
"@lingui/react": "^4.2.1",
|