Skip to content

Commit 53ec96c

Browse files
authored
Merge pull request #2009 from dxc-technology/gomezivann/select-update
Select updates
2 parents b063530 + ff17d47 commit 53ec96c

File tree

9 files changed

+281
-298
lines changed

9 files changed

+281
-298
lines changed

lib/src/dropdown/Dropdown.tsx

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,27 +7,7 @@ import useTheme from "../useTheme";
77
import * as Popover from "@radix-ui/react-popover";
88
import DropdownMenu from "./DropdownMenu";
99
import DxcIcon from "../icon/Icon";
10-
11-
const useWidth = (target) => {
12-
const [width, setWidth] = useState(0);
13-
14-
useEffect(() => {
15-
if (target != null) {
16-
setWidth(target.getBoundingClientRect().width);
17-
18-
const triggerObserver = new ResizeObserver((entries) => {
19-
const rect = entries[0].target.getBoundingClientRect();
20-
setWidth(rect?.width);
21-
});
22-
triggerObserver.observe(target);
23-
return () => {
24-
triggerObserver.unobserve(target);
25-
};
26-
}
27-
}, [target]);
28-
29-
return width;
30-
};
10+
import useWidth from "../utils/useWidth";
3111

3212
const DxcDropdown = ({
3313
options,

lib/src/select/Listbox.tsx

Lines changed: 15 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
1-
import React, { useId, useLayoutEffect, useRef } from "react";
1+
import React, { useLayoutEffect, useRef } from "react";
22
import styled from "styled-components";
33
import useTranslatedLabels from "../useTranslatedLabels";
44
import { ListboxProps } from "./types";
55
import Option from "./Option";
66
import DxcIcon from "../icon/Icon";
7-
8-
const groupsHaveOptions = (options) =>
9-
options?.[0].options ? options.some((groupOption) => groupOption.options?.length > 0) : true;
7+
import { groupsHaveOptions } from "./selectUtils";
108

119
const Listbox = ({
1210
id,
@@ -23,25 +21,24 @@ const Listbox = ({
2321
}: ListboxProps): JSX.Element => {
2422
const translatedLabels = useTranslatedLabels();
2523
const listboxRef = useRef(null);
26-
const listboxId = `select-${useId()}`;
27-
24+
2825
let globalIndex = optional && !multiple ? 0 : -1;
2926
const mapOptionFunc = (option, mapIndex) => {
30-
const groupId = `${listboxId}-group-${mapIndex}`;
27+
const groupId = `${id}-group-${mapIndex}`;
3128
if (option.options) {
3229
return (
3330
option.options.length > 0 && (
3431
<li key={groupId}>
35-
<GroupList role="listbox" aria-labelledby={groupId}>
32+
<ul role="listbox" aria-labelledby={groupId} style={{ padding: 0 }}>
3633
<GroupLabel role="presentation" id={groupId}>
3734
{option.label}
3835
</GroupLabel>
3936
{option.options.map((singleOption) => {
4037
globalIndex++;
4138
return (
4239
<Option
43-
key={`${listboxId}-option-${singleOption.value}`}
44-
id={`${listboxId}-option-${globalIndex}`}
40+
key={`${id}-option-${singleOption.value}`}
41+
id={`${id}-option-${globalIndex}`}
4542
option={singleOption}
4643
onClick={handleOptionOnClick}
4744
multiple={multiple}
@@ -54,16 +51,16 @@ const Listbox = ({
5451
/>
5552
);
5653
})}
57-
</GroupList>
54+
</ul>
5855
</li>
5956
)
6057
);
6158
} else {
6259
globalIndex++;
6360
return (
6461
<Option
65-
key={`${listboxId}-option-${option.value}`}
66-
id={`${listboxId}-option-${globalIndex}`}
62+
key={`${id}-option-${option.value}`}
63+
id={`${id}-option-${globalIndex}`}
6764
option={option}
6865
onClick={handleOptionOnClick}
6966
multiple={multiple}
@@ -88,7 +85,7 @@ const Listbox = ({
8885
visualFocusedOptionEl?.scrollIntoView?.({ block: "nearest", inline: "start" });
8986
}, [visualFocusIndex]);
9087

91-
const hasOptionGroups = options.some(option => option.options?.length > 0);
88+
const hasOptionGroups = options.some((option) => option.options?.length > 0);
9289

9390
return (
9491
<ListboxContainer
@@ -100,7 +97,7 @@ const Listbox = ({
10097
event.preventDefault();
10198
}}
10299
ref={listboxRef}
103-
aria-multiselectable={!hasOptionGroups ? multiple: undefined}
100+
aria-multiselectable={!hasOptionGroups ? multiple : undefined}
104101
style={styles}
105102
role={hasOptionGroups ? "list" : "listbox"}
106103
aria-label="List of options"
@@ -143,12 +140,13 @@ const ListboxContainer = styled.ul`
143140
border: 1px solid ${(props) => props.theme.listDialogBorderColor};
144141
border-radius: 0.25rem;
145142
box-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
146-
cursor: default;
147143
color: ${(props) => props.theme.listOptionFontColor};
148144
font-family: ${(props) => props.theme.fontFamily};
149145
font-size: ${(props) => props.theme.listOptionFontSize};
150146
font-style: ${(props) => props.theme.listOptionFontStyle};
151147
font-weight: ${(props) => props.theme.listOptionFontWeight};
148+
line-height: 24px;
149+
cursor: default;
152150
`;
153151

154152
const OptionsSystemMessage = styled.span`
@@ -170,14 +168,10 @@ const NoMatchesFoundIcon = styled.span`
170168
font-size: 16px;
171169
`;
172170

173-
const GroupList = styled.ul`
174-
padding: 0;
175-
`;
176-
177171
const GroupLabel = styled.li`
178172
padding: 4px 16px;
179173
font-weight: ${(props) => props.theme.listGroupLabelFontWeight};
180174
line-height: 1.715em;
181175
`;
182176

183-
export default React.memo(Listbox);
177+
export default Listbox;

lib/src/select/Option.tsx

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const Option = ({
1717
const handleOnMouseEnter = (event: React.MouseEvent) => {
1818
const label = event.currentTarget;
1919
const optionElement = document.getElementById(id);
20-
2120
if (optionElement.title === "" && label.scrollWidth > label.clientWidth) optionElement.title = option.label;
2221
};
2322

@@ -31,7 +30,6 @@ const Option = ({
3130
selected={isSelected}
3231
role="option"
3332
aria-selected={!multiple ? isSelected : undefined}
34-
tabIndex={0}
3533
>
3634
<StyledOption
3735
visualFocused={visualFocused}
@@ -40,7 +38,11 @@ const Option = ({
4038
grouped={isGroupedOption}
4139
multiple={multiple}
4240
>
43-
{multiple && <DxcCheckbox checked={isSelected} tabIndex={-1} />}
41+
{multiple && (
42+
<div style={{ display: "flex", pointerEvents: "none" }}>
43+
<DxcCheckbox checked={isSelected} tabIndex={-1} />
44+
</div>
45+
)}
4446
{option.icon && (
4547
<OptionIcon grouped={isGroupedOption} multiple={multiple}>
4648
{typeof option.icon === "string" ? <DxcIcon icon={option.icon} /> : option.icon}
@@ -64,7 +66,6 @@ const OptionItem = styled.li<{ visualFocused: OptionProps["visualFocused"]; sele
6466
box-shadow: inset 0 0 0 2px transparent;
6567
${(props) => props.visualFocused && `box-shadow: inset 0 0 0 2px ${props.theme.focusListOptionBorderColor};`}
6668
${(props) => props.selected && `background-color: ${props.theme.selectedListOptionBackgroundColor}`};
67-
line-height: 1.715em;
6869
cursor: pointer;
6970
7071
&:hover {
@@ -88,10 +89,11 @@ const StyledOption = styled.span<{
8889
selected: OptionProps["isSelected"];
8990
last: OptionProps["isLastOption"];
9091
}>`
92+
box-sizing: border-box;
9193
display: flex;
92-
padding: 0.25rem 0.5rem 0.188rem 0;
93-
min-height: 24px;
9494
align-items: center;
95+
height: 32px;
96+
padding: 4px 8px 4px 0;
9597
${(props) => props.grouped && props.multiple && `padding-left: 16px;`}
9698
${(props) =>
9799
props.last || props.visualFocused || props.selected
@@ -100,29 +102,28 @@ const StyledOption = styled.span<{
100102
`;
101103

102104
const OptionIcon = styled.span<{ grouped: OptionProps["isGroupedOption"]; multiple: OptionProps["multiple"] }>`
103-
display: flex;
104-
padding: 0.125rem;
105105
margin-left: ${(props) => (props.grouped && !props.multiple ? "16px" : "8px")};
106+
display: grid;
107+
place-items: center;
106108
color: ${(props) => props.theme.listOptionIconColor};
107-
109+
font-size: 24px;
108110
svg {
109111
height: 24px;
110112
width: 24px;
111113
}
112-
font-size: 24px;
113114
`;
114115

115116
const OptionContent = styled.span<{
116117
grouped: OptionProps["isGroupedOption"];
117118
multiple: OptionProps["multiple"];
118119
hasIcon: boolean;
119120
}>`
121+
margin-left: ${(props) => (props.grouped && !props.multiple && !props.hasIcon ? "16px" : "8px")};
120122
display: flex;
121123
justify-content: space-between;
122124
gap: 0.25rem;
123125
width: 100%;
124126
overflow: hidden;
125-
margin-left: ${(props) => (props.grouped && !props.multiple && !props.hasIcon ? "16px" : "8px")};
126127
`;
127128

128129
const OptionLabel = styled.span`
@@ -138,4 +139,4 @@ const OptionSelectedIndicator = styled.span`
138139
font-size: 16px;
139140
`;
140141

141-
export default React.memo(Option);
142+
export default Option;

lib/src/select/Select.stories.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ const SelectListbox = () => {
545545
<Title title="Grouped icons (Material Symbols)" theme="light" level={4} />
546546
<Listbox
547547
id="x14"
548-
currentValue={["0", "3"]}
548+
currentValue={"4"}
549549
options={icon_options_grouped_material}
550550
visualFocusIndex={-1}
551551
lastOptionIndex={3}
@@ -561,7 +561,7 @@ const SelectListbox = () => {
561561
<Title title="Grouped icons (Material)" theme="light" level={4} />
562562
<Listbox
563563
id="x15"
564-
currentValue={["facebook", "figma"]}
564+
currentValue={["car", "motorcycle", "train"]}
565565
options={options_material}
566566
visualFocusIndex={-1}
567567
lastOptionIndex={6}

0 commit comments

Comments
 (0)