mirror of
https://github.com/System-End/Vencord.git
synced 2026-04-19 19:45:09 +00:00
FormSwitch: make entire Switch clickable & add focus rings
This commit is contained in:
parent
c1556f0949
commit
b881b60ff7
6 changed files with 36 additions and 13 deletions
|
|
@ -1,5 +1,6 @@
|
|||
.vc-form-switch-wrapper {
|
||||
margin-bottom: 20px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vc-form-switch {
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export interface FormSwitchProps {
|
|||
|
||||
export function FormSwitch({ onChange, title, value, description, disabled, className, hideBorder }: FormSwitchProps) {
|
||||
return (
|
||||
<div className="vc-form-switch-wrapper">
|
||||
<label className="vc-form-switch-wrapper">
|
||||
<div className={classes("vc-form-switch", className, disabled && "vc-form-switch-disabled")}>
|
||||
<div className={"vc-form-switch-text"}>
|
||||
<Span size="md" weight="medium">{title}</Span>
|
||||
|
|
@ -36,7 +36,7 @@ export function FormSwitch({ onChange, title, value, description, disabled, clas
|
|||
<Switch checked={value} onChange={onChange} disabled={disabled} />
|
||||
</div>
|
||||
{!hideBorder && <Divider className="vc-form-switch-border" />}
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
width: 44px;
|
||||
|
||||
.high-contrast-mode & {
|
||||
border-color: var(--border-strong)
|
||||
border-color: var(--border-strong);
|
||||
}
|
||||
}
|
||||
|
||||
.vc-switch-checked {
|
||||
background: var(--brand-500);
|
||||
border-color: var(--control-border-primary-default)
|
||||
border-color: var(--control-border-primary-default);
|
||||
}
|
||||
|
||||
.vc-switch-disabled {
|
||||
|
|
@ -23,6 +23,11 @@
|
|||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.vc-switch-focusVisible {
|
||||
/* stylelint-disable-next-line custom-property-pattern */
|
||||
box-shadow: 0 0 0 4px var(--__adaptive-focus-ring-color, var(--focus-primary, #00b0f4));
|
||||
}
|
||||
|
||||
.vc-switch-slider {
|
||||
display: block;
|
||||
height: 20px;
|
||||
|
|
@ -31,10 +36,9 @@
|
|||
position: absolute;
|
||||
width: 28px;
|
||||
transition: 100ms transform ease-in-out;
|
||||
overflow: visible
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
|
||||
.vc-switch-input {
|
||||
border-radius: 14px;
|
||||
cursor: pointer;
|
||||
|
|
@ -46,7 +50,8 @@
|
|||
top: 0;
|
||||
width: 100%;
|
||||
|
||||
&[disabled] {
|
||||
pointer-events: none
|
||||
&:disabled {
|
||||
pointer-events: none;
|
||||
cursor: not-allowed
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,8 @@ import "./Switch.css";
|
|||
|
||||
import { classNameFactory } from "@api/Styles";
|
||||
import { classes } from "@utils/misc";
|
||||
import { useState } from "@webpack/common";
|
||||
import type { FocusEvent } from "react";
|
||||
|
||||
const switchCls = classNameFactory("vc-switch-");
|
||||
|
||||
|
|
@ -33,9 +35,21 @@ export interface SwitchProps {
|
|||
}
|
||||
|
||||
export function Switch({ checked, onChange, disabled }: SwitchProps) {
|
||||
const [focusVisible, setFocusVisible] = useState(false);
|
||||
|
||||
// Due to how we wrap the invisible input, there is no good way to do this with css.
|
||||
// We need it on the parent, not the input itself. For this, you can use either:
|
||||
// - :focus-within ~ this shows also when clicking, not just on keyboard focus => SUCKS
|
||||
// - :has(:focus-visible) ~ works but :has performs terribly inside Discord
|
||||
// - JS event handlers ~ what we are using now
|
||||
const handleFocusChange = (event: FocusEvent<HTMLInputElement>) => {
|
||||
const target = event.currentTarget;
|
||||
setFocusVisible(target.matches(":focus-visible"));
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className={classes(switchCls("container"), "default-colors", switchCls({ checked, disabled }))}>
|
||||
<div className={classes(switchCls("container", { checked, disabled, focusVisible }))}>
|
||||
<svg
|
||||
className={switchCls("slider")}
|
||||
viewBox="0 0 28 20"
|
||||
|
|
@ -62,6 +76,8 @@ export function Switch({ checked, onChange, disabled }: SwitchProps) {
|
|||
</svg>
|
||||
</svg>
|
||||
<input
|
||||
onFocus={handleFocusChange}
|
||||
onBlur={handleFocusChange}
|
||||
disabled={disabled}
|
||||
type="checkbox"
|
||||
className={switchCls("input")}
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ export function BooleanSetting({ option, pluginSettings, definedSettings, id, on
|
|||
}
|
||||
|
||||
return (
|
||||
<SettingsSection name={id} description={option.description} error={error} inlineSetting>
|
||||
<SettingsSection tag="label" name={id} description={option.description} error={error} inlineSetting>
|
||||
<Switch checked={state} onChange={handleChange} />
|
||||
</SettingsSection>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -38,11 +38,12 @@ interface SettingsSectionProps extends PropsWithChildren {
|
|||
description: string;
|
||||
error?: string | null;
|
||||
inlineSetting?: boolean;
|
||||
tag?: "label" | "div";
|
||||
}
|
||||
|
||||
export function SettingsSection({ name, description, error, inlineSetting, children }: SettingsSectionProps) {
|
||||
export function SettingsSection({ tag: Tag = "div", name, description, error, inlineSetting, children }: SettingsSectionProps) {
|
||||
return (
|
||||
<div className={cl("section")}>
|
||||
<Tag className={cl("section")}>
|
||||
<div className={classes(cl("content"), inlineSetting && cl("inline"))}>
|
||||
<div className={cl("label")}>
|
||||
{name && <Text className={cl("title")} variant="text-md/medium">{wordsToTitle(wordsFromCamel(name))}</Text>}
|
||||
|
|
@ -51,6 +52,6 @@ export function SettingsSection({ name, description, error, inlineSetting, child
|
|||
{children}
|
||||
</div>
|
||||
{error && <Text className={cl("error")} variant="text-sm/normal">{error}</Text>}
|
||||
</div>
|
||||
</Tag>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue