feat: implement text inspector and case converter tool

This commit is contained in:
2024-05-14 18:01:20 +02:00
parent 90ba9f4f8e
commit 5113fe626b
13 changed files with 471 additions and 47 deletions

3
.gitignore vendored
View File

@@ -45,3 +45,6 @@ firebase-debug.log
/test-results/
/playwright-report/
/playwright/.cache/
# editors
.idea

View File

@@ -13,7 +13,7 @@ pnpm dev # route types will be generated by next.js
## Known issues
- Tool search does not set query parameters
- [(Shallow routing) updating search params causes server code to rerun.](https://github.com/vercel/next.js/issues/49668)
- [(Shallow routing) updating search params causes server code to rerun.](https://github.com/vercel/next.js/issues/49668)
- [Editor may not resize to fit container size](https://github.com/suren-atoyan/monaco-react/issues/346)
- CSS outlines messed up
@@ -27,6 +27,8 @@ pnpm dev # route types will be generated by next.js
- [x] Formatters
- [x] Generators
- [ ] Text
- [x] Text Inspector
- [ ] Text Diff
- [ ] Graphic
- [ ] Settings
- [x] Settings menu item

View File

@@ -0,0 +1,17 @@
import { Metadata } from "next";
import { toolGroups } from "@/config/tools";
export const metadata: Metadata = {
title: toolGroups.text.tools.inspector_and_case_converter.longTitle,
description: toolGroups.text.tools.inspector_and_case_converter.description,
robots: {
googleBot: {
index: true,
},
},
};
export default function Layout({ children }: { children: React.ReactNode }) {
return children;
}

View File

@@ -0,0 +1,89 @@
"use client";
import { useCallback, useMemo, useState } from "react";
import { toolGroups } from "@/config/tools";
import { noOp } from "@/lib/base";
import {
countBytes,
countCharacters,
countLines,
countWords,
modeTitle,
TextTransformMode,
textTransformModes,
transformText,
} from "@/lib/text";
import { Textarea, TextareaProps } from "@/components/ui/textarea";
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group";
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";
export default function Page() {
const [input, setInput] = useState("ConvertMe");
const [mode, setMode] = useState(TextTransformMode.original);
const output = transformText(input, mode);
const stats = useMemo(
() => ({
characters: countCharacters(input),
words: countWords(input),
lines: countLines(input),
bytes: countBytes(input),
}),
[input]
);
const clearInput = useCallback(() => setInput(""), []);
const onInputChange: TextareaProps["onChange"] = e => setInput(e.currentTarget.value);
const onModeChange = (value: string) => {
if (value && value in TextTransformMode) {
setMode(value as TextTransformMode);
}
};
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 outputCopyButton = <Button.Copy text={output} />;
const inputControl = <ControlMenu list={[inputPasteButton, inputFileButton, inputClearButton]} />;
const outputControl = <ControlMenu list={[outputCopyButton]} />;
return (
<PageRootSection title={toolGroups.text.tools.inspector_and_case_converter.longTitle}>
<PageSection title="Convert">
<ToggleGroup className="flex-wrap" type="single" value={mode} onValueChange={onModeChange}>
{textTransformModes.map(m => (
<ToggleGroupItem key={m} value={m}>
{modeTitle[m]}
</ToggleGroupItem>
))}
</ToggleGroup>
</PageSection>
<div className="flex flex-1 flex-col gap-x-4 gap-y-5 lg:flex-row">
<PageSection className="min-h-[200px] flex-1" title="Input" control={inputControl}>
<Textarea value={input} onChange={onInputChange} rows={10} />
</PageSection>
<PageSection className="min-h-[200px] flex-1" title="Output" control={outputControl}>
<Textarea value={output} onChange={noOp} rows={10} readOnly />
</PageSection>
</div>
<PageSection className="min-h-[200px] flex-1" title="Information">
<div className="grid max-w-sm grid-cols-2 gap-x-4">
Characters: <span className="font-mono">{stats.characters}</span>
Words: <span className="font-mono">{stats.words}</span>
Lines: <span className="font-mono">{stats.lines}</span>
Bytes: <span className="font-mono">{stats.bytes}</span>
</div>
</PageSection>
</PageRootSection>
);
}

16
app/text/layout.tsx Normal file
View File

@@ -0,0 +1,16 @@
import { Metadata } from "next";
import { toolGroups } from "@/config/tools";
export const metadata: Metadata = {
title: toolGroups.generators.title,
robots: {
googleBot: {
index: false,
},
},
};
export default function Layout({ children }: { children: React.ReactNode }) {
return children;
}

11
app/text/page.tsx Normal file
View File

@@ -0,0 +1,11 @@
import { toolGroups } from "@/config/tools";
import { PageRootSection } from "@/components/page-root-section";
import { ToolCards } from "@/components/tool-cards";
export default function Page() {
return (
<PageRootSection title={toolGroups.text.title}>
<ToolCards tools={Object.values(toolGroups.text.tools)} />
</PageRootSection>
);
}

View File

@@ -28,6 +28,7 @@ export const Settings = memo(icons.Settings, equal);
export const Settings2 = memo(icons.Settings2, equal);
export const Space = memo(icons.Space, equal);
export const Sun = memo(icons.SunMedium, equal);
export const Type = memo(icons.Type, equal);
export const Minus = memo(icons.Minus, equal);
export const Moon = memo(icons.Moon, equal);
export const X = memo(icons.X, equal);

View File

@@ -0,0 +1,39 @@
"use client";
import * as React from "react";
import * as ToggleGroupPrimitive from "@radix-ui/react-toggle-group";
import { cn } from "@/lib/style";
const ToggleGroup = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Root>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Root>
>(({ className, ...props }, ref) => (
<ToggleGroupPrimitive.Root
ref={ref}
className={cn("flex items-center gap-2.5", className)}
{...props}
/>
));
ToggleGroup.displayName = ToggleGroupPrimitive.Root.displayName;
const ToggleGroupItem = React.forwardRef<
React.ElementRef<typeof ToggleGroupPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof ToggleGroupPrimitive.Item>
>(({ className, children, ...props }, ref) => (
<ToggleGroupPrimitive.Item
ref={ref}
className={cn(
"focus-visible:ring-ring inline-flex h-10 items-center justify-center rounded-md bg-accent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-sky-600 data-[state=on]:text-white",
className
)}
{...props}
>
{children}
</ToggleGroupPrimitive.Item>
));
ToggleGroupItem.displayName = ToggleGroupPrimitive.Item.displayName;
export { ToggleGroup, ToggleGroupItem };

View File

@@ -124,6 +124,21 @@ export const toolGroups = {
},
},
},
text: {
Icon: icons.Type,
title: "Text",
href: "/text",
tools: {
inspector_and_case_converter: {
Icon: icons.CaseSensitive,
shortTitle: "Inspector & Case Converter",
longTitle: "Text Inspector & Case Converter",
description: "Analyze text and convert it to a different case",
keywords: "case converter convert text inspector inspect",
href: "/text/inspector",
},
},
},
} as const satisfies ToolGroups;
export const singleTools = {

View File

@@ -20,3 +20,5 @@ export const formatOctal = formatNumber(3, " ");
export const formatBinary = formatNumber(4, " ");
export const unformatNumber = (x: string) => x.replaceAll(/[ ,]/g, "");
export function noOp() {}

96
lib/text.ts Normal file
View File

@@ -0,0 +1,96 @@
import * as changeCase from "change-case";
import { convert as slugify } from "url-slug";
export function countWords(text: string): number {
// Split the text by any whitespace (spaces, newlines, tabs, etc.)
const words = text.split(/\s+/);
// Filter out any empty strings in case there are extra spaces or newlines
const filteredWords = words.filter(word => word.length > 0);
return filteredWords.length;
}
export function countCharacters(text: string): number {
/** Unicode-proof way to get string length in codepoints (in characters)
For example:
const text = '👨‍👩‍👧‍👦';
text.length === 11;
[...new Intl.Segmenter().segment(text)].length === 1;
*/
return [...new Intl.Segmenter().segment(text)].length;
}
export function countLines(text: string): number {
return text.split("\n").length;
}
export function countBytes(text: string): number {
return new Blob([text]).size;
}
export enum TextTransformMode {
original = "original",
sentenceCase = "sentenceCase",
lowerCase = "lowerCase",
upperCase = "upperCase",
titleCase = "titleCase",
camelCase = "camelCase",
pascalCase = "pascalCase",
snakeCase = "snakeCase",
kebabCase = "kebabCase",
constantCase = "constantCase",
cobolCase = "cobolCase",
trainCase = "trainCase",
urlSlugify = "urlSlugify",
}
export const textTransformModes = Object.values(TextTransformMode);
export const modeTitle = {
[TextTransformMode.original]: "OriginalCase",
[TextTransformMode.upperCase]: "UPPER CASE",
[TextTransformMode.sentenceCase]: "Sentence case",
[TextTransformMode.lowerCase]: "lower case",
[TextTransformMode.titleCase]: "Title Case",
[TextTransformMode.camelCase]: "camelCase",
[TextTransformMode.pascalCase]: "PascalCase",
[TextTransformMode.snakeCase]: "snake_case",
[TextTransformMode.kebabCase]: "kebab-case",
[TextTransformMode.constantCase]: "CONSTANT_CASE",
[TextTransformMode.cobolCase]: "COBOL-CASE",
[TextTransformMode.trainCase]: "Train-Case",
[TextTransformMode.urlSlugify]: "url-slufigy",
};
export function transformText(text: string, mode: TextTransformMode) {
switch (mode) {
case TextTransformMode.original:
return text;
case TextTransformMode.upperCase:
return text.toUpperCase();
case TextTransformMode.sentenceCase:
return changeCase.sentenceCase(text);
case TextTransformMode.lowerCase:
return text.toLowerCase();
case TextTransformMode.titleCase:
return changeCase.capitalCase(text);
case TextTransformMode.camelCase:
return changeCase.camelCase(text);
case TextTransformMode.pascalCase:
return changeCase.pascalCase(text);
case TextTransformMode.kebabCase:
return changeCase.kebabCase(text);
case TextTransformMode.snakeCase:
return changeCase.snakeCase(text);
case TextTransformMode.cobolCase:
return changeCase.constantCase(text, { delimiter: "-" });
case TextTransformMode.constantCase:
return changeCase.constantCase(text);
case TextTransformMode.trainCase:
return changeCase.trainCase(text);
case TextTransformMode.urlSlugify:
return slugify(text);
default:
return text;
}
}

View File

@@ -31,7 +31,9 @@
"@radix-ui/react-select": "^1.2.2",
"@radix-ui/react-separator": "^1.0.3",
"@radix-ui/react-switch": "^1.0.3",
"@radix-ui/react-toggle-group": "^1.0.4",
"@radix-ui/react-tooltip": "^1.0.6",
"change-case": "^5.4.4",
"class-variance-authority": "^0.6.0",
"clsx": "^1.2.1",
"cmdk": "^0.2.0",
@@ -52,6 +54,7 @@
"react-fast-compare": "^3.2.2",
"sharp": "^0.32.1",
"tailwindcss-animate": "^1.0.5",
"url-slug": "^4.0.1",
"uuid": "^9.0.0"
},
"devDependencies": {

222
pnpm-lock.yaml generated
View File

@@ -1,5 +1,9 @@
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
excludeLinksFromLockfile: false
dependencies:
'@monaco-editor/react':
specifier: ^4.5.1
@@ -19,9 +23,15 @@ dependencies:
'@radix-ui/react-switch':
specifier: ^1.0.3
version: 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-toggle-group':
specifier: ^1.0.4
version: 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-tooltip':
specifier: ^1.0.6
version: 1.0.6(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
change-case:
specifier: ^5.4.4
version: 5.4.4
class-variance-authority:
specifier: ^0.6.0
version: 0.6.0(typescript@5.0.4)
@@ -82,6 +92,9 @@ dependencies:
tailwindcss-animate:
specifier: ^1.0.5
version: 1.0.5(tailwindcss@3.3.2)
url-slug:
specifier: ^4.0.1
version: 4.0.1
uuid:
specifier: ^9.0.0
version: 9.0.0
@@ -322,13 +335,13 @@ packages:
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.13.11
dev: false
/@babel/runtime@7.23.2:
resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==}
engines: {node: '>=6.9.0'}
dependencies:
regenerator-runtime: 0.14.0
dev: false
/@babel/template@7.21.9:
resolution: {integrity: sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==}
@@ -656,19 +669,19 @@ packages:
/@radix-ui/number@1.0.1:
resolution: {integrity: sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==}
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
dev: false
/@radix-ui/primitive@1.0.0:
resolution: {integrity: sha512-3e7rn8FDMin4CgeL7Z/49smCA3rFYY3Ha2rUQ7HRWFadS5iCRw08ZgVT1LaNTCNqgvrUiyczLflrVrF0SRQtNA==}
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
dev: false
/@radix-ui/primitive@1.0.1:
resolution: {integrity: sha512-yQ8oGX2GVsEYMWGxcovu1uGWPCxV5BFfeeYxqPmuAzUyLT9qmaMXSAhXpb0WrspIeqYzdJpkh2vHModJPgRIaw==}
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
dev: false
/@radix-ui/react-accordion@1.1.2(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
@@ -713,7 +726,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.7
'@types/react-dom': 18.2.4
@@ -734,7 +747,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0)
@@ -762,7 +775,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
@@ -778,7 +791,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
react: 18.2.0
dev: false
@@ -791,7 +804,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@types/react': 18.2.7
react: 18.2.0
dev: false
@@ -801,7 +814,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
react: 18.2.0
dev: false
@@ -814,7 +827,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@types/react': 18.2.7
react: 18.2.0
dev: false
@@ -825,7 +838,7 @@ packages:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-context': 1.0.0(react@18.2.0)
@@ -855,7 +868,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@types/react': 18.2.7
react: 18.2.0
dev: false
@@ -866,7 +879,7 @@ packages:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/primitive': 1.0.0
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0)
@@ -889,7 +902,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
@@ -906,7 +919,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
react: 18.2.0
dev: false
@@ -919,7 +932,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@types/react': 18.2.7
react: 18.2.0
dev: false
@@ -930,7 +943,7 @@ packages:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
@@ -951,7 +964,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0)
@@ -966,7 +979,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0)
react: 18.2.0
dev: false
@@ -980,7 +993,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
react: 18.2.0
@@ -1020,7 +1033,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@floating-ui/react-dom': 2.0.0(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-arrow': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
@@ -1043,7 +1056,7 @@ packages:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-primitive': 1.0.0(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
@@ -1062,7 +1075,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.7
'@types/react-dom': 18.2.4
@@ -1076,7 +1089,7 @@ packages:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.0(react@18.2.0)
react: 18.2.0
@@ -1096,7 +1109,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
@@ -1111,7 +1124,7 @@ packages:
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-slot': 1.0.0(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
@@ -1130,7 +1143,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-slot': 1.0.2(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
'@types/react-dom': 18.2.4
@@ -1138,6 +1151,35 @@ packages:
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-roving-focus@1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-2mUg5Mgcu001VkGy+FfzZyzbmuUWzgWkj3rvv4yu+mLw03+mTzbxZHvfcGyFp2b8EkQeMkpRQ5FiA2Vr2O6TeQ==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.23.2
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-collection': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-id': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
'@types/react-dom': 18.2.4
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-select@1.2.2(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-zI7McXr8fNaSrUY9mZe4x/HC0jTLY9fWNhO1oLWYMQGDXuV4UCivIGTxwioSzO0ZCYX9iSLyWmAh/1TOmX3Cnw==}
peerDependencies:
@@ -1205,7 +1247,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-compose-refs': 1.0.0(react@18.2.0)
react: 18.2.0
dev: false
@@ -1219,7 +1261,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-compose-refs': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
react: 18.2.0
@@ -1252,6 +1294,56 @@ packages:
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-toggle-group@1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-Uaj/M/cMyiyT9Bx6fOZO0SAG4Cls0GptBWiBmBxofmDbNVnYYoyRWj/2M/6VCi/7qcXFWnHhRUfdfZFvvkuu8A==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.23.2
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-context': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-direction': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-roving-focus': 1.0.4(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-toggle': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
'@types/react-dom': 18.2.4
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-toggle@1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-Pkqg3+Bc98ftZGsl60CLANXQBBQ4W3mTFS9EJvNxKMZ7magklKV69/id1mlAlOFDDfHvlCms0fx8fA4CMKDJHg==}
peerDependencies:
'@types/react': '*'
'@types/react-dom': '*'
react: ^16.8 || ^17.0 || ^18.0
react-dom: ^16.8 || ^17.0 || ^18.0
peerDependenciesMeta:
'@types/react':
optional: true
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.23.2
'@radix-ui/primitive': 1.0.1
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-use-controllable-state': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
'@types/react-dom': 18.2.4
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
dev: false
/@radix-ui/react-tooltip@1.0.6(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-DmNFOiwEc2UDigsYj6clJENma58OelxD24O4IODoZ+3sQc3Zb+L8w1EP+y9laTuKCLAysPw4fD6/v0j4KNV8rg==}
peerDependencies:
@@ -1289,7 +1381,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
react: 18.2.0
dev: false
@@ -1302,7 +1394,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@types/react': 18.2.7
react: 18.2.0
dev: false
@@ -1312,7 +1404,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
react: 18.2.0
dev: false
@@ -1326,7 +1418,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
react: 18.2.0
@@ -1337,7 +1429,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-use-callback-ref': 1.0.0(react@18.2.0)
react: 18.2.0
dev: false
@@ -1351,7 +1443,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-use-callback-ref': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
react: 18.2.0
@@ -1362,7 +1454,7 @@ packages:
peerDependencies:
react: ^16.8 || ^17.0 || ^18.0
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
react: 18.2.0
dev: false
@@ -1375,7 +1467,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@types/react': 18.2.7
react: 18.2.0
dev: false
@@ -1389,7 +1481,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@types/react': 18.2.7
react: 18.2.0
dev: false
@@ -1403,7 +1495,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/rect': 1.0.1
'@types/react': 18.2.7
react: 18.2.0
@@ -1418,7 +1510,7 @@ packages:
'@types/react':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-use-layout-effect': 1.0.1(@types/react@18.2.7)(react@18.2.0)
'@types/react': 18.2.7
react: 18.2.0
@@ -1437,7 +1529,7 @@ packages:
'@types/react-dom':
optional: true
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.4)(@types/react@18.2.7)(react-dom@18.2.0)(react@18.2.0)
'@types/react': 18.2.7
'@types/react-dom': 18.2.4
@@ -1448,7 +1540,7 @@ packages:
/@radix-ui/rect@1.0.1:
resolution: {integrity: sha512-fyrgCaedtvMg9NK3en0pnOYJdtfwxUcNolezkNPUsoX57X8oQk+NkqcvzHXD2uKNij6GXmWU9NDru2IWjrO4BQ==}
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
dev: false
/@rushstack/eslint-patch@1.3.0:
@@ -2058,6 +2150,10 @@ packages:
engines: {node: ^12.17.0 || ^14.13 || >=16.0.0}
dev: true
/change-case@5.4.4:
resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==}
dev: false
/chokidar@3.5.3:
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
engines: {node: '>= 8.10.0'}
@@ -2735,6 +2831,35 @@ packages:
- supports-color
dev: true
/eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.9)(eslint@8.41.0):
resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==}
engines: {node: '>=4'}
peerDependencies:
'@typescript-eslint/parser': '*'
eslint: '*'
eslint-import-resolver-node: '*'
eslint-import-resolver-typescript: '*'
eslint-import-resolver-webpack: '*'
peerDependenciesMeta:
'@typescript-eslint/parser':
optional: true
eslint:
optional: true
eslint-import-resolver-node:
optional: true
eslint-import-resolver-typescript:
optional: true
eslint-import-resolver-webpack:
optional: true
dependencies:
'@typescript-eslint/parser': 5.59.7(eslint@8.41.0)(typescript@5.0.4)
debug: 3.2.7
eslint: 8.41.0
eslint-import-resolver-node: 0.3.9
transitivePeerDependencies:
- supports-color
dev: true
/eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.41.0):
resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==}
engines: {node: '>=4'}
@@ -2787,7 +2912,7 @@ packages:
doctrine: 2.1.0
eslint: 8.41.0
eslint-import-resolver-node: 0.3.9
eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.7)(eslint-import-resolver-typescript@3.5.5)(eslint@8.41.0)
eslint-module-utils: 2.8.0(@typescript-eslint/parser@5.59.7)(eslint-import-resolver-node@0.3.9)(eslint@8.41.0)
has: 1.0.4
is-core-module: 2.13.0
is-glob: 4.0.3
@@ -2809,7 +2934,7 @@ packages:
peerDependencies:
eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8
dependencies:
'@babel/runtime': 7.22.3
'@babel/runtime': 7.23.2
aria-query: 5.1.3
array-includes: 3.1.6
array.prototype.flatmap: 1.3.1
@@ -4484,10 +4609,10 @@ packages:
/regenerator-runtime@0.13.11:
resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==}
dev: false
/regenerator-runtime@0.14.0:
resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==}
dev: false
/regexp.prototype.flags@1.5.0:
resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==}
@@ -5204,6 +5329,11 @@ packages:
punycode: 2.3.0
dev: true
/url-slug@4.0.1:
resolution: {integrity: sha512-OkHgffjR6bce7jNTp5BUDBhg2IcnqSAi9DEhLH8Rhxrq84uPBMbHFzvOxniEIRpSSGBcG13LhrtNR5XzUdztfQ==}
engines: {node: '>=18.0.0'}
dev: false
/use-callback-ref@1.3.0(@types/react@18.2.7)(react@18.2.0):
resolution: {integrity: sha512-3FT9PRuRdbB9HfXhEq35u4oZkvpJ5kuYbpqhCfmiZyReuRgpnhDlbr2ZEnnuS0RrJAPn6l23xjFg9kpDM+Ms7w==}
engines: {node: '>=10'}