From 0d57129de7e83ce43f67f7d9de087e9260a39574 Mon Sep 17 00:00:00 2001 From: Zack Rauen Date: Mon, 6 Mar 2023 19:17:28 -0500 Subject: [PATCH] Convert settings types --- renderer/src/ui/customcss/checkbox.jsx | 30 +++--- renderer/src/ui/settings/components/color.jsx | 97 +++++++++---------- .../src/ui/settings/components/dropdown.jsx | 76 +++++++-------- renderer/src/ui/settings/components/item.jsx | 22 ++--- .../src/ui/settings/components/keybind.jsx | 92 ++++++------------ .../src/ui/settings/components/number.jsx | 22 ++--- renderer/src/ui/settings/components/radio.jsx | 43 +++----- .../src/ui/settings/components/search.jsx | 30 +++--- .../src/ui/settings/components/slider.jsx | 27 +++--- .../src/ui/settings/components/switch.jsx | 47 ++++----- .../src/ui/settings/components/textbox.jsx | 22 ++--- 11 files changed, 212 insertions(+), 296 deletions(-) diff --git a/renderer/src/ui/customcss/checkbox.jsx b/renderer/src/ui/customcss/checkbox.jsx index 79f069e6..f483e8cc 100644 --- a/renderer/src/ui/customcss/checkbox.jsx +++ b/renderer/src/ui/customcss/checkbox.jsx @@ -1,27 +1,23 @@ import {React} from "modules"; -export default class Checkbox extends React.Component { - constructor(props) { - super(props); - this.onClick = this.onClick.bind(this); - this.state = {checked: this.props.checked || false}; - } +const {useState, useCallback} = React; - render() { - return
-
{this.props.text}
-
+ +export default function Checkbox(props) { + const [checked, setChecked] = useState(props.checked); + const onClick = useCallback(() => { + props?.onChange(!checked); + setChecked(!checked); + }, [checked]); + + return
+
{props.text}
+
- +
; - } - - onClick() { - this.props.onChange(!this.state.checked); - this.setState({checked: !this.state.checked}); - } } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/color.jsx b/renderer/src/ui/settings/components/color.jsx index 22774b0b..31dcd30b 100644 --- a/renderer/src/ui/settings/components/color.jsx +++ b/renderer/src/ui/settings/components/color.jsx @@ -1,5 +1,8 @@ import {DiscordModules, React} from "modules"; +const {useState, useCallback} = React; + + const Checkmark = React.memo((props) => ( @@ -28,7 +31,6 @@ const resolveColor = (color, hex = true) => { } }; - const getRGB = (color) => { let result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color); if (result) return [parseInt(result[1]), parseInt(result[2]), parseInt(result[3])]; @@ -52,56 +54,47 @@ const getContrastColor = (color) => { return (luma(color) >= 165) ? "#000" : "#fff"; }; -export default class Color extends React.Component { - constructor(props) { - super(props); - this.state = {value: this.props.value}; - this.onChange = this.onChange.bind(this); - } - onChange(e) { - this.setState({value: e.target.value}); - if (this.props.onChange) this.props.onChange(resolveColor(e.target.value)); - } +export default function Color({value: initialValue, onChange, colors = defaultColors, defaultValue}) { + const [value, setValue] = useState(initialValue); + const change = useCallback((e) => { + onChange?.(resolveColor(e.target.value)); + setValue(e.target.value); + }, []); - render() { - const intValue = resolveColor(this.state.value, false); - const {colors = defaultColors, defaultValue} = this.props; - - - return
-
- - {props => ( -
this.onChange({target: {value: defaultValue}})}> - {intValue === resolveColor(defaultValue, false) - ? - : null - } -
- )} -
- - {props => ( -
- - -
- )} -
-
-
- { - colors.map((int, index) => ( -
this.onChange({target: {value: int}})}> - {intValue === int - ? - : null - } -
- )) - } -
-
; - } -} + const intValue = resolveColor(value, false); + return
+
+ + {props => ( +
change({target: {value: defaultValue}})}> + {intValue === resolveColor(defaultValue, false) + ? + : null + } +
+ )} +
+ + {props => ( +
+ + +
+ )} +
+
+
+ { + colors.map((int, index) => ( +
change({target: {value: int}})}> + {intValue === int + ? + : null + } +
+ )) + } +
+
; +} \ No newline at end of file diff --git a/renderer/src/ui/settings/components/dropdown.jsx b/renderer/src/ui/settings/components/dropdown.jsx index 241aa003..004f12d7 100644 --- a/renderer/src/ui/settings/components/dropdown.jsx +++ b/renderer/src/ui/settings/components/dropdown.jsx @@ -1,56 +1,46 @@ import {React} from "modules"; import Arrow from "../../icons/downarrow"; -export default class Select extends React.Component { - constructor(props) { - super(props); - this.state = {open: false, value: this.props.hasOwnProperty("value") ? this.props.value : this.props.options[0].value}; - this.dropdown = React.createRef(); - this.onChange = this.onChange.bind(this); - this.showMenu = this.showMenu.bind(this); - this.hideMenu = this.hideMenu.bind(this); - } +const {useState, useCallback} = React; - showMenu(event) { + +export default function Select({value: initialValue, options, style, onChange}) { + const [value, setValue] = useState(initialValue ?? options[0].value); + const change = useCallback((val) => { + onChange?.(val); + setValue(val); + }, []); + + + const hideMenu = useCallback(() => { + setOpen(false); + document.removeEventListener("click", hideMenu); + }, []); + + const [open, setOpen] = useState(false); + const showMenu = useCallback((event) => { event.preventDefault(); event.stopPropagation(); - this.setState((state) => ({open: !state.open}), () => { - if (!this.state.open) return; + const next = !open; + setOpen(next); + if (!next) return; + document.addEventListener("click", hideMenu); + }, [open]); - document.addEventListener("click", this.hideMenu); - }); - } - hideMenu() { - this.setState({open: false}, () => { - document.removeEventListener("click", this.hideMenu); - }); - } - - onChange(value) { - this.setState({value}); - if (this.props.onChange) this.props.onChange(value); - } - - get selected() {return this.props.options.find(o => o.value == this.state.value);} - - get options() { - const selected = this.selected; - return
- {this.props.options.map(opt => -
{opt.label}
+ const selected = options.find(o => o.value == value); + const optionComponents =
+ {options.map(opt => +
change(opt.value)}>{opt.label}
)}
; - } - render() { - const style = this.props.style == "transparent" ? " bd-select-transparent" : ""; - const isOpen = this.state.open ? " menu-open" : ""; - return
-
{this.selected.label}
- - {this.state.open && this.options} -
; - } + const styleClass = style == "transparent" ? " bd-select-transparent" : ""; + const isOpen = open ? " menu-open" : ""; + return
+
{selected.label}
+ + {open && optionComponents} +
; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/item.jsx b/renderer/src/ui/settings/components/item.jsx index e7fc2075..0fdb40e0 100644 --- a/renderer/src/ui/settings/components/item.jsx +++ b/renderer/src/ui/settings/components/item.jsx @@ -1,15 +1,13 @@ import {React} from "modules"; -export default class SettingItem extends React.Component { - render() { - return
-
- - {this.props.inline && this.props.children} -
-
{this.props.note}
- {!this.props.inline && this.props.children} -
-
; - } +export default function SettingItem({id, name, note, inline, children}) { + return
+
+ + {inline && children} +
+
{note}
+ {!inline && children} +
+
; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/keybind.jsx b/renderer/src/ui/settings/components/keybind.jsx index dd028bfc..20dd638b 100644 --- a/renderer/src/ui/settings/components/keybind.jsx +++ b/renderer/src/ui/settings/components/keybind.jsx @@ -3,78 +3,50 @@ import {React} from "modules"; import Keyboard from "../../icons/keyboard"; import Close from "../../icons/close"; -export default class Keybind extends React.Component { - constructor(props) { - super(props); - this.state = {value: this.props.value, isRecording: false}; - this.onClick = this.onClick.bind(this); - this.keyHandler = this.keyHandler.bind(this); - this.clearKeybind = this.clearKeybind.bind(this); - this.accum = []; - this.max = this.props.max ?? 2; - } +const {useState, useCallback, useEffect} = React; - componentDidMount() { - window.addEventListener("keydown", this.keyHandler); - } - componentWillUnmount() { - window.removeEventListener("keydown", this.keyHandler); - } +export default function Keybind({value: initialValue, onChange, max = 2, clearable = true}) { + const [state, setState] = useState({value: initialValue, isRecording: false, accum: []}); - /** - * - * @param {KeyboardEvent} event - */ - keyHandler(event) { - if (!this.state.isRecording) return; + useEffect(() => { + window.addEventListener("keydown", keyHandler); + return () => window.removeEventListener("keydown", keyHandler); + }); + + const keyHandler = useCallback((event) => { + if (!state.isRecording) return; event.stopImmediatePropagation(); event.stopPropagation(); event.preventDefault(); - if (event.repeat || this.accum.includes(event.key)) return; + if (event.repeat || state.accum.includes(event.key)) return; - this.accum.push(event.key); - if (this.accum.length == this.max) { - if (this.props.onChange) this.props.onChange(this.accum); - this.setState({value: this.accum.slice(0), isRecording: false}, () => this.accum.splice(0, this.accum.length)); + state.accum.push(event.key); + if (state.accum.length == max) { + if (onChange) onChange(state.accum); + setState({value: state.accum.slice(0), isRecording: false, accum: []}); } - } + }, [state]); - /** - * - * @param {MouseEvent} e - */ - onClick(e) { - if (e.target?.className?.includes?.("bd-keybind-clear") || e.target?.closest(".bd-button")?.className?.includes("bd-keybind-clear")) return this.clearKeybind(e); - this.setState({isRecording: !this.state.isRecording}); - } + const onClick = useCallback((e) => { + if (e.target?.className?.includes?.("bd-keybind-clear") || e.target?.closest(".bd-button")?.className?.includes("bd-keybind-clear")) return clearKeybind(e); + setState({...state, isRecording: !state.isRecording}); + }, [state]); - /** - * - * @param {MouseEvent} event - */ - clearKeybind(event) { + const clearKeybind = useCallback((event) => { event.stopPropagation(); event.preventDefault(); - this.accum.splice(0, this.accum.length); - if (this.props.onChange) this.props.onChange(this.accum); - this.setState({value: this.accum, isRecording: false}); - } + if (onChange) onChange([]); + setState({...state, value: [], accum: []}); + }, []); - display() { - if (this.state.isRecording) return "Recording..."; - if (!this.state.value.length) return "N/A"; - return this.state.value.join(" + "); - } - render() { - const {clearable = true} = this.props; - return
- -
- - {clearable && } -
-
; - } + const displayValue = state.isRecording ? "Recording..." : !state.value.length ? "N/A" : state.value.join(" + "); + return
+ +
+ + {clearable && } +
+
; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/number.jsx b/renderer/src/ui/settings/components/number.jsx index 51e9189b..c634d0db 100644 --- a/renderer/src/ui/settings/components/number.jsx +++ b/renderer/src/ui/settings/components/number.jsx @@ -1,18 +1,14 @@ import {React} from "modules"; -export default class Number extends React.Component { - constructor(props) { - super(props); - this.state = {value: this.props.value}; - this.onChange = this.onChange.bind(this); - } +const {useState, useCallback} = React; - onChange(e) { - this.setState({value: e.target.value}); - if (this.props.onChange) this.props.onChange(e.target.value); - } - render() { - return ; - } +export default function Number({value: initialValue, min, max, step, onChange}) { + const [value, setValue] = useState(initialValue); + const change = useCallback((e) => { + onChange?.(e.target.value); + setValue(e.target.value); + }, []); + + return ; } \ No newline at end of file diff --git a/renderer/src/ui/settings/components/radio.jsx b/renderer/src/ui/settings/components/radio.jsx index fbacc3fa..99d30d60 100644 --- a/renderer/src/ui/settings/components/radio.jsx +++ b/renderer/src/ui/settings/components/radio.jsx @@ -2,25 +2,22 @@ import {React} from "modules"; import RadioIcon from "../../icons/radio"; -export default class Radio extends React.Component { - constructor(props) { - super(props); - this.state = {value: this.props.options.findIndex(o => o.value === this.props.value)}; - this.onChange = this.onChange.bind(this); - this.renderOption = this.renderOption.bind(this); - } +const {useState, useCallback} = React; - onChange(e) { - const index = parseInt(e.target.value); - const newValue = this.props.options[index].value; - this.setState({value: index}); - if (this.props.onChange) this.props.onChange(newValue); - } - renderOption(opt, index) { - const isSelected = this.state.value === index; +export default function Radio({name, value, options, onChange}) { + const [index, setIndex] = useState(options.findIndex(o => o.value === value)); + const change = useCallback((e) => { + const newIndex = parseInt(e.target.value); + const newValue = options[newIndex].value; + onChange?.(newValue); + setIndex(newIndex); + }, [index, options]); + + function renderOption(opt, i) { + const isSelected = index === i; return