Skip to content

Commit 51291a6

Browse files
committed
refactor(react/settings): associate IDs for labels
1 parent 0841603 commit 51291a6

File tree

8 files changed

+46
-27
lines changed

8 files changed

+46
-27
lines changed

apps/client/src/stylesheets/style.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,10 @@ textarea,
144144
pointer-events: none;
145145
}
146146

147+
.form-group {
148+
margin-bottom: 15px;
149+
}
150+
147151
/* Add a gap between consecutive radios / check boxes */
148152
label.tn-radio + label.tn-radio,
149153
label.tn-checkbox + label.tn-checkbox {

apps/client/src/widgets/react/FormCheckbox.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ComponentChildren } from "preact";
55
import { CSSProperties, memo } from "preact/compat";
66

77
interface FormCheckboxProps {
8-
name: string;
8+
id?: string;
99
label: string | ComponentChildren;
1010
/**
1111
* If set, the checkbox label will be underlined and dotted, indicating a hint. When hovered, it will show the hint text.
@@ -17,7 +17,7 @@ interface FormCheckboxProps {
1717
containerStyle?: CSSProperties;
1818
}
1919

20-
const FormCheckbox = memo(({ name, disabled, label, currentValue, onChange, hint, containerStyle }: FormCheckboxProps) => {
20+
const FormCheckbox = memo(({ id, disabled, label, currentValue, onChange, hint, containerStyle }: FormCheckboxProps) => {
2121
const labelRef = useRef<HTMLLabelElement>(null);
2222

2323
// Fix: Move useEffect outside conditional
@@ -55,9 +55,10 @@ const FormCheckbox = memo(({ name, disabled, label, currentValue, onChange, hint
5555
ref={labelRef}
5656
>
5757
<input
58+
id={id}
5859
className="form-check-input"
5960
type="checkbox"
60-
name={name}
61+
name={id}
6162
checked={currentValue || false}
6263
value="1"
6364
disabled={disabled}

apps/client/src/widgets/react/FormGroup.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
1-
import { ComponentChildren, RefObject } from "preact";
1+
import { cloneElement, ComponentChildren, RefObject, VNode } from "preact";
2+
import { CSSProperties } from "preact/compat";
3+
import { useUniqueName } from "./hooks";
24

35
interface FormGroupProps {
6+
name: string;
47
labelRef?: RefObject<HTMLLabelElement>;
58
label?: string;
69
title?: string;
710
className?: string;
8-
children: ComponentChildren;
11+
children: VNode<any>;
912
description?: string | ComponentChildren;
1013
disabled?: boolean;
14+
style?: CSSProperties;
1115
}
1216

13-
export default function FormGroup({ label, title, className, children, description, labelRef, disabled }: FormGroupProps) {
17+
export default function FormGroup({ name, label, title, className, children, description, labelRef, disabled, style }: FormGroupProps) {
18+
const id = useUniqueName(name);
19+
const childWithId = cloneElement(children, { id });
20+
1421
return (
15-
<div className={`form-group ${className} ${disabled ? "disabled" : ""}`} title={title}
16-
style={{ "margin-bottom": "15px" }}>
17-
{ label
18-
? <label style={{ width: "100%" }} ref={labelRef}>
19-
{label && <div style={{ "margin-bottom": "10px" }}>{label}</div> }
20-
{children}
21-
</label>
22-
: children}
22+
<div className={`form-group ${className} ${disabled ? "disabled" : ""}`} title={title} style={style}>
23+
{ label &&
24+
<label style={{ width: "100%" }} ref={labelRef} htmlFor={id}>{label}</label>}
25+
26+
{childWithId}
2327

2428
{description && <small className="form-text">{description}</small>}
2529
</div>

apps/client/src/widgets/react/FormSelect.tsx

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,17 @@ interface ValueConfig<T, Q> {
1919
}
2020

2121
interface FormSelectProps<T, Q> extends ValueConfig<T, Q> {
22+
id?: string;
2223
onChange: OnChangeListener;
2324
style?: CSSProperties;
2425
}
2526

2627
/**
2728
* Combobox component that takes in any object array as data. Each item of the array is rendered as an item, and the key and values are obtained by looking into the object by a specified key.
2829
*/
29-
export default function FormSelect<T>({ onChange, style, ...restProps }: FormSelectProps<T, T>) {
30+
export default function FormSelect<T>({ id, onChange, style, ...restProps }: FormSelectProps<T, T>) {
3031
return (
31-
<FormSelectBody onChange={onChange} style={style}>
32+
<FormSelectBody id={id} onChange={onChange} style={style}>
3233
<FormSelectGroup {...restProps} />
3334
</FormSelectBody>
3435
);
@@ -37,9 +38,9 @@ export default function FormSelect<T>({ onChange, style, ...restProps }: FormSel
3738
/**
3839
* Similar to {@link FormSelect}, but the top-level elements are actually groups.
3940
*/
40-
export function FormSelectWithGroups<T>({ values, keyProperty, titleProperty, currentValue, onChange }: FormSelectProps<T, FormSelectGroup<T>>) {
41+
export function FormSelectWithGroups<T>({ id, values, keyProperty, titleProperty, currentValue, onChange }: FormSelectProps<T, FormSelectGroup<T>>) {
4142
return (
42-
<FormSelectBody onChange={onChange}>
43+
<FormSelectBody id={id} onChange={onChange}>
4344
{values.map(({ title, items }) => {
4445
return (
4546
<optgroup label={title}>
@@ -51,9 +52,10 @@ export function FormSelectWithGroups<T>({ values, keyProperty, titleProperty, cu
5152
)
5253
}
5354

54-
function FormSelectBody({ children, onChange, style }: { children: ComponentChildren, onChange: OnChangeListener, style?: CSSProperties }) {
55+
function FormSelectBody({ id, children, onChange, style }: { id?: string, children: ComponentChildren, onChange: OnChangeListener, style?: CSSProperties }) {
5556
return (
5657
<select
58+
id={id}
5759
class="form-select"
5860
onChange={e => onChange((e.target as HTMLInputElement).value)}
5961
style={style}

apps/client/src/widgets/react/FormTextArea.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
interface FormTextAreaProps {
2+
id?: string;
23
currentValue: string;
34
onBlur?(newValue: string): void;
45
rows: number;
56
}
6-
export default function FormTextArea({ onBlur, rows, currentValue }: FormTextAreaProps) {
7+
export default function FormTextArea({ id, onBlur, rows, currentValue }: FormTextAreaProps) {
78
return (
89
<textarea
10+
id={id}
911
rows={rows}
1012
onBlur={(e) => {
1113
onBlur?.(e.currentTarget.value);

apps/client/src/widgets/react/hooks.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,5 +191,5 @@ export function useTriliumOptions<T extends OptionNames>(...names: T[]) {
191191
* @returns a name with the given prefix and a random alpanumeric string appended to it.
192192
*/
193193
export function useUniqueName(prefix: string) {
194-
return useMemo(() => prefix + utils.randomString(10), [ prefix]);
194+
return useMemo(() => prefix + "-" + utils.randomString(10), [ prefix]);
195195
}
Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
1-
import { ComponentChildren } from "preact";
1+
import { cloneElement, VNode } from "preact";
22
import "./OptionsRow.css";
3+
import { useUniqueName } from "../../../react/hooks";
34

45
interface OptionsRowProps {
6+
name: string;
57
label?: string;
6-
children: ComponentChildren;
8+
children: VNode;
79
centered?: boolean;
810
}
911

10-
export default function OptionsRow({ label, children, centered }: OptionsRowProps) {
12+
export default function OptionsRow({ name, label, children, centered }: OptionsRowProps) {
13+
const id = useUniqueName(name);
14+
const childWithId = cloneElement(children, { id });
15+
1116
return (
1217
<div className={`option-row ${centered ? "centered" : ""}`}>
13-
{label && <label>{label}</label>}
14-
{children}
18+
{label && <label for={id}>{label}</label>}
19+
{childWithId}
1520
</div>
1621
);
1722
}

apps/client/src/widgets/type_widgets/options/i18n.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,9 @@ function LocalizationOptions() {
4949
)
5050
}
5151

52-
function LocaleSelector({ locales, currentValue, onChange }: { locales: Locale[], currentValue: string, onChange: (newLocale: string) => void }) {
52+
function LocaleSelector({ id, locales, currentValue, onChange }: { id?: string; locales: Locale[], currentValue: string, onChange: (newLocale: string) => void }) {
5353
return <FormSelect
54+
id={id}
5455
values={locales}
5556
keyProperty="id" titleProperty="name"
5657
currentValue={currentValue} onChange={onChange}

0 commit comments

Comments
 (0)