✨(react) add disable property to select option
Based on recent feedbacks, this feature was needed for consumer apps. Resolve #60
This commit is contained in:
5
.changeset/wet-spiders-hide.md
Normal file
5
.changeset/wet-spiders-hide.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
---
|
||||||
|
"@openfun/cunningham-react": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
add disable property to select option
|
||||||
@@ -26,6 +26,7 @@ The available options must be given via the `options` props. It is an array of o
|
|||||||
code={`{
|
code={`{
|
||||||
label: string
|
label: string
|
||||||
value?: string
|
value?: string
|
||||||
|
disabled?: boolean;
|
||||||
}`}
|
}`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -83,6 +84,15 @@ By default, the select is clearable ( the cross icon on the right is shown ). Yo
|
|||||||
<Story id="components-forms-select-mono--not-clearable"/>
|
<Story id="components-forms-select-mono--not-clearable"/>
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
|
||||||
|
## Disabled options
|
||||||
|
|
||||||
|
You can disable some options by using the `disabled` props on the `Option` object.
|
||||||
|
|
||||||
|
<Canvas sourceState="shown">
|
||||||
|
<Story id="components-forms-select-mono--disabled-options"/>
|
||||||
|
</Canvas>
|
||||||
|
|
||||||
## Controlled / Non Controlled
|
## Controlled / Non Controlled
|
||||||
|
|
||||||
Like a native select, you can use the Select component in a controlled or non controlled way. You can see the example below
|
Like a native select, you can use the Select component in a controlled or non controlled way. You can see the example below
|
||||||
|
|||||||
@@ -121,6 +121,11 @@
|
|||||||
&--selected {
|
&--selected {
|
||||||
background-color: var(--c--components--forms-select--item-background-color--selected);
|
background-color: var(--c--components--forms-select--item-background-color--selected);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--disabled {
|
||||||
|
color: var(--c--components--forms-select--item-color--disabled);
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,12 @@ describe("<Select/>", () => {
|
|||||||
"c__select__menu__item--selected"
|
"c__select__menu__item--selected"
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
const expectOptionToBeDisabled = (option: HTMLLIElement) => {
|
||||||
|
expect(option).toHaveAttribute("disabled");
|
||||||
|
expect(Array.from(option.classList)).contains(
|
||||||
|
"c__select__menu__item--disabled"
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
describe("Searchable", () => {
|
describe("Searchable", () => {
|
||||||
it("shows all options when clicking on the input", async () => {
|
it("shows all options when clicking on the input", async () => {
|
||||||
@@ -1067,5 +1073,65 @@ describe("<Select/>", () => {
|
|||||||
})
|
})
|
||||||
).not.toBeInTheDocument();
|
).not.toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
it("is not possible to select disabled options", async () => {
|
||||||
|
render(
|
||||||
|
<CunninghamProvider>
|
||||||
|
<Select
|
||||||
|
label="City"
|
||||||
|
options={[
|
||||||
|
{
|
||||||
|
label: "Paris",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "London",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "New York",
|
||||||
|
disabled: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Tokyo",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
|
</CunninghamProvider>
|
||||||
|
);
|
||||||
|
const input = screen.getByRole("combobox", {
|
||||||
|
name: "City",
|
||||||
|
});
|
||||||
|
const menu: HTMLDivElement = screen.getByRole("listbox", {
|
||||||
|
name: "City",
|
||||||
|
});
|
||||||
|
const valueRendered = document.querySelector(".c__select__inner__value");
|
||||||
|
|
||||||
|
// Make sure the select is empty.
|
||||||
|
expect(valueRendered).toHaveTextContent("");
|
||||||
|
|
||||||
|
const user = userEvent.setup();
|
||||||
|
await user.click(input);
|
||||||
|
expectMenuToBeOpen(menu);
|
||||||
|
|
||||||
|
// Make sure the disabled option is not selectable.
|
||||||
|
let option: HTMLLIElement = screen.getByRole("option", {
|
||||||
|
name: "New York",
|
||||||
|
});
|
||||||
|
expectOptionToBeDisabled(option);
|
||||||
|
|
||||||
|
// Try to click on the disabled option.
|
||||||
|
await user.click(option);
|
||||||
|
|
||||||
|
expectMenuToBeOpen(menu);
|
||||||
|
// Make sure the select is still empty.
|
||||||
|
expect(valueRendered).toHaveTextContent("");
|
||||||
|
|
||||||
|
// Select a not disabled option.
|
||||||
|
option = screen.getByRole("option", {
|
||||||
|
name: "Tokyo",
|
||||||
|
});
|
||||||
|
|
||||||
|
await user.click(option);
|
||||||
|
expectMenuToBeClosed(menu);
|
||||||
|
expect(valueRendered).toHaveTextContent("Tokyo");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import { Button } from ":/components/Button";
|
|||||||
interface Option {
|
interface Option {
|
||||||
value?: string;
|
value?: string;
|
||||||
label: string;
|
label: string;
|
||||||
|
disabled?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
type Props = PropsWithChildren &
|
type Props = PropsWithChildren &
|
||||||
@@ -197,20 +198,28 @@ const SelectAux = ({
|
|||||||
>
|
>
|
||||||
<ul>
|
<ul>
|
||||||
{downshiftReturn.isOpen &&
|
{downshiftReturn.isOpen &&
|
||||||
options.map((item, index) => (
|
options.map((item, index) => {
|
||||||
<li
|
const isActive = index === downshiftReturn.highlightedIndex;
|
||||||
className={classNames("c__select__menu__item", {
|
return (
|
||||||
"c__select__menu__item--highlight":
|
<li
|
||||||
downshiftReturn.highlightedIndex === index,
|
className={classNames("c__select__menu__item", {
|
||||||
"c__select__menu__item--selected":
|
"c__select__menu__item--highlight": isActive,
|
||||||
downshiftReturn.selectedItem === item,
|
"c__select__menu__item--selected":
|
||||||
})}
|
downshiftReturn.selectedItem === item,
|
||||||
key={`${item.value}${index}`}
|
"c__select__menu__item--disabled": item.disabled,
|
||||||
{...downshiftReturn.getItemProps({ item, index })}
|
})}
|
||||||
>
|
key={`${item.value}${index}`}
|
||||||
<span>{item.label}</span>
|
{...downshiftReturn.getItemProps({
|
||||||
</li>
|
item,
|
||||||
))}
|
index,
|
||||||
|
isActive,
|
||||||
|
disabled: item.disabled,
|
||||||
|
})}
|
||||||
|
>
|
||||||
|
<span>{item.label}</span>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
})}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -165,6 +165,14 @@ export const NotClearable = {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const DisabledOptions = {
|
||||||
|
render: Template,
|
||||||
|
args: {
|
||||||
|
label: "Select a city",
|
||||||
|
options: OPTIONS.map((option, i) => ({ ...option, disabled: i % 3 === 0 })),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const Success = {
|
export const Success = {
|
||||||
render: Template,
|
render: Template,
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const tokens = (defaults: DefaultTokens) => ({
|
|||||||
"item-background-color--hover": defaults.theme.colors["greyscale-200"],
|
"item-background-color--hover": defaults.theme.colors["greyscale-200"],
|
||||||
"item-background-color--selected": defaults.theme.colors["primary-100"],
|
"item-background-color--selected": defaults.theme.colors["primary-100"],
|
||||||
"item-color": defaults.theme.colors["greyscale-800"],
|
"item-color": defaults.theme.colors["greyscale-800"],
|
||||||
|
"item-color--disabled": defaults.theme.colors["greyscale-500"],
|
||||||
"item-font-size": defaults.theme.font.sizes.l,
|
"item-font-size": defaults.theme.font.sizes.l,
|
||||||
"background-color": "white",
|
"background-color": "white",
|
||||||
"menu-background-color": "white",
|
"menu-background-color": "white",
|
||||||
|
|||||||
@@ -117,6 +117,7 @@
|
|||||||
--c--components--forms-select--item-background-color--hover: #F3F4F4;
|
--c--components--forms-select--item-background-color--hover: #F3F4F4;
|
||||||
--c--components--forms-select--item-background-color--selected: #EBF2FC;
|
--c--components--forms-select--item-background-color--selected: #EBF2FC;
|
||||||
--c--components--forms-select--item-color: #303C4B;
|
--c--components--forms-select--item-color: #303C4B;
|
||||||
|
--c--components--forms-select--item-color--disabled: #9EA3AA;
|
||||||
--c--components--forms-select--item-font-size: 1rem;
|
--c--components--forms-select--item-font-size: 1rem;
|
||||||
--c--components--forms-select--background-color: white;
|
--c--components--forms-select--background-color: white;
|
||||||
--c--components--forms-select--menu-background-color: white;
|
--c--components--forms-select--menu-background-color: white;
|
||||||
|
|||||||
Reference in New Issue
Block a user