From 63e0be09e625e2e5e02a5f153fe87608f6093447 Mon Sep 17 00:00:00 2001 From: andres Date: Sun, 19 May 2024 14:53:00 +0200 Subject: [PATCH] chore: upgrade to react 19 beta and next 14 canary --- .eslintrc.json | 3 +- app/converters/json-yaml/layout.tsx | 3 +- app/converters/json-yaml/page.tsx | 20 +- app/converters/layout.tsx | 3 +- app/converters/number-base/layout.tsx | 3 +- app/converters/number-base/page.tsx | 10 +- app/encoders-decoders/base64/layout.tsx | 3 +- app/encoders-decoders/base64/page.tsx | 14 +- app/encoders-decoders/html/layout.tsx | 3 +- app/encoders-decoders/html/page.tsx | 14 +- app/encoders-decoders/jwt/layout.tsx | 3 +- app/encoders-decoders/jwt/page.tsx | 6 +- app/encoders-decoders/layout.tsx | 3 +- app/encoders-decoders/url/layout.tsx | 3 +- app/encoders-decoders/url/page.tsx | 14 +- app/formatters/json/layout.tsx | 3 +- app/formatters/json/page.tsx | 34 +- app/formatters/layout.tsx | 3 +- app/generators/hash/layout.tsx | 3 +- app/generators/hash/page.tsx | 4 +- app/generators/layout.tsx | 3 +- app/generators/uuid/layout.tsx | 3 +- app/generators/uuid/page.tsx | 14 +- app/layout.tsx | 30 +- app/search/layout.tsx | 3 +- app/settings/layout.tsx | 3 +- app/text/diff/page.tsx | 112 +- app/text/inspector/layout.tsx | 3 +- app/text/inspector/page.tsx | 19 +- app/text/layout.tsx | 3 +- components/buttons/clear.tsx | 7 +- components/buttons/copy.tsx | 11 +- components/buttons/file.tsx | 58 +- components/buttons/paste.tsx | 11 +- components/buttons/toggle-full-size.tsx | 7 +- components/client-layout.tsx | 10 +- components/configuration.tsx | 7 +- components/configurations.tsx | 7 +- components/control-menu.tsx | 7 +- components/icons.tsx | 76 +- components/indicator.tsx | 6 +- components/panel-resize-handler.tsx | 24 +- components/sidebar/tool-group.tsx | 8 +- components/sidebar/tool-link.tsx | 6 +- components/site-header.tsx | 16 +- components/tailwind-indicator.tsx | 2 +- components/theme-toggle.tsx | 4 +- components/tool-card.tsx | 1 + components/ui/button.tsx | 17 +- components/ui/diff-editor.tsx | 49 +- components/ui/editor.tsx | 51 +- components/ui/input.tsx | 39 +- components/ui/label.tsx | 11 +- components/ui/providers.tsx | 23 + components/ui/select.tsx | 78 +- components/ui/separator.tsx | 17 +- components/ui/switch.tsx | 52 +- components/ui/textarea.tsx | 37 +- components/ui/toggle-group.tsx | 29 +- components/ui/tooltip.tsx | 16 +- contexts/sidebar.tsx | 35 - hooks/use-sidebar.tsx | 57 + next.config.mjs | 2 + package.json | 62 +- pnpm-lock.yaml | 3336 ++++++++++++++--------- 65 files changed, 2626 insertions(+), 1898 deletions(-) create mode 100644 components/ui/providers.tsx delete mode 100644 contexts/sidebar.tsx create mode 100644 hooks/use-sidebar.tsx diff --git a/.eslintrc.json b/.eslintrc.json index 323ddb3..78749f7 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -11,8 +11,9 @@ "next/core-web-vitals", "prettier" ], - "plugins": ["tailwindcss"], + "plugins": ["tailwindcss", "eslint-plugin-react-compiler"], "rules": { + "react-compiler/react-compiler": "error", "@next/next/no-html-link-for-pages": "off", "@typescript-eslint/explicit-module-boundary-types": "off", "@typescript-eslint/no-unused-vars": [ diff --git a/app/converters/json-yaml/layout.tsx b/app/converters/json-yaml/layout.tsx index c0c0286..93444e9 100644 --- a/app/converters/json-yaml/layout.tsx +++ b/app/converters/json-yaml/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/converters/json-yaml/page.tsx b/app/converters/json-yaml/page.tsx index f49241a..6487927 100644 --- a/app/converters/json-yaml/page.tsx +++ b/app/converters/json-yaml/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import yaml from "js-yaml"; import { toolGroups } from "@/config/tools"; @@ -28,7 +28,7 @@ export default function Page() { yaml: "foo: bar", }); - const setFormByJson = useCallback((text: string) => { + const setFormByJson = (text: string) => { setForm(prev => ({ ...prev, json: text, @@ -36,9 +36,9 @@ export default function Page() { .map(x => yaml.dump(x, { indent: prev.indentation.length, quotingType: '"' })) .unwrapOr(""), })); - }, []); + }; - const setFormByYaml = useCallback((text: string) => { + const setFormByYaml = (text: string) => { setForm(prev => ({ ...prev, json: safeYamlParse(text) @@ -46,15 +46,15 @@ export default function Page() { .unwrapOr(""), yaml: text, })); - }, []); + }; - const clearBoth = useCallback(() => { + const clearBoth = () => { setForm(prev => ({ ...prev, json: "", yaml: "", })); - }, []); + }; const onIndentationChange: Select.Props["onValueChange"] = value => { const jsonYaml = safeJsonParse(form.json) @@ -73,7 +73,11 @@ export default function Page() { }); }; + // @ts-expect-error react 19 beta error + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const onJsonChange: EditorProps["onChange"] = value => setFormByJson(value ?? ""); + // @ts-expect-error react 19 beta error + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const onYamlChange: EditorProps["onChange"] = value => setFormByYaml(value ?? ""); const indentationConfig = ( @@ -133,9 +137,11 @@ export default function Page() {
+ {/* @ts-expect-error react 19 beta error */} + {/* @ts-expect-error react 19 beta error */}
diff --git a/app/converters/layout.tsx b/app/converters/layout.tsx index d017263..9b815cc 100644 --- a/app/converters/layout.tsx +++ b/app/converters/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -11,6 +12,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/converters/number-base/layout.tsx b/app/converters/number-base/layout.tsx index df0f214..ba7128f 100644 --- a/app/converters/number-base/layout.tsx +++ b/app/converters/number-base/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/converters/number-base/page.tsx b/app/converters/number-base/page.tsx index de0454a..023e3cc 100644 --- a/app/converters/number-base/page.tsx +++ b/app/converters/number-base/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { toolGroups } from "@/config/tools"; import * as baselib from "@/lib/base"; @@ -48,10 +48,10 @@ export default function Page() { } }; - const trySetDec = useCallback((value: string) => trySetInt(10)(value), []); - const trySetHex = useCallback((value: string) => trySetInt(16)(value), []); - const trySetOct = useCallback((value: string) => trySetInt(8)(value), []); - const trySetBin = useCallback((value: string) => trySetInt(2)(value), []); + const trySetDec = (value: string) => trySetInt(10)(value); + const trySetHex = (value: string) => trySetInt(16)(value); + const trySetOct = (value: string) => trySetInt(8)(value); + const trySetBin = (value: string) => trySetInt(2)(value); const onDecChange: InputProps["onChange"] = e => trySetDec(e.currentTarget.value); const onHexChange: InputProps["onChange"] = e => trySetHex(e.currentTarget.value); diff --git a/app/encoders-decoders/base64/layout.tsx b/app/encoders-decoders/base64/layout.tsx index 709b7a3..927a5e4 100644 --- a/app/encoders-decoders/base64/layout.tsx +++ b/app/encoders-decoders/base64/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/encoders-decoders/base64/page.tsx b/app/encoders-decoders/base64/page.tsx index 881fe15..d6ea200 100644 --- a/app/encoders-decoders/base64/page.tsx +++ b/app/encoders-decoders/base64/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { decode, encode, isValid } from "js-base64"; import { toolGroups } from "@/config/tools"; @@ -16,28 +16,28 @@ export default function Page() { encoded: "8J+YgPCfmILwn6Sj", }); - const setFormByDecoded = useCallback((text: string) => { + const setFormByDecoded = (text: string) => { setForm({ decoded: text, encoded: encode(text), }); - }, []); + }; - const setFormByEncoded = useCallback((text: string) => { + const setFormByEncoded = (text: string) => { const newDecoded = decode(text); setForm({ decoded: isValid(text) && !newDecoded.includes("�") ? newDecoded : "", encoded: text, }); - }, []); + }; - const clearBoth = useCallback(() => { + const clearBoth = () => { setForm({ decoded: "", encoded: "", }); - }, []); + }; const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value); const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value); diff --git a/app/encoders-decoders/html/layout.tsx b/app/encoders-decoders/html/layout.tsx index be07253..513c70a 100644 --- a/app/encoders-decoders/html/layout.tsx +++ b/app/encoders-decoders/html/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/encoders-decoders/html/page.tsx b/app/encoders-decoders/html/page.tsx index c8cc22d..cce9833 100644 --- a/app/encoders-decoders/html/page.tsx +++ b/app/encoders-decoders/html/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { escape, unescape } from "html-escaper"; import { toolGroups } from "@/config/tools"; @@ -16,26 +16,26 @@ export default function Page() { encoded: "> It's "HTML escaping".", }); - const setFormByDecoded = useCallback((text: string) => { + const setFormByDecoded = (text: string) => { setForm({ decoded: text, encoded: escape(text), }); - }, []); + }; - const setFormByEncoded = useCallback((text: string) => { + const setFormByEncoded = (text: string) => { setForm({ decoded: unescape(text), encoded: text, }); - }, []); + }; - const clearBoth = useCallback(() => { + const clearBoth = () => { setForm({ decoded: "", encoded: "", }); - }, []); + }; const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value); const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value); diff --git a/app/encoders-decoders/jwt/layout.tsx b/app/encoders-decoders/jwt/layout.tsx index 22e857c..e229c4d 100644 --- a/app/encoders-decoders/jwt/layout.tsx +++ b/app/encoders-decoders/jwt/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/encoders-decoders/jwt/page.tsx b/app/encoders-decoders/jwt/page.tsx index 1532e5d..a6cefd3 100644 --- a/app/encoders-decoders/jwt/page.tsx +++ b/app/encoders-decoders/jwt/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { toolGroups } from "@/config/tools"; import { decode } from "@/lib/jwt"; @@ -20,7 +20,7 @@ export default function Page() { const header = h.map(x => JSON.stringify(x, null, 2)).unwrapOr(""); const payload = p.map(x => JSON.stringify(x, null, 2)).unwrapOr(""); - const clearJwt = useCallback(() => setJwt(""), []); + const clearJwt = () => setJwt(""); const onJwtChange: TextareaProps["onChange"] = e => setJwt(e.currentTarget.value); @@ -49,9 +49,11 @@ export default function Page() {
+ {/* @ts-expect-error react 19 beta error */} + {/* @ts-expect-error react 19 beta error */}
diff --git a/app/encoders-decoders/layout.tsx b/app/encoders-decoders/layout.tsx index f6b94d3..e3eb583 100644 --- a/app/encoders-decoders/layout.tsx +++ b/app/encoders-decoders/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -11,6 +12,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/encoders-decoders/url/layout.tsx b/app/encoders-decoders/url/layout.tsx index c553b9a..a43e0fe 100644 --- a/app/encoders-decoders/url/layout.tsx +++ b/app/encoders-decoders/url/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/encoders-decoders/url/page.tsx b/app/encoders-decoders/url/page.tsx index 6d826fb..ce74616 100644 --- a/app/encoders-decoders/url/page.tsx +++ b/app/encoders-decoders/url/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { toolGroups } from "@/config/tools"; import { safeDecodeURIComponent, safeEncodeURIComponent } from "@/lib/uri"; @@ -16,26 +16,26 @@ export default function Page() { encoded: "%3E%20It's%20%22URL%20encoding%22%3F", }); - const setFormByDecoded = useCallback((text: string) => { + const setFormByDecoded = (text: string) => { setForm({ decoded: text, encoded: safeEncodeURIComponent(text).unwrapOr(""), }); - }, []); + }; - const setFormByEncoded = useCallback((text: string) => { + const setFormByEncoded = (text: string) => { setForm({ decoded: safeDecodeURIComponent(text).unwrapOr(""), encoded: text, }); - }, []); + }; - const clearBoth = useCallback(() => { + const clearBoth = () => { setForm({ decoded: "", encoded: "", }); - }, []); + }; const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value); const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value); diff --git a/app/formatters/json/layout.tsx b/app/formatters/json/layout.tsx index 7822d01..f505994 100644 --- a/app/formatters/json/layout.tsx +++ b/app/formatters/json/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/formatters/json/page.tsx b/app/formatters/json/page.tsx index 3472ce5..bf7c158 100644 --- a/app/formatters/json/page.tsx +++ b/app/formatters/json/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { toolGroups } from "@/config/tools"; import { safeJsonParse } from "@/lib/json"; @@ -21,15 +21,26 @@ const indentations = { tab: "\t", }; +const INDENTATION = { + TWO_SPACES: "two", + FOUR_SPACES: "four", + TAB: "tab", + ZERO: "zero", +} as const; + +type Indentation = (typeof INDENTATION)[keyof typeof INDENTATION]; + export default function Page() { - const [indentation, setIndentation] = useState(indentations.two); + const [indentation, setIndentation] = useState(INDENTATION.TWO_SPACES); const [input, setInput] = useState('{\n"foo":"bar"\n}'); const parsed = safeJsonParse(input); - const output = parsed.map(x => JSON.stringify(x, null, indentation)).unwrapOr(""); + const output = parsed.map(x => JSON.stringify(x, null, indentations[indentation])).unwrapOr(""); - const clearInput = useCallback(() => setInput(""), []); + const clearInput = () => setInput(""); + // @ts-expect-error react 19 beta error + // eslint-disable-next-line @typescript-eslint/no-unsafe-argument const onJsonChange: EditorProps["onChange"] = value => setInput(value ?? ""); const indentationConfig = ( @@ -37,7 +48,10 @@ export default function Page() { icon={} title="Indentation" control={ - + setIndentation(value as Indentation)} + > - 2 spaces - 4 spaces - 1 tab - minified + 2 spaces + 4 spaces + 1 tab + minified } @@ -75,9 +89,11 @@ export default function Page() {
+ {/* @ts-expect-error react 19 beta error */} + {/* @ts-expect-error react 19 beta error */}
diff --git a/app/formatters/layout.tsx b/app/formatters/layout.tsx index 5907c46..775d815 100644 --- a/app/formatters/layout.tsx +++ b/app/formatters/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -11,6 +12,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/generators/hash/layout.tsx b/app/generators/hash/layout.tsx index 54d37df..a51d6a3 100644 --- a/app/generators/hash/layout.tsx +++ b/app/generators/hash/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/generators/hash/page.tsx b/app/generators/hash/page.tsx index 40cdebd..5ec749e 100644 --- a/app/generators/hash/page.tsx +++ b/app/generators/hash/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import createHash from "create-hash"; import { toolGroups } from "@/config/tools"; @@ -29,7 +29,7 @@ export default function Page() { const sha256 = uppercase ? newSha256.toUpperCase() : newSha256; const sha512 = uppercase ? newSha512.toUpperCase() : newSha512; - const clearInput = useCallback(() => setInput(""), []); + const clearInput = () => setInput(""); const onInputChange: TextareaProps["onChange"] = e => setInput(e.currentTarget.value); diff --git a/app/generators/layout.tsx b/app/generators/layout.tsx index c384483..926e07e 100644 --- a/app/generators/layout.tsx +++ b/app/generators/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -11,6 +12,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/generators/uuid/layout.tsx b/app/generators/uuid/layout.tsx index 73f0ef0..a74d137 100644 --- a/app/generators/uuid/layout.tsx +++ b/app/generators/uuid/layout.tsx @@ -1,3 +1,4 @@ +import { PropsWithChildren } from "react"; import { Metadata } from "next"; import { toolGroups } from "@/config/tools"; @@ -12,6 +13,6 @@ export const metadata: Metadata = { }, }; -export default function Layout({ children }: { children: React.ReactNode }) { +export default function Layout({ children }: PropsWithChildren) { return children; } diff --git a/app/generators/uuid/page.tsx b/app/generators/uuid/page.tsx index ccdfd99..a612858 100644 --- a/app/generators/uuid/page.tsx +++ b/app/generators/uuid/page.tsx @@ -1,6 +1,6 @@ "use client"; -import { useCallback, useState } from "react"; +import { useState } from "react"; import { range } from "fp-ts/NonEmptyArray"; import { toolGroups } from "@/config/tools"; @@ -41,21 +41,21 @@ export default function Page() { const uuidsString = uuids.join("\n"); - const clearUuids = useCallback(() => setUuids([]), []); + const clearUuids = () => setUuids([]); - const onUuidVersionChange: NonNullable = useCallback(value => { + const onUuidVersionChange: NonNullable = value => { if (isUuidVersion(value)) { setUuidVersion(value); } - }, []); + }; - const onGeneratesChange: NonNullable = useCallback(e => { + const onGeneratesChange: NonNullable = e => { const newGenerates = Number(e.currentTarget.value); if (newGenerates >= 1 && newGenerates <= 1000) { setGenerates(newGenerates); } - }, []); + }; const onGenerateClick = () => { const newUuids = range(1, generates).map(_ => uuid(uuidVersion, hyphens, uppercase)); @@ -136,7 +136,7 @@ export default function Page() { -