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

FEPLT-1739: Add defaultSelected to Checkbox and Radio #4495

Merged
merged 4 commits into from
Oct 22, 2024
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
31 changes: 17 additions & 14 deletions packages/orbit-components/src/Checkbox/Checkbox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,13 @@ import Tooltip from "../Tooltip";
import Checkbox from ".";

const meta: Meta<typeof Checkbox> = {
title: "CheckBox",
title: "Checkbox",
component: Checkbox,

parameters: {
info: "Additionally you can add tooltip to this component.",
controls: {
exclude: ["onChange"],
exclude: ["onChange", "defaultChecked", "readOnly", "value", "name"],
},
},

Expand All @@ -27,7 +27,6 @@ const meta: Meta<typeof Checkbox> = {
checked: false,
hasError: false,
disabled: false,
readOnly: false,
name: "name",
onChange: action("onChange"),
},
Expand All @@ -41,7 +40,7 @@ export const Default: Story = {
parameters: {
info: "Checkbox needs only label and onChange by default.",
controls: {
exclude: ["info", "hasError", "disabled", "readOnly", "name", "value", "onChange"],
exclude: ["info", "hasError", "disabled", "name", "value", "onChange"],
},
},

Expand All @@ -50,6 +49,20 @@ export const Default: Story = {
},
};

export const Uncontrolled: Story = {
parameters: {
info: `Uncontrolled Checkbox. It doesn't require "checked" prop. Can be used with "defaultChecked" prop.`,
controls: {
exclude: ["checked", "info", "hasError", "disabled", "name", "value", "onChange"],
},
},

args: {
checked: undefined,
info: undefined,
},
};

export const WithHelp: Story = {
parameters: {
info: "Additional information about this choice",
Expand Down Expand Up @@ -112,16 +125,6 @@ export const WithTooltip: Story = {
},
};

export const ReadOnly: Story = {
args: {
readOnly: true,
},

parameters: {
info: "This is a preview of this component in read-only state.",
},
};

export const Rtl: Story = {
render: args => (
<RenderInRtl>
Expand Down
35 changes: 18 additions & 17 deletions packages/orbit-components/src/Checkbox/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,28 @@ After adding import into your project you can use it simply like:

Table below contains all types of the props available in Checkbox component.

| Name | Type | Default | Description |
| :------- | :------------------------- | :------ | :----------------------------------------------------------------------------------------------------------- |
| checked | `boolean` | `false` | If `true`, the Checkbox will be checked. |
| disabled | `boolean` | `false` | If `true`, the Checkbox will be set up as disabled. |
| dataTest | `string` | | Optional prop for testing purposes. |
| id | `string` | | Set `id` for `Checkbox` |
| hasError | `boolean` | `false` | If `true`, the border of the Checkbox will turn red. [See Functional specs](#functional-specs) |
| info | `React.Node` | | The additional info about the Checkbox. |
| label | `string` | | The label of the Checkbox. |
| name | `string` | | The name for the Checkbox. |
| onChange | `event => void \| Promise` | | Function for handling onChange event. |
| ref | `func` | | Prop for forwarded ref of the Checkbox. [See Functional specs](#functional-specs) |
| tabIndex | `string \| number` | | Specifies the tab order of an element |
| tooltip | `Element<Tooltip>` | | Optional property when you need to attach Tooltip to the Checkbox. [See Functional specs](#functional-specs) |
| value | `string` | | The value of the Checkbox. |
| Name | Type | Default | Description |
| :------------- | :------------------------- | :------ | :----------------------------------------------------------------------------------------------------------- |
| checked | `boolean` | | If `true`, the Checkbox will be checked. |
| defaultChecked | `boolean` | | If `true`, the Checkbox will be checked by default. Only to be used in uncontrolled. |
| disabled | `boolean` | `false` | If `true`, the Checkbox will be set up as disabled. |
| dataTest | `string` | | Optional prop for testing purposes. |
| id | `string` | | Set `id` for `Checkbox` |
| hasError | `boolean` | `false` | If `true`, the border of the Checkbox will turn red. [See Functional specs](#functional-specs) |
| info | `React.Node` | | The additional info about the Checkbox. |
| label | `string` | | The label of the Checkbox. |
| name | `string` | | The name for the Checkbox. |
| onChange | `event => void \| Promise` | | Function for handling onChange event. |
| ref | `func` | | Prop for forwarded ref of the Checkbox. [See Functional specs](#functional-specs) |
| tabIndex | `string \| number` | | Specifies the tab order of an element |
| tooltip | `Element<Tooltip>` | | Optional property when you need to attach Tooltip to the Checkbox. [See Functional specs](#functional-specs) |
| value | `string` | | The value of the Checkbox. |

## Functional specs

- The `hasError` prop will be visible only when the Checkbox has `checked` or `disabled` prop set on **false**.
- The `hasError` prop will be visible only when the Checkbox is not checked nor disabled.

- `ref` can be used for example auto-focus the elements immediately after render.
- `ref` can be used, for example, to control focus or to get the status (checked) of the element.

```jsx
import * as React from "react";
Expand Down
23 changes: 22 additions & 1 deletion packages/orbit-components/src/Checkbox/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import CheckBox from "..";
describe("CheckBox", () => {
const user = userEvent.setup();

it("default", async () => {
it("can be controlled", async () => {
const onChange = jest.fn();
render(
<CheckBox
Expand All @@ -24,7 +24,28 @@ describe("CheckBox", () => {
expect(checkbox).toHaveAttribute("value", "option");
expect(checkbox).toHaveAttribute("name", "name");
expect(checkbox).toHaveAttribute("tabIndex", "-1");
expect(checkbox).not.toHaveAttribute("checked");
await user.click(checkbox);
expect(onChange).toHaveBeenCalled();
});

it("can be uncontrolled", async () => {
const onChange = jest.fn();
render(
<CheckBox
label="Checkbox"
onChange={onChange}
value="option"
dataTest="test"
name="name"
defaultChecked
/>,
);
expect(screen.getByTestId("test")).toBeInTheDocument();
const checkbox = screen.getByRole("checkbox", { name: "Checkbox" }) as HTMLInputElement;
expect(checkbox.checked).toBeTruthy();
await user.click(checkbox);
expect(onChange).toHaveBeenCalled();
expect(checkbox.checked).toBeFalsy();
});
});
34 changes: 19 additions & 15 deletions packages/orbit-components/src/Checkbox/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const Checkbox = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
value,
hasError = false,
disabled = false,
checked = false,
checked,
defaultChecked,
name,
onChange,
dataTest,
Expand All @@ -33,24 +34,31 @@ const Checkbox = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
"flex flex-row",
"relative w-full",
"[&_.orbit-checkbox-icon-container]:hover:shadow-none",
"[&_.orbit-checkbox-icon-container]:has-[:checked]:bg-blue-normal [&_.orbit-checkbox-icon-container]:has-[:checked]:hover:bg-blue-dark",
"[&_.orbit-checkbox-icon-container]:has-[:focus]:outline-blue-normal [&_.orbit-checkbox-icon-container]:has-[:focus]:outline [&_.orbit-checkbox-icon-container]:has-[:focus]:outline-2",
"[&_.orbit-checkbox-icon-container>svg]:has-[:checked]:visible",
disabled
? "cursor-not-allowed"
? [
"cursor-not-allowed",
"[&_.orbit-checkbox-icon-container]:bg-form-element-disabled-background",
"[&_.orbit-checkbox-icon-container]:has-[:checked]:bg-cloud-dark",
checked && "[&_.orbit-checkbox-icon-container]:bg-cloud-dark",
]
: [
"cursor-pointer",
"[&_.orbit-checkbox-icon-container]:has-[:checked]:border-blue-normal [&_.orbit-checkbox-icon-container]:has-[:checked]:hover:border-blue-dark",
checked &&
!hasError &&
"[&_.orbit-checkbox-icon-container]:bg-blue-normal [&_.orbit-checkbox-icon-container]:border-blue-normal [&_.orbit-checkbox-icon-container]:hover:bg-blue-dark [&_.orbit-checkbox-icon-container]:hover:border-blue-dark",
!checked && "[&_.orbit-checkbox-icon-container]:bg-form-element-background",
!checked &&
hasError &&
"[&_.orbit-checkbox-icon-container]:border-form-element-error",
!checked &&
!hasError &&
"[&_.orbit-checkbox-icon-container]:border-form-element-border-color [&_.orbit-checkbox-icon-container]:hover:border-blue-light-active [&_.orbit-checkbox-icon-container]:active:border-form-element-focus",
!checked && hasError
? "[&_.orbit-checkbox-icon-container]:border-form-element-error"
: "[&_.orbit-checkbox-icon-container]:border-form-element-border-color [&_.orbit-checkbox-icon-container]:hover:border-blue-light-active [&_.orbit-checkbox-icon-container]:active:border-form-element-focus",
],
)}
>
<input
className="-z-default peer absolute opacity-0"
className="-z-default absolute opacity-0"
data-test={dataTest}
id={id}
data-state={getFieldDataState(!!hasError)}
Expand All @@ -60,6 +68,7 @@ const Checkbox = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
name={name}
tabIndex={tabIndex ? Number(tabIndex) : undefined}
checked={checked}
defaultChecked={defaultChecked}
onChange={!readOnly ? onChange : undefined}
onClick={e => readOnly && e.stopPropagation()}
ref={ref}
Expand All @@ -76,16 +85,11 @@ const Checkbox = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
"size-icon-medium",
"rounded-150 de:rounded-100",
"duration-fast transition-all ease-in-out",
"peer-focus:outline-blue-normal peer-focus:outline peer-focus:outline-2",
"[&>svg]:size-icon-small",
"[&>svg]:flex [&>svg]:items-center [&>svg]:justify-center",
"active:scale-95",
checked ? "[&>svg]:visible" : "[&>svg]:invisible",
disabled && [
"border-cloud-dark",
checked && "bg-cloud-dark",
!checked && "bg-form-element-disabled-background",
],
disabled && ["border-cloud-dark"],
)}
>
<Check customColor="white" />
Expand Down
4 changes: 4 additions & 0 deletions packages/orbit-components/src/Checkbox/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ export interface Props extends Common.Globals {
readonly hasError?: boolean;
readonly disabled?: boolean;
readonly checked?: boolean;
readonly defaultChecked?: boolean;
readonly name?: string;
readonly info?: React.ReactNode;
readonly tabIndex?: string | number;
/**
* @deprecated Radio does not support `readOnly` prop. Use `disabled` instead.
*/
readonly readOnly?: boolean;
readonly tooltip?: React.ReactNode | null;
// Should be InputEvent type
Expand Down
36 changes: 18 additions & 18 deletions packages/orbit-components/src/Radio/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,28 @@ After adding import into your project you can use it simply like:

Table below contains all types of the props available in Radio component.

| Name | Type | Default | Description |
| :------- | :------------------------- | :------ | :-------------------------------------------------------------------------------------------------------- |
| checked | `boolean` | `false` | If `true`, the Radio will be checked. |
| dataTest | `string` | | Optional prop for testing purposes. |
| id | `string` | | Set `id` for `Radio` input |
| disabled | `boolean` | `false` | If `true`, the Radio will be set up as disabled. |
| hasError | `boolean` | `false` | If `true`, the border of the Radio will turn red. [See Functional specs](#functional-specs) |
| info | `React.Node` | | The additional info about the Radio. |
| label | `string` | | The label of the Radio. |
| name | `string` | | The name for the Radio. |
| onChange | `event => void \| Promise` | | Function for handling onChange event. |
| ref | `func` | | Prop for forwarded ref of the Radio. [See Functional specs](#functional-specs) |
| tabIndex | `string \| number` | | Specifies the tab order of an element |
| tooltip | `Element<Tooltip>` | | Optional property when you need to attach Tooltip to the Radio. [See Functional specs](#functional-specs) |
| value | `string` | | The value of the Radio. |
| readOnly | `boolean` | | If `true`, the Radio will be set up as readOnly. |
| Name | Type | Default | Description |
| :------------- | :------------------------- | :------ | :-------------------------------------------------------------------------------------------------------- |
| checked | `boolean` | `false` | If `true`, the Radio will be checked. |
| defaultChecked | `boolean` | | If `true`, the Radio will be checked by default. Only to be used in uncontrolled. |
| dataTest | `string` | | Optional prop for testing purposes. |
| id | `string` | | Set `id` for `Radio` input |
| disabled | `boolean` | `false` | If `true`, the Radio will be set up as disabled. |
| hasError | `boolean` | `false` | If `true`, the border of the Radio will turn red. [See Functional specs](#functional-specs) |
| info | `React.Node` | | The additional info about the Radio. |
| label | `string` | | The label of the Radio. |
| name | `string` | | The name for the Radio. |
| onChange | `event => void \| Promise` | | Function for handling onChange event. |
| ref | `func` | | Prop for forwarded ref of the Radio. [See Functional specs](#functional-specs) |
| tabIndex | `string \| number` | | Specifies the tab order of an element |
| tooltip | `Element<Tooltip>` | | Optional property when you need to attach Tooltip to the Radio. [See Functional specs](#functional-specs) |
| value | `string` | | The value of the Radio. |

## Functional specs

- The`hasError` prop will be visible only when the Radio has `checked` or `disabled` prop set on false.
- The`hasError` prop will be visible only when the Radio is not checked nor disabled.

- `ref` can be used for example auto-focus the elements immediately after render.
- `ref` can be used, for example, to control focus or to get the status (checked) of the element.

```jsx
class Component extends React.PureComponent<Props> {
Expand Down
Loading
Loading