Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Select specification updates & more #1450

Merged
merged 6 commits into from
Feb 2, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 5 additions & 6 deletions lib/src/paginator/Paginator.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@ import DxcPaginator from "./Paginator";

// Mocking DOMRect for Radix Primitive Popover
global.globalThis = global;
global.DOMRect = {
fromRect: () => ({ top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0 }),
};
global.ResizeObserver = class ResizeObserver {
constructor(cb) {
this.cb = cb;
}
observe() {
this.cb([{ borderBoxSize: { inlineSize: 0, blockSize: 0 } }]);
}
observe() {}
unobserve() {}
disconnect() {}
};

global.DOMRect = {
Expand Down
17 changes: 6 additions & 11 deletions lib/src/resultsetTable/ResultsetTable.test.js
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import React from "react";
import { render, fireEvent, act } from "@testing-library/react";
import { render, fireEvent } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import DxcResultsetTable from "./ResultsetTable";

// Mocking DOMRect for Radix Primitive Popover
global.globalThis = global;
global.ResizeObserver = class ResizeObserver {
constructor(cb) {
this.cb = cb;
}
observe() {
this.cb([{ borderBoxSize: { inlineSize: 0, blockSize: 0 } }]);
}
unobserve() {}
};

global.DOMRect = {
fromRect: () => ({ top: 0, left: 0, bottom: 0, right: 0, width: 0, height: 0 }),
};
global.ResizeObserver = class ResizeObserver {
observe() {}
unobserve() {}
disconnect() {}
};

const columns = [
{
Expand Down
100 changes: 40 additions & 60 deletions lib/src/select/Listbox.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { useState, useLayoutEffect, useEffect, useRef } from "react";
import styled, { ThemeProvider } from "styled-components";
import useTheme from "../useTheme";
import React, { useLayoutEffect, useRef } from "react";
import styled from "styled-components";
import useTranslatedLabels from "../useTranslatedLabels";
import { ListboxProps } from "./types";
import Option from "./Option";
Expand All @@ -20,14 +19,12 @@ const Listbox = ({
optionalItem,
searchable,
handleOptionOnClick,
getSelectWidth,
styles,
}: ListboxProps): JSX.Element => {
const colorsTheme = useTheme();
const translatedLabels = useTranslatedLabels();
const listboxRef = useRef(null);
const [styles, setStyles] = useState(null);

let globalIndex = optional && !multiple ? 0 : -1; // index for options, starting from 0 to options.length -1
let globalIndex = optional && !multiple ? 0 : -1;
const mapOptionFunc = (option, mapIndex) => {
if (option.options) {
const groupId = `group-${mapIndex}`;
Expand Down Expand Up @@ -90,60 +87,43 @@ const Listbox = ({
visualFocusedOptionEl?.scrollIntoView?.({ block: "nearest", inline: "start" });
}, [visualFocusIndex]);

const handleResize = () => {
setStyles({ width: getSelectWidth() });
};

useLayoutEffect(() => {
handleResize();
} , [getSelectWidth]);

useEffect(() => {
window.addEventListener("resize", handleResize);
return () => {
window.removeEventListener("resize", handleResize);
};
}, [getSelectWidth]);

return (
<ThemeProvider theme={colorsTheme.select}>
<ListboxContainer
id={id}
onClick={(event) => {
event.stopPropagation();
}}
onMouseDown={(event) => {
event.preventDefault();
}}
ref={listboxRef}
role="listbox"
aria-multiselectable={multiple}
style={styles}
>
{searchable && (options.length === 0 || !groupsHaveOptions(options)) ? (
<OptionsSystemMessage>
<NoMatchesFoundIcon>{selectIcons.searchOff}</NoMatchesFoundIcon>
{translatedLabels.select.noMatchesErrorMessage}
</OptionsSystemMessage>
) : (
optional &&
!multiple && (
<Option
key={`option-${optionalItem.value}`}
id={`option-${0}`}
option={optionalItem}
onClick={handleOptionOnClick}
multiple={multiple}
visualFocused={visualFocusIndex === 0}
isGroupedOption={false}
isLastOption={lastOptionIndex === 0}
isSelected={multiple ? currentValue.includes(optionalItem.value) : currentValue === optionalItem.value}
/>
)
)}
{options.map(mapOptionFunc)}
</ListboxContainer>
</ThemeProvider>
<ListboxContainer
id={id}
onClick={(event) => {
event.stopPropagation();
}}
onMouseDown={(event) => {
event.preventDefault();
}}
ref={listboxRef}
role="listbox"
aria-multiselectable={multiple}
style={styles}
>
{searchable && (options.length === 0 || !groupsHaveOptions(options)) ? (
<OptionsSystemMessage>
<NoMatchesFoundIcon>{selectIcons.searchOff}</NoMatchesFoundIcon>
{translatedLabels.select.noMatchesErrorMessage}
</OptionsSystemMessage>
) : (
optional &&
!multiple && (
<Option
key={`option-${optionalItem.value}`}
id={`option-${0}`}
option={optionalItem}
onClick={handleOptionOnClick}
multiple={multiple}
visualFocused={visualFocusIndex === 0}
isGroupedOption={false}
isLastOption={lastOptionIndex === 0}
isSelected={multiple ? currentValue.includes(optionalItem.value) : currentValue === optionalItem.value}
/>
)
)}
{options.map(mapOptionFunc)}
</ListboxContainer>
);
};

Expand Down
73 changes: 33 additions & 40 deletions lib/src/select/Option.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import React from "react";
import styled, { ThemeProvider } from "styled-components";
import styled from "styled-components";
import { OptionProps } from "../select/types";
import useTheme from "../useTheme";
import DxcCheckbox from "../checkbox/Checkbox";
import selectIcons from "./Icons";

Expand All @@ -14,47 +13,41 @@ const Option = ({
isGroupedOption = false,
isLastOption,
isSelected,
}: OptionProps): JSX.Element => {
const colorsTheme = useTheme();

return (
<ThemeProvider theme={colorsTheme.select}>
<OptionItem
id={id}
onClick={() => {
onClick(option);
}}
visualFocused={visualFocused}
selected={isSelected}
role="option"
aria-selected={isSelected}
>
<StyledOption
visualFocused={visualFocused}
selected={isSelected}
last={isLastOption}
}: OptionProps): JSX.Element => (
<OptionItem
id={id}
onClick={() => {
onClick(option);
}}
visualFocused={visualFocused}
selected={isSelected}
role="option"
aria-selected={isSelected}
>
<StyledOption
visualFocused={visualFocused}
selected={isSelected}
last={isLastOption}
grouped={isGroupedOption}
multiple={multiple}
>
{multiple && <DxcCheckbox checked={isSelected} tabIndex={-1} />}
{option.icon && (
<OptionIcon
grouped={isGroupedOption}
multiple={multiple}
role={!(typeof option.icon === "string") ? "img" : undefined}
>
{multiple && <DxcCheckbox checked={isSelected} tabIndex={-1} />}
{option.icon && (
<OptionIcon
grouped={isGroupedOption}
multiple={multiple}
role={!(typeof option.icon === "string") ? "img" : undefined}
>
{typeof option.icon === "string" ? <img src={option.icon} /> : option.icon}
</OptionIcon>
)}
<OptionContent grouped={isGroupedOption} hasIcon={option.icon ? true : false} multiple={multiple}>
<OptionLabel>{option.label}</OptionLabel>
{!multiple && isSelected && <OptionSelectedIndicator>{selectIcons.selected}</OptionSelectedIndicator>}
</OptionContent>
</StyledOption>
</OptionItem>
</ThemeProvider>
);
};
{typeof option.icon === "string" ? <img src={option.icon} /> : option.icon}
</OptionIcon>
)}
<OptionContent grouped={isGroupedOption} hasIcon={option.icon ? true : false} multiple={multiple}>
<OptionLabel>{option.label}</OptionLabel>
{!multiple && isSelected && <OptionSelectedIndicator>{selectIcons.selected}</OptionSelectedIndicator>}
</OptionContent>
</StyledOption>
</OptionItem>
);

type OptionItemProps = {
visualFocused: boolean;
Expand Down