mirror of
https://github.com/ershisan99/DevToysWeb.git
synced 2025-12-16 12:32:48 +00:00
refactor: rename, reorder, etc.
This commit is contained in:
@@ -7,18 +7,8 @@ import { toolGroups } from "@/config/tools";
|
||||
import { safeJsonParse } from "@/lib/json";
|
||||
import { safeYamlParse } from "@/lib/yaml";
|
||||
import { Editor, EditorProps } from "@/components/ui/editor";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectProps,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { FileButton } from "@/components/buttons/file";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Select from "@/components/ui/select";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { Configuration } from "@/components/configuration";
|
||||
import { Configurations } from "@/components/configurations";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
@@ -38,41 +28,44 @@ export default function Page() {
|
||||
yaml: "foo: bar",
|
||||
});
|
||||
|
||||
const setJsonReactively = useCallback((text: string) => {
|
||||
const parsed = safeJsonParse(text);
|
||||
|
||||
const setFormByJson = useCallback((text: string) => {
|
||||
setForm(prev => ({
|
||||
...prev,
|
||||
json: text,
|
||||
yaml: parsed.isErr()
|
||||
? ""
|
||||
: yaml.dump(parsed.value, { indent: prev.indentation.length, quotingType: '"' }),
|
||||
yaml: safeJsonParse(text)
|
||||
.map(x => yaml.dump(x, { indent: prev.indentation.length, quotingType: '"' }))
|
||||
.unwrapOr(""),
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const setYamlReactively = useCallback((text: string) => {
|
||||
const parsed = safeYamlParse(text);
|
||||
|
||||
const setFormByYaml = useCallback((text: string) => {
|
||||
setForm(prev => ({
|
||||
...prev,
|
||||
json: safeYamlParse(text)
|
||||
.map(x => JSON.stringify(x, null, prev.indentation))
|
||||
.unwrapOr(""),
|
||||
yaml: text,
|
||||
json: parsed.isErr() ? "" : JSON.stringify(parsed.value, null, prev.indentation),
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const clearBoth = useCallback(() => {
|
||||
setForm(prev => ({ ...prev, json: "", yaml: "" }));
|
||||
setForm(prev => ({
|
||||
...prev,
|
||||
json: "",
|
||||
yaml: "",
|
||||
}));
|
||||
}, []);
|
||||
|
||||
const onIndentationChange: SelectProps["onValueChange"] = value => {
|
||||
const parsed = safeJsonParse(form.json);
|
||||
|
||||
const jsonYaml = parsed.isErr()
|
||||
? { json: "", yaml: "" }
|
||||
: {
|
||||
json: JSON.stringify(parsed.value, null, value),
|
||||
yaml: yaml.dump(parsed.value, { indent: value.length, quotingType: '"' }),
|
||||
};
|
||||
const onIndentationChange: Select.Props["onValueChange"] = value => {
|
||||
const jsonYaml = safeJsonParse(form.json)
|
||||
.map(x => ({
|
||||
json: JSON.stringify(x, null, value),
|
||||
yaml: yaml.dump(x, { indent: value.length, quotingType: '"' }),
|
||||
}))
|
||||
.unwrapOr({
|
||||
json: "",
|
||||
yaml: "",
|
||||
});
|
||||
|
||||
setForm({
|
||||
indentation: value,
|
||||
@@ -80,59 +73,55 @@ export default function Page() {
|
||||
});
|
||||
};
|
||||
|
||||
const onJsonChange: EditorProps["onChange"] = value => setJsonReactively(value ?? "");
|
||||
const onYamlChange: EditorProps["onChange"] = value => setYamlReactively(value ?? "");
|
||||
const onJsonChange: EditorProps["onChange"] = value => setFormByJson(value ?? "");
|
||||
const onYamlChange: EditorProps["onChange"] = value => setFormByYaml(value ?? "");
|
||||
|
||||
const indentationConfig = (
|
||||
<Configuration
|
||||
icon={<icons.Space size={24} className="-translate-y-1.5" />}
|
||||
title="Indentation"
|
||||
control={
|
||||
<Select value={form.indentation} onValueChange={onIndentationChange}>
|
||||
<SelectTrigger
|
||||
<Select.Root value={form.indentation} onValueChange={onIndentationChange}>
|
||||
<Select.Trigger
|
||||
className="w-28"
|
||||
aria-label="toggle open/close state of indentation selection"
|
||||
>
|
||||
<SelectValue placeholder={form.indentation} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={indentations.two}>2 spaces</SelectItem>
|
||||
<SelectItem value={indentations.four}>4 spaces</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select.Value placeholder={form.indentation} />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value={indentations.two}>2 spaces</Select.Item>
|
||||
<Select.Item value={indentations.four}>4 spaces</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
const jsonPasteButton = <PasteButton onClipboardRead={setJsonReactively} />;
|
||||
const yamlPasteButton = <PasteButton onClipboardRead={setYamlReactively} />;
|
||||
const jsonPasteButton = <Button.Paste onClipboardRead={setFormByJson} />;
|
||||
const yamlPasteButton = <Button.Paste onClipboardRead={setFormByYaml} />;
|
||||
|
||||
const jsonFileButton = (
|
||||
<FileButton
|
||||
accept=".json"
|
||||
onFileRead={setJsonReactively}
|
||||
iconOnly
|
||||
aria-label="load a json file"
|
||||
/>
|
||||
<Button.File accept=".json" onFileRead={setFormByJson} iconOnly aria-label="load a json file" />
|
||||
);
|
||||
const yamlFileButton = (
|
||||
<FileButton
|
||||
<Button.File
|
||||
accept=".yml,.yaml"
|
||||
onFileRead={setYamlReactively}
|
||||
onFileRead={setFormByYaml}
|
||||
iconOnly
|
||||
aria-label="load a yaml file"
|
||||
/>
|
||||
);
|
||||
|
||||
const jsonCopyButton = <CopyButton text={form.json} />;
|
||||
const yamlCopyButton = <CopyButton text={form.yaml} />;
|
||||
const jsonCopyButton = <Button.Copy text={form.json} />;
|
||||
const yamlCopyButton = <Button.Copy text={form.yaml} />;
|
||||
|
||||
const clearButton = <ClearButton onClick={clearBoth} iconOnly aria-label="clear json and yaml" />;
|
||||
const clearButton = (
|
||||
<Button.Clear onClick={clearBoth} iconOnly aria-label="clear json and yaml" />
|
||||
);
|
||||
|
||||
const jsonControl = (
|
||||
<ControlMenu list={[jsonPasteButton, jsonFileButton, jsonCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
const yamlControl = (
|
||||
<ControlMenu list={[yamlPasteButton, yamlFileButton, yamlCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { useCallback, useState } from "react";
|
||||
import { toolGroups } from "@/config/tools";
|
||||
import * as baselib from "@/lib/base";
|
||||
import { Input, InputProps } from "@/components/ui/input";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { Configuration } from "@/components/configuration";
|
||||
import { Configurations } from "@/components/configurations";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
@@ -53,10 +53,10 @@ export default function Page() {
|
||||
const trySetOct = useCallback((value: string) => trySetInt(8)(value), []);
|
||||
const trySetBin = useCallback((value: string) => trySetInt(2)(value), []);
|
||||
|
||||
const onDecChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetDec(value);
|
||||
const onHexChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetHex(value);
|
||||
const onOctChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetOct(value);
|
||||
const onBinChange: InputProps["onChange"] = ({ currentTarget: { value } }) => trySetBin(value);
|
||||
const onDecChange: InputProps["onChange"] = e => trySetDec(e.currentTarget.value);
|
||||
const onHexChange: InputProps["onChange"] = e => trySetHex(e.currentTarget.value);
|
||||
const onOctChange: InputProps["onChange"] = e => trySetOct(e.currentTarget.value);
|
||||
const onBinChange: InputProps["onChange"] = e => trySetBin(e.currentTarget.value);
|
||||
|
||||
const formatNumberConfig = (
|
||||
<Configuration
|
||||
@@ -73,10 +73,10 @@ export default function Page() {
|
||||
}
|
||||
/>
|
||||
);
|
||||
const decPasteButton = <PasteButton onClipboardRead={trySetDec} />;
|
||||
const hexPasteButton = <PasteButton onClipboardRead={trySetHex} />;
|
||||
const octPasteButton = <PasteButton onClipboardRead={trySetOct} />;
|
||||
const binPasteButton = <PasteButton onClipboardRead={trySetBin} />;
|
||||
const decPasteButton = <Button.Paste onClipboardRead={trySetDec} />;
|
||||
const hexPasteButton = <Button.Paste onClipboardRead={trySetHex} />;
|
||||
const octPasteButton = <Button.Paste onClipboardRead={trySetOct} />;
|
||||
const binPasteButton = <Button.Paste onClipboardRead={trySetBin} />;
|
||||
|
||||
const decControl = <ControlMenu list={[decPasteButton]} />;
|
||||
const hexControl = <ControlMenu list={[hexPasteButton]} />;
|
||||
|
||||
@@ -5,10 +5,7 @@ import { decode, encode, isValid } from "js-base64";
|
||||
|
||||
import { toolGroups } from "@/config/tools";
|
||||
import { Textarea, TextareaProps } from "@/components/ui/textarea";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { FileButton } from "@/components/buttons/file";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
import { PageRootSection } from "@/components/page-root-section";
|
||||
import { PageSection } from "@/components/page-section";
|
||||
@@ -19,19 +16,19 @@ export default function Page() {
|
||||
encoded: "8J+YgPCfmILwn6Sj",
|
||||
});
|
||||
|
||||
const setDecodedReactively = useCallback((text: string) => {
|
||||
const setFormByDecoded = useCallback((text: string) => {
|
||||
setForm({
|
||||
decoded: text,
|
||||
encoded: encode(text),
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setEncodedReactively = useCallback((text: string) => {
|
||||
const setFormByEncoded = useCallback((text: string) => {
|
||||
const newDecoded = decode(text);
|
||||
|
||||
setForm({
|
||||
encoded: text,
|
||||
decoded: isValid(text) && !newDecoded.includes("<22>") ? newDecoded : "",
|
||||
encoded: text,
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -42,33 +39,29 @@ export default function Page() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||
setDecodedReactively(value);
|
||||
const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value);
|
||||
const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value);
|
||||
|
||||
const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||
setEncodedReactively(value);
|
||||
|
||||
const decodedPasteButton = <PasteButton onClipboardRead={setDecodedReactively} />;
|
||||
const encodedPasteButton = <PasteButton onClipboardRead={setEncodedReactively} />;
|
||||
const decodedPasteButton = <Button.Paste onClipboardRead={setFormByDecoded} />;
|
||||
const encodedPasteButton = <Button.Paste onClipboardRead={setFormByEncoded} />;
|
||||
|
||||
const decodedFileButton = (
|
||||
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
|
||||
<Button.File onFileRead={setFormByDecoded} iconOnly aria-label="load a decoded file" />
|
||||
);
|
||||
const encodedFileButton = (
|
||||
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
|
||||
<Button.File onFileRead={setFormByEncoded} iconOnly aria-label="load a encoded file" />
|
||||
);
|
||||
|
||||
const decodedCopyButton = <CopyButton text={form.decoded} />;
|
||||
const encodedCopyButton = <CopyButton text={form.encoded} />;
|
||||
const decodedCopyButton = <Button.Copy text={form.decoded} />;
|
||||
const encodedCopyButton = <Button.Copy text={form.encoded} />;
|
||||
|
||||
const clearButton = (
|
||||
<ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
|
||||
<Button.Clear onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
|
||||
);
|
||||
|
||||
const decodedControl = (
|
||||
<ControlMenu list={[decodedPasteButton, decodedFileButton, decodedCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
const encodedControl = (
|
||||
<ControlMenu list={[encodedPasteButton, encodedFileButton, encodedCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
@@ -5,10 +5,7 @@ import { escape, unescape } from "html-escaper";
|
||||
|
||||
import { toolGroups } from "@/config/tools";
|
||||
import { Textarea, TextareaProps } from "@/components/ui/textarea";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { FileButton } from "@/components/buttons/file";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
import { PageRootSection } from "@/components/page-root-section";
|
||||
import { PageSection } from "@/components/page-section";
|
||||
@@ -19,17 +16,17 @@ export default function Page() {
|
||||
encoded: "> It's "HTML escaping".",
|
||||
});
|
||||
|
||||
const setDecodedReactively = useCallback((text: string) => {
|
||||
const setFormByDecoded = useCallback((text: string) => {
|
||||
setForm({
|
||||
decoded: text,
|
||||
encoded: escape(text),
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setEncodedReactively = useCallback((text: string) => {
|
||||
const setFormByEncoded = useCallback((text: string) => {
|
||||
setForm({
|
||||
encoded: text,
|
||||
decoded: unescape(text),
|
||||
encoded: text,
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -40,33 +37,29 @@ export default function Page() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||
setDecodedReactively(value);
|
||||
const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value);
|
||||
const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value);
|
||||
|
||||
const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||
setEncodedReactively(value);
|
||||
|
||||
const decodedPasteButton = <PasteButton onClipboardRead={setDecodedReactively} />;
|
||||
const encodedPasteButton = <PasteButton onClipboardRead={setEncodedReactively} />;
|
||||
const decodedPasteButton = <Button.Paste onClipboardRead={setFormByDecoded} />;
|
||||
const encodedPasteButton = <Button.Paste onClipboardRead={setFormByEncoded} />;
|
||||
|
||||
const decodedFileButton = (
|
||||
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
|
||||
<Button.File onFileRead={setFormByDecoded} iconOnly aria-label="load a decoded file" />
|
||||
);
|
||||
const encodedFileButton = (
|
||||
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
|
||||
<Button.File onFileRead={setFormByEncoded} iconOnly aria-label="load a encoded file" />
|
||||
);
|
||||
|
||||
const decodedCopyButton = <CopyButton text={form.decoded} />;
|
||||
const encodedCopyButton = <CopyButton text={form.encoded} />;
|
||||
const decodedCopyButton = <Button.Copy text={form.decoded} />;
|
||||
const encodedCopyButton = <Button.Copy text={form.encoded} />;
|
||||
|
||||
const clearButton = (
|
||||
<ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
|
||||
<Button.Clear onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
|
||||
);
|
||||
|
||||
const decodedControl = (
|
||||
<ControlMenu list={[decodedPasteButton, decodedFileButton, decodedCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
const encodedControl = (
|
||||
<ControlMenu list={[encodedPasteButton, encodedFileButton, encodedCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
@@ -6,10 +6,7 @@ import { toolGroups } from "@/config/tools";
|
||||
import { decode } from "@/lib/jwt";
|
||||
import { Editor } from "@/components/ui/editor";
|
||||
import { Textarea, TextareaProps } from "@/components/ui/textarea";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { FileButton } from "@/components/buttons/file";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
import { PageRootSection } from "@/components/page-root-section";
|
||||
import { PageSection } from "@/components/page-section";
|
||||
@@ -20,23 +17,23 @@ export default function Page() {
|
||||
);
|
||||
|
||||
const { header: h, payload: p } = decode(jwt);
|
||||
const header = h.isErr() ? "" : JSON.stringify(h.value, null, 2);
|
||||
const payload = p.isErr() ? "" : JSON.stringify(p.value, null, 2);
|
||||
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 onJwtChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) => setJwt(value);
|
||||
const onJwtChange: TextareaProps["onChange"] = e => setJwt(e.currentTarget.value);
|
||||
|
||||
const jwtTokenPasteButton = <PasteButton onClipboardRead={setJwt} />;
|
||||
const jwtTokenPasteButton = <Button.Paste onClipboardRead={setJwt} />;
|
||||
|
||||
const jwtTokenFileButton = (
|
||||
<FileButton onFileRead={setJwt} iconOnly aria-label="load a token file" />
|
||||
<Button.File onFileRead={setJwt} iconOnly aria-label="load a token file" />
|
||||
);
|
||||
|
||||
const jwtTokenClearButton = <ClearButton onClick={clearJwt} iconOnly aria-label="clear token" />;
|
||||
const jwtTokenClearButton = <Button.Clear onClick={clearJwt} iconOnly aria-label="clear token" />;
|
||||
|
||||
const heaederCopyButton = <CopyButton text={header} />;
|
||||
const payloadCopyButton = <CopyButton text={payload} />;
|
||||
const heaederCopyButton = <Button.Copy text={header} />;
|
||||
const payloadCopyButton = <Button.Copy text={payload} />;
|
||||
|
||||
const jwtTokenControl = (
|
||||
<ControlMenu list={[jwtTokenPasteButton, jwtTokenFileButton, jwtTokenClearButton]} />
|
||||
|
||||
@@ -5,10 +5,7 @@ import { useCallback, useState } from "react";
|
||||
import { toolGroups } from "@/config/tools";
|
||||
import { safeDecodeURIComponent, safeEncodeURIComponent } from "@/lib/uri";
|
||||
import { Textarea, TextareaProps } from "@/components/ui/textarea";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { FileButton } from "@/components/buttons/file";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
import { PageRootSection } from "@/components/page-root-section";
|
||||
import { PageSection } from "@/components/page-section";
|
||||
@@ -19,17 +16,17 @@ export default function Page() {
|
||||
encoded: "%3E%20It's%20%22URL%20encoding%22%3F",
|
||||
});
|
||||
|
||||
const setDecodedReactively = useCallback((text: string) => {
|
||||
const setFormByDecoded = useCallback((text: string) => {
|
||||
setForm({
|
||||
decoded: text,
|
||||
encoded: safeEncodeURIComponent(text).unwrapOr(""),
|
||||
});
|
||||
}, []);
|
||||
|
||||
const setEncodedReactively = useCallback((text: string) => {
|
||||
const setFormByEncoded = useCallback((text: string) => {
|
||||
setForm({
|
||||
encoded: text,
|
||||
decoded: safeDecodeURIComponent(text).unwrapOr(""),
|
||||
encoded: text,
|
||||
});
|
||||
}, []);
|
||||
|
||||
@@ -40,33 +37,29 @@ export default function Page() {
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onDecodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||
setDecodedReactively(value);
|
||||
const onDecodedChange: TextareaProps["onChange"] = e => setFormByDecoded(e.currentTarget.value);
|
||||
const onEncodedChange: TextareaProps["onChange"] = e => setFormByEncoded(e.currentTarget.value);
|
||||
|
||||
const onEncodedChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||
setEncodedReactively(value);
|
||||
|
||||
const decodedPasteButton = <PasteButton onClipboardRead={setDecodedReactively} />;
|
||||
const encodedPasteButton = <PasteButton onClipboardRead={setEncodedReactively} />;
|
||||
const decodedPasteButton = <Button.Paste onClipboardRead={setFormByDecoded} />;
|
||||
const encodedPasteButton = <Button.Paste onClipboardRead={setFormByEncoded} />;
|
||||
|
||||
const decodedFileButton = (
|
||||
<FileButton onFileRead={setDecodedReactively} iconOnly aria-label="load a decoded file" />
|
||||
<Button.File onFileRead={setFormByDecoded} iconOnly aria-label="load a decoded file" />
|
||||
);
|
||||
const encodedFileButton = (
|
||||
<FileButton onFileRead={setEncodedReactively} iconOnly aria-label="load a encoded file" />
|
||||
<Button.File onFileRead={setFormByEncoded} iconOnly aria-label="load a encoded file" />
|
||||
);
|
||||
|
||||
const decodedCopyButton = <CopyButton text={form.decoded} />;
|
||||
const encodedCopyButton = <CopyButton text={form.encoded} />;
|
||||
const decodedCopyButton = <Button.Copy text={form.decoded} />;
|
||||
const encodedCopyButton = <Button.Copy text={form.encoded} />;
|
||||
|
||||
const clearButton = (
|
||||
<ClearButton onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
|
||||
<Button.Clear onClick={clearBoth} iconOnly aria-label="clear decoded and encoded" />
|
||||
);
|
||||
|
||||
const decodedControl = (
|
||||
<ControlMenu list={[decodedPasteButton, decodedFileButton, decodedCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
const encodedControl = (
|
||||
<ControlMenu list={[encodedPasteButton, encodedFileButton, encodedCopyButton, clearButton]} />
|
||||
);
|
||||
|
||||
@@ -5,17 +5,8 @@ import { useCallback, useState } from "react";
|
||||
import { toolGroups } from "@/config/tools";
|
||||
import { safeJsonParse } from "@/lib/json";
|
||||
import { Editor, EditorProps } from "@/components/ui/editor";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { FileButton } from "@/components/buttons/file";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Select from "@/components/ui/select";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { Configuration } from "@/components/configuration";
|
||||
import { Configurations } from "@/components/configurations";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
@@ -35,7 +26,7 @@ export default function Page() {
|
||||
const [input, setInput] = useState('{\n"foo":"bar"\n}');
|
||||
|
||||
const parsed = safeJsonParse(input);
|
||||
const output = parsed.isErr() ? "" : JSON.stringify(parsed.value, null, indentation);
|
||||
const output = parsed.map(x => JSON.stringify(x, null, indentation)).unwrapOr("");
|
||||
|
||||
const clearInput = useCallback(() => setInput(""), []);
|
||||
|
||||
@@ -46,33 +37,33 @@ export default function Page() {
|
||||
icon={<icons.Space size={24} className="-translate-y-1.5" />}
|
||||
title="Indentation"
|
||||
control={
|
||||
<Select value={indentation} onValueChange={setIndentation}>
|
||||
<SelectTrigger
|
||||
<Select.Root value={indentation} onValueChange={setIndentation}>
|
||||
<Select.Trigger
|
||||
className="w-28"
|
||||
aria-label="toggle open/close state of indentation selection"
|
||||
>
|
||||
<SelectValue placeholder={indentation} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={indentations.two}>2 spaces</SelectItem>
|
||||
<SelectItem value={indentations.four}>4 spaces</SelectItem>
|
||||
<SelectItem value={indentations.tab}>1 tab</SelectItem>
|
||||
<SelectItem value={indentations.zero}>minified</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select.Value placeholder={indentation} />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value={indentations.two}>2 spaces</Select.Item>
|
||||
<Select.Item value={indentations.four}>4 spaces</Select.Item>
|
||||
<Select.Item value={indentations.tab}>1 tab</Select.Item>
|
||||
<Select.Item value={indentations.zero}>minified</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
const inputPasteButton = <PasteButton onClipboardRead={setInput} />;
|
||||
const inputPasteButton = <Button.Paste onClipboardRead={setInput} />;
|
||||
|
||||
const inputFileButton = (
|
||||
<FileButton accept=".json" onFileRead={setInput} iconOnly aria-label="load a json file" />
|
||||
<Button.File accept=".json" onFileRead={setInput} iconOnly aria-label="load a json file" />
|
||||
);
|
||||
|
||||
const inputClearButton = <ClearButton onClick={clearInput} iconOnly aria-label="clear json" />;
|
||||
const inputClearButton = <Button.Clear onClick={clearInput} iconOnly aria-label="clear json" />;
|
||||
|
||||
const outputCopyButton = <CopyButton text={output} />;
|
||||
const outputCopyButton = <Button.Copy text={output} />;
|
||||
|
||||
const inputControl = <ControlMenu list={[inputPasteButton, inputFileButton, inputClearButton]} />;
|
||||
const outputControl = <ControlMenu list={[outputCopyButton]} />;
|
||||
|
||||
@@ -6,10 +6,7 @@ import createHash from "create-hash";
|
||||
import { toolGroups } from "@/config/tools";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea, TextareaProps } from "@/components/ui/textarea";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { FileButton } from "@/components/buttons/file";
|
||||
import { PasteButton } from "@/components/buttons/paste";
|
||||
import * as Button from "@/components/buttons";
|
||||
import { Configuration } from "@/components/configuration";
|
||||
import { Configurations } from "@/components/configurations";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
@@ -34,8 +31,7 @@ export default function Page() {
|
||||
|
||||
const clearInput = useCallback(() => setInput(""), []);
|
||||
|
||||
const onInputChange: TextareaProps["onChange"] = ({ currentTarget: { value } }) =>
|
||||
setInput(value);
|
||||
const onInputChange: TextareaProps["onChange"] = e => setInput(e.currentTarget.value);
|
||||
|
||||
const uppercaseConfig = (
|
||||
<Configuration
|
||||
@@ -53,16 +49,20 @@ export default function Page() {
|
||||
/>
|
||||
);
|
||||
|
||||
const inputPasteButton = <PasteButton onClipboardRead={setInput} />;
|
||||
const inputFileButton = <FileButton onFileRead={setInput} iconOnly aria-label="load a file" />;
|
||||
const inputClearButton = <ClearButton onClick={clearInput} iconOnly aria-label="clear input" />;
|
||||
const inputPasteButton = <Button.Paste onClipboardRead={setInput} />;
|
||||
const inputFileButton = <Button.File onFileRead={setInput} iconOnly aria-label="load a file" />;
|
||||
const inputClearButton = <Button.Clear onClick={clearInput} iconOnly aria-label="clear input" />;
|
||||
|
||||
const inputControl = <ControlMenu list={[inputPasteButton, inputFileButton, inputClearButton]} />;
|
||||
|
||||
const md5CopyButton = <CopyButton text={md5} iconOnly aria-label="copy generated md5" />;
|
||||
const sha1CopyButton = <CopyButton text={sha1} iconOnly aria-label="copy generated sha1" />;
|
||||
const sha256CopyButton = <CopyButton text={sha256} iconOnly aria-label="copy generated sha256" />;
|
||||
const sha512CopyButton = <CopyButton text={sha512} iconOnly aria-label="copy generated sha512" />;
|
||||
const md5CopyButton = <Button.Copy text={md5} iconOnly aria-label="copy generated md5" />;
|
||||
const sha1CopyButton = <Button.Copy text={sha1} iconOnly aria-label="copy generated sha1" />;
|
||||
const sha256CopyButton = (
|
||||
<Button.Copy text={sha256} iconOnly aria-label="copy generated sha256" />
|
||||
);
|
||||
const sha512CopyButton = (
|
||||
<Button.Copy text={sha512} iconOnly aria-label="copy generated sha512" />
|
||||
);
|
||||
|
||||
return (
|
||||
<PageRootSection title={toolGroups.generators.tools.hash.longTitle}>
|
||||
|
||||
@@ -9,17 +9,10 @@ import { uuid } from "@/lib/uuid";
|
||||
import { useScrollFollow } from "@/hooks/useScrollFollow";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input, InputProps } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectProps,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import * as Select from "@/components/ui/select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { ClearButton } from "@/components/buttons/clear";
|
||||
import { CopyButton } from "@/components/buttons/copy";
|
||||
import { Clear } from "@/components/buttons/clear";
|
||||
import { Copy } from "@/components/buttons/copy";
|
||||
import { Configuration } from "@/components/configuration";
|
||||
import { Configurations } from "@/components/configurations";
|
||||
import { ControlMenu } from "@/components/control-menu";
|
||||
@@ -48,22 +41,19 @@ export default function Page() {
|
||||
|
||||
const clearUuids = useCallback(() => setUuids([]), []);
|
||||
|
||||
const onUuidVersionChange: NonNullable<SelectProps["onValueChange"]> = useCallback(value => {
|
||||
const onUuidVersionChange: NonNullable<Select.Props["onValueChange"]> = useCallback(value => {
|
||||
if (uuidVersions.is(value)) {
|
||||
setUuidVersion(value);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onGeneratesChange: NonNullable<InputProps["onChange"]> = useCallback(
|
||||
({ currentTarget: { value } }) => {
|
||||
const newGenerates = Number(value);
|
||||
const onGeneratesChange: NonNullable<InputProps["onChange"]> = useCallback(e => {
|
||||
const newGenerates = Number(e.currentTarget.value);
|
||||
|
||||
if (newGenerates >= 1 && newGenerates <= 1000) {
|
||||
setGenerates(newGenerates);
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
if (newGenerates >= 1 && newGenerates <= 1000) {
|
||||
setGenerates(newGenerates);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const onGenerateClick = () => {
|
||||
const newUuids = range(1, generates).map(_ => uuid(uuidVersion, hyphens, uppercase));
|
||||
@@ -108,24 +98,24 @@ export default function Page() {
|
||||
title="UUID version"
|
||||
description="Choose the version of UUID to generate"
|
||||
control={
|
||||
<Select value={uuidVersion} onValueChange={onUuidVersionChange}>
|
||||
<SelectTrigger
|
||||
<Select.Root value={uuidVersion} onValueChange={onUuidVersionChange}>
|
||||
<Select.Trigger
|
||||
className="w-28"
|
||||
aria-label="toggle open/close state of uuid version selection"
|
||||
>
|
||||
<SelectValue placeholder={uuidVersion} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value={versions.v1}>1</SelectItem>
|
||||
<SelectItem value={versions.v4}>4 (GUID)</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select.Value placeholder={uuidVersion} />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value={versions.v1}>1</Select.Item>
|
||||
<Select.Item value={versions.v4}>4 (GUID)</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
const uuidsCopyButton = <CopyButton text={uuidsString} />;
|
||||
const uuidsClearButton = <ClearButton onClick={clearUuids} iconOnly aria-label="clear uuids" />;
|
||||
const uuidsCopyButton = <Copy text={uuidsString} />;
|
||||
const uuidsClearButton = <Clear onClick={clearUuids} iconOnly aria-label="clear uuids" />;
|
||||
|
||||
const uuidsControl = <ControlMenu list={[uuidsCopyButton, uuidsClearButton]} />;
|
||||
|
||||
|
||||
@@ -3,13 +3,7 @@
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
import { singleTools } from "@/config/tools";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import * as Select from "@/components/ui/select";
|
||||
import { Configuration } from "@/components/configuration";
|
||||
import { Configurations } from "@/components/configurations";
|
||||
import { icons } from "@/components/icons";
|
||||
@@ -25,19 +19,19 @@ export default function Page() {
|
||||
title="App theme"
|
||||
description="Select which app theme to display"
|
||||
control={
|
||||
<Select value={theme} onValueChange={setTheme}>
|
||||
<SelectTrigger
|
||||
<Select.Root value={theme} onValueChange={setTheme}>
|
||||
<Select.Trigger
|
||||
className="w-28"
|
||||
aria-label="toggle open/close state of app theme selection"
|
||||
>
|
||||
<SelectValue placeholder={theme} />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="light">Light</SelectItem>
|
||||
<SelectItem value="dark">Dark</SelectItem>
|
||||
<SelectItem value="system">System</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select.Value placeholder={theme} />
|
||||
</Select.Trigger>
|
||||
<Select.Content>
|
||||
<Select.Item value="light">Light</Select.Item>
|
||||
<Select.Item value="dark">Dark</Select.Item>
|
||||
<Select.Item value="system">System</Select.Item>
|
||||
</Select.Content>
|
||||
</Select.Root>
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { Button, ButtonProps } from "@/components/ui/button";
|
||||
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
|
||||
|
||||
export type BaseButtonProps = ButtonProps & {
|
||||
export type BaseProps = ButtonProps & {
|
||||
icon: React.ReactNode;
|
||||
iconOnly?: true;
|
||||
labelText: string;
|
||||
};
|
||||
|
||||
export function BaseButton({ icon, iconOnly, labelText, ...props }: BaseButtonProps) {
|
||||
export function Base({ icon, iconOnly, labelText, ...props }: BaseProps) {
|
||||
const button = (
|
||||
<Button className="w-fit border" {...props}>
|
||||
{icon}
|
||||
|
||||
@@ -3,12 +3,12 @@ import equal from "react-fast-compare";
|
||||
|
||||
import { icons } from "@/components/icons";
|
||||
|
||||
import { BaseButton, BaseButtonProps } from "./base";
|
||||
import { Base, BaseProps } from "./base";
|
||||
|
||||
export type ClearButtonProps = Omit<BaseButtonProps, "icon" | "labelText">;
|
||||
export type ClearProps = Omit<BaseProps, "icon" | "labelText">;
|
||||
|
||||
function RawClearButton({ iconOnly, ...props }: ClearButtonProps) {
|
||||
return <BaseButton {...props} icon={<icons.X size={16} />} {...{ iconOnly }} labelText="Clear" />;
|
||||
function RawClear({ iconOnly, ...props }: ClearProps) {
|
||||
return <Base {...props} icon={<icons.X size={16} />} {...{ iconOnly }} labelText="Clear" />;
|
||||
}
|
||||
|
||||
export const ClearButton = memo(RawClearButton, equal);
|
||||
export const Clear = memo(RawClear, equal);
|
||||
|
||||
@@ -3,14 +3,14 @@ import equal from "react-fast-compare";
|
||||
|
||||
import { icons } from "@/components/icons";
|
||||
|
||||
import { BaseButton, BaseButtonProps } from "./base";
|
||||
import { Base, BaseProps } from "./base";
|
||||
|
||||
export type CopyButtonProps = Omit<BaseButtonProps, "icon" | "labelText" | "onClick"> & {
|
||||
export type CopyProps = Omit<BaseProps, "icon" | "labelText" | "onClick"> & {
|
||||
text: string;
|
||||
};
|
||||
|
||||
function RawCopyButton({ text, iconOnly, ...props }: CopyButtonProps) {
|
||||
const onClick: BaseButtonProps["onClick"] = useCallback(() => {
|
||||
function RawButton({ text, iconOnly, ...props }: CopyProps) {
|
||||
const onClick: BaseProps["onClick"] = useCallback(() => {
|
||||
navigator.clipboard.writeText(text).catch(e => {
|
||||
if (e instanceof Error) {
|
||||
// eslint-disable-next-line no-alert
|
||||
@@ -20,13 +20,8 @@ function RawCopyButton({ text, iconOnly, ...props }: CopyButtonProps) {
|
||||
}, [text]);
|
||||
|
||||
return (
|
||||
<BaseButton
|
||||
{...props}
|
||||
icon={<icons.Copy size={16} />}
|
||||
{...{ iconOnly, onClick }}
|
||||
labelText="Copy"
|
||||
/>
|
||||
<Base {...props} icon={<icons.Copy size={16} />} {...{ iconOnly, onClick }} labelText="Copy" />
|
||||
);
|
||||
}
|
||||
|
||||
export const CopyButton = memo(RawCopyButton, equal);
|
||||
export const Copy = memo(RawButton, equal);
|
||||
|
||||
@@ -3,30 +3,24 @@ import equal from "react-fast-compare";
|
||||
|
||||
import { icons } from "@/components/icons";
|
||||
|
||||
import { BaseButton, BaseButtonProps } from "./base";
|
||||
import { Base, BaseProps } from "./base";
|
||||
|
||||
type InputProps = React.ComponentProps<"input">;
|
||||
|
||||
export type FileButtonProps = Pick<InputProps, "accept"> &
|
||||
Omit<BaseButtonProps, "icon" | "labelText" | "onClick"> & {
|
||||
export type FileProps = Pick<InputProps, "accept"> &
|
||||
Omit<BaseProps, "icon" | "labelText" | "onClick"> & {
|
||||
maxFileSizeMb?: number;
|
||||
onFileRead: (text: string) => void;
|
||||
};
|
||||
|
||||
export function RawFileButton({
|
||||
accept,
|
||||
iconOnly,
|
||||
maxFileSizeMb = 20,
|
||||
onFileRead,
|
||||
...props
|
||||
}: FileButtonProps) {
|
||||
export function RawFile({ accept, iconOnly, maxFileSizeMb = 20, onFileRead, ...props }: FileProps) {
|
||||
const ref = useRef<HTMLInputElement>(null);
|
||||
|
||||
const onClick = () => ref.current?.click();
|
||||
|
||||
const onChange: NonNullable<InputProps["onChange"]> = useCallback(
|
||||
({ currentTarget }) => {
|
||||
const file = Array.from(currentTarget.files ?? []).at(0);
|
||||
e => {
|
||||
const file = Array.from(e.currentTarget.files ?? []).at(0);
|
||||
|
||||
if (!file) {
|
||||
return;
|
||||
@@ -51,14 +45,14 @@ export function RawFileButton({
|
||||
|
||||
// clear selected file to accept the same file again
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
currentTarget.value = "";
|
||||
e.currentTarget.value = "";
|
||||
},
|
||||
[maxFileSizeMb, onFileRead]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<BaseButton
|
||||
<Base
|
||||
{...props}
|
||||
icon={<icons.File size={16} />}
|
||||
{...{ iconOnly, onClick }}
|
||||
@@ -69,4 +63,4 @@ export function RawFileButton({
|
||||
);
|
||||
}
|
||||
|
||||
export const FileButton = memo(RawFileButton, equal);
|
||||
export const File = memo(RawFile, equal);
|
||||
|
||||
4
components/buttons/index.ts
Normal file
4
components/buttons/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export * from "./clear";
|
||||
export * from "./copy";
|
||||
export * from "./file";
|
||||
export * from "./paste";
|
||||
@@ -3,14 +3,14 @@ import equal from "react-fast-compare";
|
||||
|
||||
import { icons } from "@/components/icons";
|
||||
|
||||
import { BaseButton, BaseButtonProps } from "./base";
|
||||
import { Base, BaseProps } from "./base";
|
||||
|
||||
export type PasteButtonProps = Omit<BaseButtonProps, "icon" | "labelText" | "onClick"> & {
|
||||
export type PasteProps = Omit<BaseProps, "icon" | "labelText" | "onClick"> & {
|
||||
onClipboardRead: (text: string) => void;
|
||||
};
|
||||
|
||||
export function RawPasteButton({ iconOnly, onClipboardRead, ...props }: PasteButtonProps) {
|
||||
const onClick: BaseButtonProps["onClick"] = useCallback(() => {
|
||||
export function RawPaste({ iconOnly, onClipboardRead, ...props }: PasteProps) {
|
||||
const onClick: BaseProps["onClick"] = useCallback(() => {
|
||||
navigator.clipboard
|
||||
.readText()
|
||||
.then(onClipboardRead)
|
||||
@@ -23,7 +23,7 @@ export function RawPasteButton({ iconOnly, onClipboardRead, ...props }: PasteBut
|
||||
}, [onClipboardRead]);
|
||||
|
||||
return (
|
||||
<BaseButton
|
||||
<Base
|
||||
{...props}
|
||||
icon={<icons.Clipboard size={16} />}
|
||||
{...{ iconOnly, onClick }}
|
||||
@@ -32,4 +32,4 @@ export function RawPasteButton({ iconOnly, onClipboardRead, ...props }: PasteBut
|
||||
);
|
||||
}
|
||||
|
||||
export const PasteButton = memo(RawPasteButton, equal);
|
||||
export const Paste = memo(RawPaste, equal);
|
||||
|
||||
@@ -27,7 +27,7 @@ export function SearchBar() {
|
||||
}
|
||||
};
|
||||
|
||||
const changeText: InputProps["onChange"] = ({ currentTarget }) => setText(currentTarget.value);
|
||||
const changeText: InputProps["onChange"] = e => setText(e.currentTarget.value);
|
||||
|
||||
const searchIfEnter: InputProps["onKeyDown"] = ({ code }) => {
|
||||
if (code === "Enter") {
|
||||
|
||||
@@ -7,13 +7,11 @@ import { cn } from "@/lib/style";
|
||||
import { icons } from "@/components/icons";
|
||||
import { Indicator } from "@/components/indicator";
|
||||
|
||||
export type SelectProps = React.ComponentPropsWithoutRef<typeof Select>;
|
||||
export type Props = React.ComponentPropsWithoutRef<typeof SelectPrimitive.Root>;
|
||||
|
||||
export const Select = SelectPrimitive.Root;
|
||||
export const SelectGroup = SelectPrimitive.Group;
|
||||
export const SelectValue = SelectPrimitive.Value;
|
||||
export const { Root, Group, Value } = SelectPrimitive;
|
||||
|
||||
export const SelectTrigger = React.forwardRef<
|
||||
export const Trigger = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Trigger>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Trigger>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
@@ -34,9 +32,9 @@ export const SelectTrigger = React.forwardRef<
|
||||
</SelectPrimitive.Icon>
|
||||
</SelectPrimitive.Trigger>
|
||||
));
|
||||
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||
Trigger.displayName = SelectPrimitive.Trigger.displayName;
|
||||
|
||||
export const SelectContent = React.forwardRef<
|
||||
export const Content = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Content>
|
||||
>(({ className, children, position = "popper", ...props }, ref) => (
|
||||
@@ -62,9 +60,9 @@ export const SelectContent = React.forwardRef<
|
||||
</SelectPrimitive.Content>
|
||||
</SelectPrimitive.Portal>
|
||||
));
|
||||
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
||||
Content.displayName = SelectPrimitive.Content.displayName;
|
||||
|
||||
export const SelectLabel = React.forwardRef<
|
||||
export const Label = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Label>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Label>
|
||||
>(({ className, ...props }, ref) => (
|
||||
@@ -74,9 +72,9 @@ export const SelectLabel = React.forwardRef<
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
||||
Label.displayName = SelectPrimitive.Label.displayName;
|
||||
|
||||
export const SelectItem = React.forwardRef<
|
||||
export const Item = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Item>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
@@ -98,9 +96,9 @@ export const SelectItem = React.forwardRef<
|
||||
<SelectPrimitive.ItemText>{children}</SelectPrimitive.ItemText>
|
||||
</SelectPrimitive.Item>
|
||||
));
|
||||
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
||||
Item.displayName = SelectPrimitive.Item.displayName;
|
||||
|
||||
export const SelectSeparator = React.forwardRef<
|
||||
export const Separator = React.forwardRef<
|
||||
React.ElementRef<typeof SelectPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof SelectPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
@@ -110,4 +108,4 @@ export const SelectSeparator = React.forwardRef<
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
||||
Separator.displayName = SelectPrimitive.Separator.displayName;
|
||||
|
||||
Reference in New Issue
Block a user