Skip to content

Commit 80778e3

Browse files
authored
fix: Style panel style value combobox doesn't close on ESC (#4277)
## Description closes #4269 ## Steps for reproduction 1. click button 2. expect xyz ## Code Review - [ ] hi @kof, I need you to do - conceptual review (architecture, feature-correctness) - detailed review (read every line) - test it on preview ## Before requesting a review - [ ] made a self-review - [ ] added inline comments where things may be not obvious (the "why", not "what") ## Before merging - [ ] tested locally and on preview environment (preview dev login: 5de6) - [ ] updated [test cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md) document - [ ] added tests - [ ] if any new env variables are added, added them to `.env` file
1 parent af931ac commit 80778e3

File tree

3 files changed

+54
-29
lines changed

3 files changed

+54
-29
lines changed

apps/builder/app/builder/features/style-panel/shared/css-value-input/css-value-input.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import {
5050
} from "~/shared/nano-states";
5151
import { convertUnits } from "./convert-units";
5252
import { mergeRefs } from "@react-aria/utils";
53+
import { composeEventHandlers } from "~/shared/event-utils";
5354

5455
// We need to enable scrub on properties that can have numeric value.
5556
const canBeNumber = (property: StyleProperty, value: CssValueInputValue) => {
@@ -691,6 +692,11 @@ export const CssValueInput = ({
691692
.filter(Boolean)
692693
.map((descr) => <Description>{descr}</Description>);
693694

695+
const inputPropsHandleKeyDown = composeEventHandlers(
696+
inputProps.onKeyDown,
697+
handleKeyDown
698+
);
699+
694700
return (
695701
<ComboboxRoot open={isOpen}>
696702
<Box {...getComboboxProps()}>
@@ -710,7 +716,7 @@ export const CssValueInput = ({
710716
}}
711717
autoFocus={autoFocus}
712718
onBlur={handleOnBlur}
713-
onKeyDown={handleKeyDown}
719+
onKeyDown={inputPropsHandleKeyDown}
714720
containerRef={disabled ? undefined : scrubRef}
715721
inputRef={mergeRefs(inputRef, props.inputRef ?? null)}
716722
name={property}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
https://github.com/radix-ui/primitives/blob/main/packages/core/primitive/src/primitive.tsx
3+
4+
MIT License
5+
6+
Copyright (c) 2022 WorkOS
7+
8+
Permission is hereby granted, free of charge, to any person obtaining a copy
9+
of this software and associated documentation files (the "Software"), to deal
10+
in the Software without restriction, including without limitation the rights
11+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12+
copies of the Software, and to permit persons to whom the Software is
13+
furnished to do so, subject to the following conditions:
14+
15+
The above copyright notice and this permission notice shall be included in all
16+
copies or substantial portions of the Software.
17+
18+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24+
SOFTWARE.
25+
*/
26+
27+
export const composeEventHandlers = <E>(
28+
originalEventHandler?: (event: E) => void,
29+
ourEventHandler?: (event: E) => void,
30+
{ checkForDefaultPrevented = true } = {}
31+
) => {
32+
return function handleEvent(event: E) {
33+
originalEventHandler?.(event);
34+
35+
if (
36+
checkForDefaultPrevented === false ||
37+
!(event as unknown as Event).defaultPrevented
38+
) {
39+
return ourEventHandler?.(event);
40+
}
41+
};
42+
};

packages/design-system/src/components/combobox.stories.tsx

Lines changed: 5 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import type {
77
import {
88
ComboboxListboxItem,
99
useCombobox,
10-
comboboxStateChangeTypes,
1110
ComboboxContent,
1211
ComboboxRoot,
1312
ComboboxListbox,
@@ -38,32 +37,12 @@ export const Complex = () => {
3837

3938
const stateReducer = useCallback(
4039
(
41-
state: UseComboboxState<string>,
40+
_state: UseComboboxState<string>,
4241
actionAndChanges: UseComboboxStateChangeOptions<string>
4342
) => {
4443
const { type, changes } = actionAndChanges;
45-
switch (type) {
46-
// on item selection.
47-
case comboboxStateChangeTypes.ItemClick:
48-
case comboboxStateChangeTypes.InputKeyDownEnter:
49-
case comboboxStateChangeTypes.InputBlur:
50-
case comboboxStateChangeTypes.ControlledPropUpdatedSelectedItem:
51-
return {
52-
...changes,
53-
// if we have a selected item.
54-
...(changes.selectedItem && {
55-
// we will set the input value to "" (empty string).
56-
inputValue: "",
57-
}),
58-
};
59-
60-
// Remove "reset" action
61-
case comboboxStateChangeTypes.InputKeyDownEscape: {
62-
return {
63-
...state,
64-
};
65-
}
6644

45+
switch (type) {
6746
default:
6847
return changes; // otherwise business as usual.
6948
}
@@ -86,16 +65,14 @@ export const Complex = () => {
8665
stateReducer,
8766
onItemSelect: setValue,
8867
onChange: (value) => {
89-
if (value) {
90-
setValue(value);
91-
}
68+
setValue(value ?? "");
9269
},
9370
});
9471

9572
return (
9673
<ComboboxRoot open={isOpen}>
9774
<Flex {...getComboboxProps()} direction="column" gap="3">
98-
<ComboboxAnchor>
75+
<ComboboxAnchor asChild>
9976
<InputField
10077
prefix={
10178
<Flex align="center">
@@ -110,8 +87,8 @@ export const Complex = () => {
11087
{items.map((item, index) => {
11188
return (
11289
<ComboboxListboxItem
113-
key={index}
11490
{...getItemProps({ item, index })}
91+
key={index}
11592
>
11693
{item}
11794
</ComboboxListboxItem>

0 commit comments

Comments
 (0)