@adobe-commerce/elsie 1.9.0 → 1.9.1-alpha-20260702101934
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 +6 -0
- package/package.json +1 -1
- package/src/components/Picker/Picker.tsx +40 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @adobe-commerce/elsie
|
|
2
2
|
|
|
3
|
+
## 1.9.1-alpha-20260702101934
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- fa16e7d: fix(Picker): auto-select and emit the sole option when the control auto-disables, so single-option narrowing on configurable PDPs no longer leaves the value unselected and Add to Cart permanently disabled
|
|
8
|
+
|
|
3
9
|
## 1.9.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@ import { Icon } from '@adobe-commerce/elsie/components';
|
|
|
11
11
|
import { ChevronDown } from '@adobe-commerce/elsie/icons';
|
|
12
12
|
import { classes } from '@adobe-commerce/elsie/lib';
|
|
13
13
|
import { FunctionComponent, VNode } from 'preact';
|
|
14
|
-
import { HTMLAttributes, useEffect, useState } from 'preact/compat';
|
|
14
|
+
import { HTMLAttributes, useEffect, useRef, useState } from 'preact/compat';
|
|
15
15
|
|
|
16
16
|
import '@adobe-commerce/elsie/components/Picker/Picker.css';
|
|
17
17
|
|
|
@@ -46,10 +46,13 @@ function findSelectedValue(
|
|
|
46
46
|
defaultOption?: PickerOption,
|
|
47
47
|
placeholder?: string,
|
|
48
48
|
floatingLabel?: string,
|
|
49
|
-
firstAvailableOption?: PickerOption
|
|
49
|
+
firstAvailableOption?: PickerOption,
|
|
50
|
+
singleOption?: PickerOption
|
|
50
51
|
) {
|
|
51
52
|
if (value) return value;
|
|
52
53
|
if (defaultOption) return defaultOption.value;
|
|
54
|
+
// sole option wins over the placeholder so it stays selected, not blank
|
|
55
|
+
if (singleOption) return singleOption.value;
|
|
53
56
|
if (placeholder || floatingLabel) return '';
|
|
54
57
|
if (firstAvailableOption) return firstAvailableOption.value;
|
|
55
58
|
return null;
|
|
@@ -75,17 +78,26 @@ export const Picker: FunctionComponent<PickerProps> = ({
|
|
|
75
78
|
const uniqueId = id ?? name ?? `dropin-picker-${Math.random().toString(36)}`;
|
|
76
79
|
const isRequired = !!props?.required;
|
|
77
80
|
const isDisabled = disabled || options?.length === 1;
|
|
81
|
+
const selectRef = useRef<HTMLSelectElement>(null);
|
|
78
82
|
|
|
79
83
|
// find the first option that is not disabled
|
|
80
84
|
const firstAvailableOption = options?.find((option) => !option.disabled);
|
|
81
85
|
|
|
86
|
+
// the only selectable option when the picker auto-disables; a disabled
|
|
87
|
+
// <select> never fires change, so we must emit it ourselves (see below)
|
|
88
|
+
const singleOption =
|
|
89
|
+
!disabled && options?.length === 1 && !options[0]?.disabled
|
|
90
|
+
? options[0]
|
|
91
|
+
: undefined;
|
|
92
|
+
|
|
82
93
|
const [selectedValue, setSelectedValue] = useState<PickerValue>(() => {
|
|
83
94
|
return findSelectedValue(
|
|
84
95
|
value,
|
|
85
96
|
defaultOption,
|
|
86
97
|
placeholder,
|
|
87
98
|
floatingLabel,
|
|
88
|
-
firstAvailableOption
|
|
99
|
+
firstAvailableOption,
|
|
100
|
+
singleOption
|
|
89
101
|
);
|
|
90
102
|
});
|
|
91
103
|
|
|
@@ -96,10 +108,32 @@ export const Picker: FunctionComponent<PickerProps> = ({
|
|
|
96
108
|
defaultOption,
|
|
97
109
|
placeholder,
|
|
98
110
|
floatingLabel,
|
|
99
|
-
firstAvailableOption
|
|
111
|
+
firstAvailableOption,
|
|
112
|
+
singleOption
|
|
100
113
|
)
|
|
101
114
|
);
|
|
102
|
-
}, [
|
|
115
|
+
}, [
|
|
116
|
+
value,
|
|
117
|
+
defaultOption,
|
|
118
|
+
placeholder,
|
|
119
|
+
floatingLabel,
|
|
120
|
+
firstAvailableOption,
|
|
121
|
+
singleOption,
|
|
122
|
+
]);
|
|
123
|
+
|
|
124
|
+
// commit the sole option to the consumer; skip once value has come back in.
|
|
125
|
+
// dispatch a real change event so handleOptionClick emits it: consumers get
|
|
126
|
+
// a genuine Event (some call preventDefault) identical to a user selection.
|
|
127
|
+
useEffect(() => {
|
|
128
|
+
if (!singleOption || value === singleOption.value) return;
|
|
129
|
+
|
|
130
|
+
const select = selectRef.current;
|
|
131
|
+
if (!select) return;
|
|
132
|
+
|
|
133
|
+
select.value = singleOption.value as string;
|
|
134
|
+
select.dispatchEvent(new Event('change', { bubbles: true }));
|
|
135
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
136
|
+
}, [singleOption?.value, value]);
|
|
103
137
|
|
|
104
138
|
const handleOptionClick = (event: Event) => {
|
|
105
139
|
const { options, value } = event.target as HTMLSelectElement;
|
|
@@ -157,6 +191,7 @@ export const Picker: FunctionComponent<PickerProps> = ({
|
|
|
157
191
|
)}
|
|
158
192
|
|
|
159
193
|
<select
|
|
194
|
+
ref={selectRef}
|
|
160
195
|
id={uniqueId}
|
|
161
196
|
className={classes([
|
|
162
197
|
'dropin-picker__select',
|