Skip to content

Commit

Permalink
feat: checkbox (#108)
Browse files Browse the repository at this point in the history
  • Loading branch information
uipoet authored Jan 5, 2022
1 parent 438c136 commit 9d45d26
Show file tree
Hide file tree
Showing 7 changed files with 207 additions and 0 deletions.
14 changes: 14 additions & 0 deletions src/docs/pages/examples/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Card, Checkbox } from "ninjakit";
import { FunctionComponent } from "react";

export const CheckboxExamples: FunctionComponent = () => (
<Card appearance="elevated" id="checkbox" title="Checkbox">
<section>
<Checkbox>One</Checkbox>
<Checkbox defaultChecked label="Two" />
<Checkbox disabled label="Three" />
<Checkbox defaultChecked disabled label="Four" />
<Checkbox indeterminate label="Two" />
</section>
</Card>
);
2 changes: 2 additions & 0 deletions src/docs/pages/examples/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FunctionComponent } from "react";
import { AnchorButtonExamples } from "./anchor-button";
import { ButtonExamples } from "./button";
import { ButtonMenuExamples } from "./button-menu";
import { CheckboxExamples } from "./checkbox";
import { InputMenuExamples } from "./input-menu";
import { RadiosetExamples } from "./radioset";
import { TextInputExamples } from "./text-input";
Expand All @@ -14,6 +15,7 @@ export const Examples: FunctionComponent = () => (
<TextInputExamples />
<ButtonMenuExamples />
<InputMenuExamples />
<CheckboxExamples />
<RadiosetExamples />
</>
);
Expand Down
94 changes: 94 additions & 0 deletions src/lib/components/checkbox/checkbox.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
.checkbox {
align-items: center;
composes: nk from global;
display: flex;
position: relative;
}

.check {
fill: var(--md-color-on-primary);
font-size: 2rem;
left: 1rem;
position: absolute;
transform: scale3d(0, 0, 0);
transition: 300ms transform ease-in-out;
}

.checkbox,
.checkbox > input[type="checkbox"] {
cursor: pointer;
}

.checkbox {
align-items: center;
display: flex;
flex-wrap: nowrap;
}

.checkbox > input[type="checkbox"] {
appearance: none;
border: 0.2rem solid var(--md-color-outline);
border-radius: 0.2rem;
height: 2rem;
margin: 1rem;
position: relative;
width: 2rem;
}

.checkbox > input[type="checkbox"]::before {
background-color: var(--md-color-on-surface);
border-radius: 2rem;
content: "";
height: 4rem;
left: -1.2rem;
opacity: 0;
position: absolute;
top: -1.2rem;
transition: 300ms opacity ease-in-out;
width: 4rem;
}

.checkbox > input[type="checkbox"]:hover::before {
opacity: 0.08;
}

.checkbox > input[type="checkbox"]:active::before,
.checkbox > input[type="checkbox"]:focus-visible::before {
opacity: 0.12;
}

.checkbox > input[type="checkbox"]:checked,
.checkbox > input[type="checkbox"]:indeterminate {
background-color: var(--md-color-primary);
border-color: var(--md-color-primary);
}

.checkbox > input[type="checkbox"]:checked + .check {
transform: scale3d(1, 1, 1);
}

.checkbox > input[type="checkbox"]:indeterminate::after {
background-color: var(--md-color-on-primary);
content: "";
height: 0.2rem;
left: 0.25rem;
position: absolute;
top: 0.7rem;
width: 1rem;
}

.checkbox.disabled {
color: var(--md-color-on-surface);
cursor: default;
opacity: 0.38;
}

.checkbox > input[type="checkbox"]:disabled {
border-color: var(--md-color-on-surface);
cursor: default;
opacity: 0.38;
}

.checkbox > input[type="checkbox"]:disabled::before {
opacity: 0;
}
12 changes: 12 additions & 0 deletions src/lib/components/checkbox/checkbox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { render, screen } from "@testing-library/react";
import { Checkbox } from "ninjakit";

describe("checkbox", () => {
test("default", () => {
render(<Checkbox label="test" name="test" />);

const $checkbox = screen.getByRole("checkbox", { name: "test" });

expect($checkbox).toHaveClass("nk");
});
});
58 changes: 58 additions & 0 deletions src/lib/components/checkbox/checkbox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { forwardRef, MouseEventHandler, useEffect, useRef } from "react";
import { MdCheck } from "react-icons/md";

import { CheckboxProps, useClassName } from ".";
import styles from "./checkbox.module.css";

/** @see https://material.io/components/checkbox */
export const Checkbox = forwardRef<
HTMLInputElement,
JSX.IntrinsicElements["input"] & CheckboxProps
>(function (
{
children,
className: override,
disabled,
indeterminate,
label,
name,
onClick,
...props
},
ref
) {
const className = useClassName({ disabled, override });
const checkboxRef = useRef<HTMLInputElement>(null);

const handleClick: MouseEventHandler<HTMLInputElement> = (event) => {
if (onClick) return onClick(event);

if (checkboxRef.current === null) return;

checkboxRef.current.indeterminate = false;
};

useEffect(() => {
if (checkboxRef.current === null || indeterminate === undefined) return;

checkboxRef.current.indeterminate = indeterminate;
}, [indeterminate]);

return (
<label className={className}>
<input
{...props}
className="nk"
disabled={disabled}
name={name}
onClick={handleClick}
ref={ref || checkboxRef}
type="checkbox"
/>
<MdCheck className={styles.check} />
{children || label}
</label>
);
});

Checkbox.displayName = "Checkbox";
26 changes: 26 additions & 0 deletions src/lib/components/checkbox/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import typography from "../typography/typography.module.css";
import styles from "./checkbox.module.css";

export type CheckboxProps = JSX.IntrinsicElements["input"] & {
indeterminate?: boolean;
label?: string;
};

export function useClassName({
disabled,
override,
}: {
disabled?: boolean;
override?: string;
}): string | undefined {
return [
typography.labelLarge,
styles.checkbox,
disabled ? styles.disabled : undefined,
override,
]
.join(" ")
.trim();
}

export { Checkbox } from "./checkbox";
1 change: 1 addition & 0 deletions src/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export { Article } from "./components/article";
export { Aside } from "./components/aside";
export { AnchorButton, Button } from "./components/button";
export { Card } from "./components/card";
export { Checkbox } from "./components/checkbox";
export { FloatingActionButton } from "./components/floating-action-button";
export { Footer } from "./components/footer";
export { Header } from "./components/header";
Expand Down

0 comments on commit 9d45d26

Please sign in to comment.