Skip to content

Commit e5c7f0c

Browse files
rtrbtphotron
authored andcommitted
web: Don't use useId for now.
Preact's useId does not work with multiple roots: preactjs/preact#3781 Once the port to preact is complete, we can switch back to Preact's useId.
1 parent 04711f6 commit e5c7f0c

14 files changed

+53
-26
lines changed

software/web/src/ts/components/input_date.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
import { h, Context, Fragment, ComponentChildren } from "preact";
21-
import { useContext, useId, useRef } from "preact/hooks";
21+
import { useContext, useRef, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323
import { Button } from "react-bootstrap";
2424
import { ArrowLeft, ArrowRight } from "react-feather";
@@ -36,7 +36,7 @@ interface InputDateProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputElemen
3636

3737
export function InputDate(props: InputDateProps) {
3838
const input = useRef<HTMLInputElement>();
39-
const id = !props.idContext ? useId() : useContext(props.idContext);
39+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
4040

4141
const dateToValue = (date: Date) => {
4242
try {

software/web/src/ts/components/input_file.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import * as util from "../../ts/util";
2121

2222
import { h, Context, Fragment } from "preact";
23-
import { useContext, useId, useState } from "preact/hooks";
23+
import { useContext, useState } from "preact/hooks";
2424
import { JSXInternal } from "preact/src/jsx";
2525
import { Button } from "react-bootstrap";
2626
import { __ } from "../../ts/translation";
@@ -46,7 +46,7 @@ export function InputFile(props: InputFileProps) {
4646

4747
const percent = (progress * 100).toFixed(0);
4848

49-
const id = !props.idContext ? useId() : useContext(props.idContext);
49+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
5050

5151
const upload = async () => {
5252
if(props.onUploadStart && !await props.onUploadStart(file))

software/web/src/ts/components/input_float.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import * as util from "../util";
2121

2222
import { h, Context, Fragment } from "preact";
23-
import { useContext, useId, useRef, useState } from "preact/hooks";
23+
import { useContext, useRef, useState } from "preact/hooks";
2424
import { Button, ButtonGroup } from "react-bootstrap";
2525
import { Minus, Plus } from "react-feather";
2626

@@ -40,7 +40,7 @@ interface InputFloatProps extends InputFloatReadonlyProps {
4040
}
4141

4242
export function InputFloat(props: InputFloatProps | InputFloatReadonlyProps) {
43-
const id = !props.idContext ? useId() : useContext(props.idContext);
43+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
4444

4545
let pow10 = Math.pow(10, props.digits);
4646

software/web/src/ts/components/input_indicator.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
*/
1919

2020
import { h, Context } from "preact";
21-
import { useContext, useId } from "preact/hooks";
21+
import { useContext, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323
import { Button } from "react-bootstrap";
2424

25+
import * as util from "../../ts/util";
26+
2527
type variant = "primary" | "secondary" | "success" | "warning" | "danger" | "light" | "link"
2628

2729
interface InputIndicatorProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputElement>, "class" | "id" | "type" | "onInput"> {
@@ -36,7 +38,7 @@ interface InputIndicatorProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputE
3638
}
3739

3840
export function InputIndicator(props: InputIndicatorProps) {
39-
const id = !props.idContext ? useId() : useContext(props.idContext);
41+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
4042

4143
let inner = (
4244
<input class={`form-control input-indicator input-indicator-${props.variant}`}

software/web/src/ts/components/input_ip.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
*/
1919

2020
import { h, Context, Fragment, ComponentChildren } from "preact";
21-
import { useContext, useId } from "preact/hooks";
21+
import { useContext, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323

24+
import * as util from "../../ts/util";
25+
2426
interface InputIPProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputElement>, "class" | "id" | "type" | "minLength" | "maxLength" | "size" | "pattern" | "onInput"> {
2527
idContext?: Context<string>
2628
onValue: (value: string) => void
@@ -29,7 +31,7 @@ interface InputIPProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputElement>
2931
}
3032

3133
export function InputIP(props: InputIPProps) {
32-
const id = !props.idContext ? useId() : useContext(props.idContext);
34+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
3335
return (<>
3436
<input class={"form-control" + (props.moreClasses? " " + props.moreClasses.join(" ") : "")}
3537
id={id}

software/web/src/ts/components/input_month.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
import { h, Context, ComponentChildren, Fragment } from "preact";
21-
import { useContext, useId, useRef } from "preact/hooks";
21+
import { useContext, useRef, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323
import { Button } from "react-bootstrap";
2424
import { ArrowLeft, ArrowRight } from "react-feather";
@@ -38,7 +38,7 @@ interface InputMonthProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputEleme
3838
// but the arrow buttons work as expected, so this is still usable
3939
export function InputMonth(props: InputMonthProps) {
4040
const input = useRef<HTMLInputElement>();
41-
const id = !props.idContext ? useId() : useContext(props.idContext);
41+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
4242

4343
const dateToValue = (date: Date) => {
4444
try {

software/web/src/ts/components/input_number.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
import { h, Context, Fragment } from "preact";
21-
import { useContext, useId, useRef } from "preact/hooks";
21+
import { useContext, useRef, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323
import { Button } from "react-bootstrap";
2424
import { Minus, Plus } from "react-feather";
@@ -33,7 +33,7 @@ interface InputNumberProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputElem
3333
}
3434

3535
export function InputNumber(props: InputNumberProps) {
36-
const id = !props.idContext ? useId() : useContext(props.idContext);
36+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
3737

3838
const input = useRef<HTMLInputElement>();
3939

software/web/src/ts/components/input_password.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,14 @@
1818
*/
1919

2020
import { h, Component, Context, Fragment } from "preact";
21-
import { useContext, useId } from "preact/hooks";
21+
import { useContext, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323
import { Button } from "react-bootstrap";
2424
import { Eye, EyeOff, Trash2 } from "react-feather";
2525
import { __ } from "../translation";
2626

27+
import * as util from "../../ts/util";
28+
2729
interface InputPasswordProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputElement>, "class" | "id" | "type" | "onInput" | "value" | "disabled"> {
2830
idContext?: Context<string>
2931
value: string | null
@@ -60,7 +62,7 @@ export class InputPassword extends Component<InputPasswordProps, InputPasswordSt
6062
}
6163

6264
render(props: InputPasswordProps, state: Readonly<InputPasswordState>) {
63-
const id = !props.idContext ? useId() : useContext(props.idContext);
65+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
6466

6567
let invalidFeedback = undefined;
6668
if ("invalidFeedback" in props)

software/web/src/ts/components/input_select.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
*/
1919

2020
import { h, Context } from "preact";
21-
import { useContext, useId } from "preact/hooks";
21+
import { useContext, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323

24+
import * as util from "../../ts/util";
25+
2426
export interface InputSelectProps extends Omit<JSXInternal.HTMLAttributes<HTMLSelectElement>, "id" | "type" | "onInput"> {
2527
idContext?: Context<string>
2628
items: [string, string][];
@@ -33,7 +35,7 @@ export interface InputSelectProps extends Omit<JSXInternal.HTMLAttributes<HTMLSe
3335
export function InputSelect(props: InputSelectProps) {
3436
let {idContext, items, value, onValue, placeholder, classList, style, ...p} = props;
3537

36-
const id = !idContext ? useId() : useContext(idContext);
38+
const id = !idContext ? util.useId() : useContext(idContext);
3739

3840
if (placeholder) {
3941
let found = false;

software/web/src/ts/components/input_text.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
*/
1919

2020
import { h, Context, Fragment, ComponentChildren } from "preact";
21-
import { useContext, useId } from "preact/hooks";
21+
import { useContext, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323
import { __ } from "../translation";
2424

@@ -42,7 +42,7 @@ interface InputTextWithValidationProps extends Omit<JSXInternal.HTMLAttributes<H
4242
}
4343

4444
export function InputText<T extends (InputTextProps | InputTextWithValidationProps)>(props: util.NoExtraProperties<InputTextProps, T> | InputTextWithValidationProps) {
45-
const id = !props.idContext ? useId() : useContext(props.idContext);
45+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
4646

4747
let invalidFeedback = undefined;
4848
if ("invalidFeedback" in props && props.invalidFeedback)

software/web/src/ts/components/output_datetime.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,11 @@
1818
*/
1919

2020
import { h, Context } from "preact";
21-
import { useContext, useId } from "preact/hooks";
21+
import { useContext, useState } from "preact/hooks";
2222
import { JSXInternal } from "preact/src/jsx";
2323

24+
import * as util from "../../ts/util";
25+
2426
interface OutputDatetimeProps extends Omit<JSXInternal.HTMLAttributes<HTMLInputElement>, "value" | "class" | "id" | "type" | "onInput" | "disabled"> {
2527
idContext?: Context<string>
2628
date: Date
@@ -43,7 +45,7 @@ function toIsoString(date: Date) {
4345
}
4446

4547
export function OutputDatetime(props: OutputDatetimeProps) {
46-
const id = !props.idContext ? useId() : useContext(props.idContext);
48+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
4749

4850
let inner = <input class={"form-control " + props.className}
4951
id={id}

software/web/src/ts/components/output_float.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
import * as util from "../util";
2121

2222
import { h, Context } from "preact";
23-
import { useContext, useId } from "preact/hooks";
23+
import { useContext, useState } from "preact/hooks";
2424

2525
interface OutputFloatProps {
2626
idContext?: Context<string>
@@ -34,7 +34,7 @@ interface OutputFloatProps {
3434
}
3535

3636
export function OutputFloat(props: OutputFloatProps) {
37-
const id = !props.idContext ? useId() : useContext(props.idContext);
37+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
3838
let pow10 = Math.pow(10, props.scale);
3939

4040
let val = util.toLocaleFixed(props.value / pow10, props.digits);

software/web/src/ts/components/switch.tsx

+4-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
*/
1919

2020
import { h, JSX, Context, ComponentChildren } from "preact";
21-
import { useContext, useId } from "preact/hooks";
21+
import { useContext, useState } from "preact/hooks";
22+
23+
import * as util from "../../ts/util";
2224

2325
export interface SwitchProps {
2426
idContext?: Context<string>
@@ -30,7 +32,7 @@ export interface SwitchProps {
3032
}
3133

3234
export function Switch(props: SwitchProps) {
33-
const id = !props.idContext ? useId() : useContext(props.idContext);
35+
const id = !props.idContext ? util.useId() : useContext(props.idContext);
3436

3537
let inner = <div class={"borderless-form-control custom-control custom-switch "}>
3638
<input type="checkbox" class="custom-control-input" id={id} checked={props.checked} onClick={props.onClick} disabled={props.disabled}/>

software/web/src/ts/util.ts

+15
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { __ } from "./translation";
2626
import { AsyncModal } from "./components/async_modal";
2727
import { api_cache } from "./api_defs";
2828
import { batch, signal, Signal } from "@preact/signals-core";
29+
import { useState } from "preact/hooks";
2930

3031
export function reboot() {
3132
API.call("reboot", null, "").then(() => postReboot(__("util.reboot_title"), __("util.reboot_text")));
@@ -624,3 +625,17 @@ export function compareArrays(a: Array<any>, b: Array<any>): boolean
624625
{
625626
return a.length === b.length && a.every((element, index) => element === b[index]);
626627
}
628+
629+
// https://stackoverflow.com/a/1535650
630+
export let nextId = (function() {
631+
var id = 0;
632+
return function() {return "ID-" + (++id).toString();};
633+
})();
634+
635+
// Preact's useId does not work with multiple roots:
636+
// https://github.com/preactjs/preact/issues/3781
637+
// Once the port to preact is complete,
638+
// we can switch back to Preact's useId.
639+
export function useId() {
640+
return useState(nextId())[0];
641+
}

0 commit comments

Comments
 (0)