mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Native switch component (#4610)
* Switch component initial draft
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Add onClick event
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* onClick fine-tunings
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Fine-tuning styles
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Adding tests
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Fix light theme thumb color
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Using native switch in places
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Removing material ui switcher
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Revert "Removing material ui switcher"
This reverts commit 6b9e0a090c.
* Mark Switcher and FormSwitch as deprecated
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Cleaning up
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Using theme-light mixin
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Fix fetching values from onChange callback
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Add custon onChange event with checked prop
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Check for onChange() availability
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
* Fix show minimap label
Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
1 parent
d8dbe51e7a
commit
5bdfea6e31
10 files changed
+262
-53
No files matched your search
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent, render } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import { Switch } from "..";
|
||||
|
||||
describe("<Switch/>", () => {
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = render(<Switch />);
|
||||
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
it("render label text", () => {
|
||||
const { getByLabelText } = render(<Switch>Test label</Switch>);
|
||||
|
||||
expect(getByLabelText("Test label")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("passes disabled and checked attributes to input", () => {
|
||||
const { container } = render(<Switch checked disabled/>);
|
||||
const checkbox = container.querySelector("input[type=checkbox]");
|
||||
|
||||
expect(checkbox).toHaveAttribute("disabled");
|
||||
expect(checkbox).toHaveAttribute("checked");
|
||||
});
|
||||
|
||||
it("onClick event fired", () => {
|
||||
const onClick = jest.fn();
|
||||
const { getByTestId } = render(<Switch onClick={onClick}/>);
|
||||
const switcher = getByTestId("switch");
|
||||
|
||||
fireEvent.click(switcher);
|
||||
|
||||
expect(onClick).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("onClick event not fired for disabled item", () => {
|
||||
const onClick = jest.fn();
|
||||
const { getByTestId } = render(<Switch onClick={onClick} disabled/>);
|
||||
const switcher = getByTestId("switch");
|
||||
|
||||
fireEvent.click(switcher);
|
||||
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -35,6 +35,9 @@ const useStyles = makeStyles({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* @deprecated Use <Switch/> instead from "../switch.tsx".
|
||||
*/
|
||||
export function FormSwitch(props: FormControlLabelProps) {
|
||||
const classes = useStyles();
|
||||
|
||||
|
||||
@@ -21,3 +21,4 @@
|
||||
|
||||
export * from "./switcher";
|
||||
export * from "./form-switcher";
|
||||
export * from "./switch";
|
||||
@@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
.Switch {
|
||||
--thumb-size: 2rem;
|
||||
--thumb-color: hsl(0 0% 100%);
|
||||
--thumb-color-highlight: hsl(0 0% 100% / 25%);
|
||||
|
||||
--track-size: calc(var(--thumb-size) * 2);
|
||||
--track-padding: 2px;
|
||||
--track-color-inactive: hsl(80 0% 35%);
|
||||
--track-color-active: hsl(110, 60%, 60%);
|
||||
|
||||
--thumb-position: 0%;
|
||||
--thumb-transition-duration: .25s;
|
||||
|
||||
--hover-highlight-size: 0;
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2ch;
|
||||
justify-content: space-between;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
color: var(--textColorAccent);
|
||||
font-weight: 500;
|
||||
|
||||
& > input {
|
||||
padding: var(--track-padding);
|
||||
background: var(--track-color-inactive);
|
||||
inline-size: var(--track-size);
|
||||
block-size: var(--thumb-size);
|
||||
border-radius: var(--track-size);
|
||||
|
||||
appearance: none;
|
||||
pointer-events: none;
|
||||
border: none;
|
||||
outline-offset: 5px;
|
||||
box-sizing: content-box;
|
||||
|
||||
flex-shrink: 0;
|
||||
display: grid;
|
||||
align-items: center;
|
||||
grid: [track] 1fr / [track] 1fr;
|
||||
|
||||
transition: background-color .25s ease;
|
||||
|
||||
&::before {
|
||||
content: "";
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
grid-area: track;
|
||||
inline-size: var(--thumb-size);
|
||||
block-size: var(--thumb-size);
|
||||
background: var(--thumb-color);
|
||||
box-shadow: 0 0 0 var(--hover-highlight-size) var(--thumb-color-highlight);
|
||||
border-radius: 50%;
|
||||
transform: translateX(var(--thumb-position));
|
||||
transition:
|
||||
transform var(--thumb-transition-duration) ease,
|
||||
box-shadow .25s ease;
|
||||
}
|
||||
|
||||
&:not(:disabled):hover::before {
|
||||
--hover-highlight-size: .5rem;
|
||||
}
|
||||
|
||||
&:checked {
|
||||
background: var(--track-color-active);
|
||||
--thumb-position: 100%;
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
--track-color-inactive: hsl(80 0% 30%);
|
||||
--thumb-color: transparent;
|
||||
|
||||
&::before {
|
||||
cursor: not-allowed;
|
||||
box-shadow: inset 0 0 0 2px hsl(0 0% 0% / 40%);
|
||||
}
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
box-shadow: 0 0 0 2px var(--blue);
|
||||
}
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
@include theme-light {
|
||||
.Switch {
|
||||
--thumb-color-highlight: hsl(0 0% 0% / 25%);
|
||||
|
||||
& > input {
|
||||
&:disabled {
|
||||
--track-color-inactive: hsl(80 0% 80%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* Copyright (c) 2021 OpenLens Authors
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
* this software and associated documentation files (the "Software"), to deal in
|
||||
* the Software without restriction, including without limitation the rights to
|
||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import styles from "./switch.module.scss";
|
||||
|
||||
import React, { ChangeEvent, HTMLProps } from "react";
|
||||
import { cssNames } from "../../utils";
|
||||
|
||||
interface Props extends Omit<HTMLProps<HTMLInputElement>, "onChange"> {
|
||||
onChange?: (checked: boolean, event: ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
export function Switch({ children, disabled, onChange, ...props }: Props) {
|
||||
return (
|
||||
<label className={cssNames(styles.Switch, { [styles.disabled]: disabled })} data-testid="switch">
|
||||
{children}
|
||||
<input type="checkbox" role="switch" disabled={disabled} onChange={(event) => onChange?.(props.checked, event)} {...props}/>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
@@ -31,6 +31,9 @@ interface Props extends SwitchProps {
|
||||
classes: Styles;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use <Switch/> instead from "../switch.tsx".
|
||||
*/
|
||||
export const Switcher = withStyles((theme: Theme) =>
|
||||
createStyles({
|
||||
root: {
|
||||
|
||||
Reference in new issue
Block a user