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:
parent
d8dbe51e7a
commit
5bdfea6e31
@ -27,7 +27,7 @@ import { ThemeStore } from "../../theme.store";
|
|||||||
import { UserStore } from "../../../common/user-store";
|
import { UserStore } from "../../../common/user-store";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { isWindows } from "../../../common/vars";
|
import { isWindows } from "../../../common/vars";
|
||||||
import { FormSwitch, Switcher } from "../switch";
|
import { Switch } from "../switch";
|
||||||
import moment from "moment-timezone";
|
import moment from "moment-timezone";
|
||||||
import { CONSTANTS, defaultExtensionRegistryUrl, ExtensionRegistryLocation } from "../../../common/user-store/preferences-helpers";
|
import { CONSTANTS, defaultExtensionRegistryUrl, ExtensionRegistryLocation } from "../../../common/user-store/preferences-helpers";
|
||||||
import { action } from "mobx";
|
import { action } from "mobx";
|
||||||
@ -86,16 +86,12 @@ export const Application = observer(() => {
|
|||||||
|
|
||||||
<section id="terminalSelection">
|
<section id="terminalSelection">
|
||||||
<SubTitle title="Terminal copy & paste" />
|
<SubTitle title="Terminal copy & paste" />
|
||||||
<FormSwitch
|
<Switch
|
||||||
label="Copy on select and paste on right-click"
|
|
||||||
control={
|
|
||||||
<Switcher
|
|
||||||
checked={userStore.terminalCopyOnSelect}
|
checked={userStore.terminalCopyOnSelect}
|
||||||
onChange={v => userStore.terminalCopyOnSelect = v.target.checked}
|
onChange={() => userStore.terminalCopyOnSelect = !userStore.terminalCopyOnSelect}
|
||||||
name="terminalCopyOnSelect"
|
>
|
||||||
/>
|
Copy on select and paste on right-click
|
||||||
}
|
</Switch>
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<hr/>
|
<hr/>
|
||||||
@ -135,16 +131,9 @@ export const Application = observer(() => {
|
|||||||
|
|
||||||
<section id="other">
|
<section id="other">
|
||||||
<SubTitle title="Start-up"/>
|
<SubTitle title="Start-up"/>
|
||||||
<FormSwitch
|
<Switch checked={userStore.openAtLogin} onChange={() => userStore.openAtLogin = !userStore.openAtLogin}>
|
||||||
control={
|
Automatically start Lens on login
|
||||||
<Switcher
|
</Switch>
|
||||||
checked={userStore.openAtLogin}
|
|
||||||
onChange={v => userStore.openAtLogin = v.target.checked}
|
|
||||||
name="startup"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Automatically start Lens on login"
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<hr />
|
<hr />
|
||||||
|
|||||||
@ -21,7 +21,7 @@
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { UserStore } from "../../../common/user-store";
|
import { UserStore } from "../../../common/user-store";
|
||||||
import { FormSwitch, Switcher } from "../switch";
|
import { Switch } from "../switch";
|
||||||
import { Select } from "../select";
|
import { Select } from "../select";
|
||||||
import { SubTitle } from "../layout/sub-title";
|
import { SubTitle } from "../layout/sub-title";
|
||||||
import { SubHeader } from "../layout/sub-header";
|
import { SubHeader } from "../layout/sub-header";
|
||||||
@ -45,15 +45,12 @@ export const Editor = observer(() => {
|
|||||||
<section>
|
<section>
|
||||||
<div className="flex gaps justify-space-between">
|
<div className="flex gaps justify-space-between">
|
||||||
<div className="flex gaps align-center">
|
<div className="flex gaps align-center">
|
||||||
<FormSwitch
|
<Switch
|
||||||
label={<SubHeader compact>Show minimap</SubHeader>}
|
|
||||||
control={
|
|
||||||
<Switcher
|
|
||||||
checked={editorConfiguration.minimap.enabled}
|
checked={editorConfiguration.minimap.enabled}
|
||||||
onChange={(evt, checked) => editorConfiguration.minimap.enabled = checked}
|
onChange={() => editorConfiguration.minimap.enabled = !editorConfiguration.minimap.enabled}
|
||||||
/>
|
>
|
||||||
}
|
Show minimap
|
||||||
/>
|
</Switch>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gaps align-center">
|
<div className="flex gaps align-center">
|
||||||
<SubHeader compact>Position</SubHeader>
|
<SubHeader compact>Position</SubHeader>
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import { getDefaultKubectlDownloadPath, UserStore } from "../../../common/user-s
|
|||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import { bundledKubectlPath } from "../../../main/kubectl";
|
import { bundledKubectlPath } from "../../../main/kubectl";
|
||||||
import { SelectOption, Select } from "../select";
|
import { SelectOption, Select } from "../select";
|
||||||
import { FormSwitch, Switcher } from "../switch";
|
import { Switch } from "../switch";
|
||||||
import { packageMirrors } from "../../../common/user-store/preferences-helpers";
|
import { packageMirrors } from "../../../common/user-store/preferences-helpers";
|
||||||
|
|
||||||
export const KubectlBinaries = observer(() => {
|
export const KubectlBinaries = observer(() => {
|
||||||
@ -48,16 +48,12 @@ export const KubectlBinaries = observer(() => {
|
|||||||
<>
|
<>
|
||||||
<section>
|
<section>
|
||||||
<SubTitle title="Kubectl binary download"/>
|
<SubTitle title="Kubectl binary download"/>
|
||||||
<FormSwitch
|
<Switch
|
||||||
control={
|
|
||||||
<Switcher
|
|
||||||
checked={userStore.downloadKubectlBinaries}
|
checked={userStore.downloadKubectlBinaries}
|
||||||
onChange={v => userStore.downloadKubectlBinaries = v.target.checked}
|
onChange={() => userStore.downloadKubectlBinaries = !userStore.downloadKubectlBinaries}
|
||||||
name="kubectl-download"
|
>
|
||||||
/>
|
Download kubectl binaries matching the Kubernetes cluster version
|
||||||
}
|
</Switch>
|
||||||
label="Download kubectl binaries matching the Kubernetes cluster version"
|
|
||||||
/>
|
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<section>
|
||||||
|
|||||||
@ -24,10 +24,11 @@ import React from "react";
|
|||||||
import { UserStore } from "../../../common/user-store";
|
import { UserStore } from "../../../common/user-store";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { SubTitle } from "../layout/sub-title";
|
import { SubTitle } from "../layout/sub-title";
|
||||||
import { FormSwitch, Switcher } from "../switch";
|
import { Switch } from "../switch";
|
||||||
|
|
||||||
export const LensProxy = observer(() => {
|
export const LensProxy = observer(() => {
|
||||||
const [proxy, setProxy] = React.useState(UserStore.getInstance().httpsProxy || "");
|
const [proxy, setProxy] = React.useState(UserStore.getInstance().httpsProxy || "");
|
||||||
|
const store = UserStore.getInstance();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section id="proxy">
|
<section id="proxy">
|
||||||
@ -50,16 +51,9 @@ export const LensProxy = observer(() => {
|
|||||||
|
|
||||||
<section className="small">
|
<section className="small">
|
||||||
<SubTitle title="Certificate Trust"/>
|
<SubTitle title="Certificate Trust"/>
|
||||||
<FormSwitch
|
<Switch checked={store.allowUntrustedCAs} onChange={() => store.allowUntrustedCAs = !store.allowUntrustedCAs}>
|
||||||
control={
|
Allow untrusted Certificate Authorities
|
||||||
<Switcher
|
</Switch>
|
||||||
checked={UserStore.getInstance().allowUntrustedCAs}
|
|
||||||
onChange={v => UserStore.getInstance().allowUntrustedCAs = v.target.checked}
|
|
||||||
name="startup"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
label="Allow untrusted Certificate Authorities"
|
|
||||||
/>
|
|
||||||
<small className="hint">
|
<small className="hint">
|
||||||
This will make Lens to trust ANY certificate authority without any validations.{" "}
|
This will make Lens to trust ANY certificate authority without any validations.{" "}
|
||||||
Needed with some corporate proxies that do certificate re-writing.{" "}
|
Needed with some corporate proxies that do certificate re-writing.{" "}
|
||||||
|
|||||||
67
src/renderer/components/switch/__tests__/switch.test.tsx
Normal file
67
src/renderer/components/switch/__tests__/switch.test.tsx
Normal file
@ -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) {
|
export function FormSwitch(props: FormControlLabelProps) {
|
||||||
const classes = useStyles();
|
const classes = useStyles();
|
||||||
|
|
||||||
|
|||||||
@ -21,3 +21,4 @@
|
|||||||
|
|
||||||
export * from "./switcher";
|
export * from "./switcher";
|
||||||
export * from "./form-switcher";
|
export * from "./form-switcher";
|
||||||
|
export * from "./switch";
|
||||||
|
|||||||
121
src/renderer/components/switch/switch.module.scss
Normal file
121
src/renderer/components/switch/switch.module.scss
Normal file
@ -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%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
38
src/renderer/components/switch/switch.tsx
Normal file
38
src/renderer/components/switch/switch.tsx
Normal file
@ -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;
|
classes: Styles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use <Switch/> instead from "../switch.tsx".
|
||||||
|
*/
|
||||||
export const Switcher = withStyles((theme: Theme) =>
|
export const Switcher = withStyles((theme: Theme) =>
|
||||||
createStyles({
|
createStyles({
|
||||||
root: {
|
root: {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user