From d5ce56930bd3f43d5f6ce1dc1138d1c3a0569de9 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Sun, 28 Jun 2026 22:43:18 -0400 Subject: [PATCH] refactor(ui): extract shared SettingsSelect; replace raw elements (which render OS-styled and broke under non-default themes via colorScheme:'dark'): - Profile "auto-clear after" select - PushRuleEditor add-rule mode select (dropped the now-unused handleModeChange) The form-tied timezone `, which renders OS-styled and + * breaks under non-default themes. + */ +export function SettingsSelect({ + value, + options, + onChange, + 'aria-label': ariaLabel, +}: { + value: T; + options: SettingsSelectOption[]; + onChange: (v: T) => void; + 'aria-label'?: string; +}) { + const [menuCords, setMenuCords] = useState(); + const selectedLabel = options.find((o) => o.value === value)?.label ?? value; + + const handleMenu: MouseEventHandler = (evt) => { + setMenuCords(evt.currentTarget.getBoundingClientRect()); + }; + + const handleSelect = (v: T) => { + onChange(v); + setMenuCords(undefined); + }; + + return ( + <> + + setMenuCords(undefined), + clickOutsideDeactivates: true, + isKeyForward: (evt: KeyboardEvent) => + evt.key === 'ArrowDown' || evt.key === 'ArrowRight', + isKeyBackward: (evt: KeyboardEvent) => + evt.key === 'ArrowUp' || evt.key === 'ArrowLeft', + escapeDeactivates: stopPropagation, + }} + > + + + {options.map((opt) => ( + !opt.disabled && handleSelect(opt.value)} + > + {opt.label} + + ))} + + + + } + /> + + ); +} diff --git a/src/app/features/settings/account/Profile.tsx b/src/app/features/settings/account/Profile.tsx index e8df2b0b3..7a6f1da51 100644 --- a/src/app/features/settings/account/Profile.tsx +++ b/src/app/features/settings/account/Profile.tsx @@ -30,6 +30,7 @@ import { } from 'folds'; import { Method } from 'matrix-js-sdk'; import FocusTrap from 'focus-trap-react'; +import { SettingsSelect } from '../../../components/settings-select/SettingsSelect'; import { SequenceCard } from '../../../components/sequence-card'; import { SequenceCardStyle } from '../styles.css'; import { SettingTile } from '../../../components/setting-tile'; @@ -544,35 +545,12 @@ function ProfileStatus() { Auto-clear after: - + /> {(presence?.status || statusMsg) && ( - setMenuCords(undefined), - clickOutsideDeactivates: true, - isKeyForward: (evt: KeyboardEvent) => - evt.key === 'ArrowDown' || evt.key === 'ArrowRight', - isKeyBackward: (evt: KeyboardEvent) => - evt.key === 'ArrowUp' || evt.key === 'ArrowLeft', - escapeDeactivates: stopPropagation, - }} - > - - - {options.map((opt) => ( - !opt.disabled && handleSelect(opt.value)} - > - {opt.label} - - ))} - - - - } - /> - - ); -} - function SystemThemePreferences() { const themeKind = useSystemThemeKind(); const themeNames = useThemeNames(); diff --git a/src/app/features/settings/notifications/PushRuleEditor.tsx b/src/app/features/settings/notifications/PushRuleEditor.tsx index 95594446b..df57676db 100644 --- a/src/app/features/settings/notifications/PushRuleEditor.tsx +++ b/src/app/features/settings/notifications/PushRuleEditor.tsx @@ -1,6 +1,7 @@ import React, { ChangeEventHandler, FormEventHandler, useCallback, useMemo, useState } from 'react'; import { IPushRule, IPushRules, PushRuleKind } from 'matrix-js-sdk'; import { Box, Text, Button, Input, config, IconButton, Icons, Icon, Spinner, Switch } from 'folds'; +import { SettingsSelect } from '../../../components/settings-select/SettingsSelect'; import { useAccountData } from '../../../hooks/useAccountData'; import { AccountDataEvent } from '../../../../types/matrix/accountData'; import { SequenceCard } from '../../../components/sequence-card'; @@ -193,10 +194,6 @@ function AddRuleForm({ kind, placeholder, label }: AddRuleFormProps) { setRuleId(evt.currentTarget.value); }; - const handleModeChange: ChangeEventHandler = (evt) => { - setMode(evt.target.value as NotificationMode); - }; - return ( @@ -217,24 +214,12 @@ function AddRuleForm({ kind, placeholder, label }: AddRuleFormProps) { /> - + options={ADD_MODES.map((m) => ({ value: m, label: MODE_LABELS[m] }))} + onChange={setMode} + aria-label="Notification mode" + />