mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-22 21:42:49 +01:00
Upgrade to React 19
This commit is contained in:
parent
cb2cd72cd4
commit
8916d7d3cc
@ -26,8 +26,8 @@
|
||||
"@waveterm/docusaurus-og": "https://github.com/wavetermdev/docusaurus-og",
|
||||
"clsx": "^2.1.1",
|
||||
"prism-react-renderer": "^2.3.0",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-typescript-code-import": "^1.0.1",
|
||||
"ua-parser-js": "^2.0.0"
|
||||
@ -53,7 +53,7 @@
|
||||
"remark-preset-lint-consistent": "^6.0.0",
|
||||
"remark-preset-lint-recommended": "^7.0.0",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.18.0"
|
||||
"typescript-eslint": "^8.18.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"path-to-regexp@npm:2.2.1": "^3",
|
||||
|
@ -39,6 +39,7 @@ import * as util from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import * as jotai from "jotai";
|
||||
import * as React from "react";
|
||||
import { JSX } from "react";
|
||||
import { BlockFrameProps } from "./blocktypes";
|
||||
|
||||
const NumActiveConnColors = 8;
|
||||
@ -513,7 +514,7 @@ const BlockFrame_Default_Component = (props: BlockFrameProps) => {
|
||||
const magnifiedBlockBlur = jotai.useAtomValue(magnifiedBlockBlurAtom);
|
||||
const [magnifiedBlockOpacityAtom] = React.useState(() => getSettingsKeyAtom("window:magnifiedblockopacity"));
|
||||
const magnifiedBlockOpacity = jotai.useAtomValue(magnifiedBlockOpacityAtom);
|
||||
const connBtnRef = React.useRef<HTMLDivElement>();
|
||||
const connBtnRef = React.useRef<HTMLDivElement>(null);
|
||||
React.useEffect(() => {
|
||||
if (!manageConnection) {
|
||||
return;
|
||||
|
@ -145,6 +145,7 @@ export function getBlockHeaderIcon(blockIcon: string, blockData: Block): React.R
|
||||
interface ConnectionButtonProps {
|
||||
connection: string;
|
||||
changeConnModalAtom: jotai.PrimitiveAtom<boolean>;
|
||||
ref?: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export function computeConnColorNum(connStatus: ConnStatus): number {
|
||||
@ -156,88 +157,84 @@ export function computeConnColorNum(connStatus: ConnStatus): number {
|
||||
return connColorNum;
|
||||
}
|
||||
|
||||
export const ConnectionButton = React.memo(
|
||||
React.forwardRef<HTMLDivElement, ConnectionButtonProps>(
|
||||
({ connection, changeConnModalAtom }: ConnectionButtonProps, ref) => {
|
||||
const [connModalOpen, setConnModalOpen] = jotai.useAtom(changeConnModalAtom);
|
||||
const isLocal = util.isBlank(connection);
|
||||
const connStatusAtom = getConnStatusAtom(connection);
|
||||
const connStatus = jotai.useAtomValue(connStatusAtom);
|
||||
let showDisconnectedSlash = false;
|
||||
let connIconElem: React.ReactNode = null;
|
||||
const connColorNum = computeConnColorNum(connStatus);
|
||||
let color = `var(--conn-icon-color-${connColorNum})`;
|
||||
const clickHandler = function () {
|
||||
setConnModalOpen(true);
|
||||
};
|
||||
let titleText = null;
|
||||
let shouldSpin = false;
|
||||
if (isLocal) {
|
||||
color = "var(--grey-text-color)";
|
||||
titleText = "Connected to Local Machine";
|
||||
connIconElem = (
|
||||
<i
|
||||
className={clsx(util.makeIconClass("laptop", false), "fa-stack-1x")}
|
||||
style={{ color: color, marginRight: 2 }}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
titleText = "Connected to " + connection;
|
||||
let iconName = "arrow-right-arrow-left";
|
||||
let iconSvg = null;
|
||||
if (connStatus?.status == "connecting") {
|
||||
color = "var(--warning-color)";
|
||||
titleText = "Connecting to " + connection;
|
||||
shouldSpin = false;
|
||||
iconSvg = (
|
||||
<div className="connecting-svg">
|
||||
<DotsSvg />
|
||||
</div>
|
||||
);
|
||||
} else if (connStatus?.status == "error") {
|
||||
color = "var(--error-color)";
|
||||
titleText = "Error connecting to " + connection;
|
||||
if (connStatus?.error != null) {
|
||||
titleText += " (" + connStatus.error + ")";
|
||||
}
|
||||
showDisconnectedSlash = true;
|
||||
} else if (!connStatus?.connected) {
|
||||
color = "var(--grey-text-color)";
|
||||
titleText = "Disconnected from " + connection;
|
||||
showDisconnectedSlash = true;
|
||||
}
|
||||
if (iconSvg != null) {
|
||||
connIconElem = iconSvg;
|
||||
} else {
|
||||
connIconElem = (
|
||||
<i
|
||||
className={clsx(util.makeIconClass(iconName, false), "fa-stack-1x")}
|
||||
style={{ color: color, marginRight: 2 }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref} className={clsx("connection-button")} onClick={clickHandler} title={titleText}>
|
||||
<span className={clsx("fa-stack connection-icon-box", shouldSpin ? "fa-spin" : null)}>
|
||||
{connIconElem}
|
||||
<i
|
||||
className="fa-slash fa-solid fa-stack-1x"
|
||||
style={{
|
||||
color: color,
|
||||
marginRight: "2px",
|
||||
textShadow: "0 1px black, 0 1.5px black",
|
||||
opacity: showDisconnectedSlash ? 1 : 0,
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
{isLocal ? null : <div className="connection-name">{connection}</div>}
|
||||
export const ConnectionButton = React.memo(({ connection, changeConnModalAtom, ref }: ConnectionButtonProps) => {
|
||||
const setConnModalOpen = jotai.useSetAtom(changeConnModalAtom);
|
||||
const isLocal = util.isBlank(connection);
|
||||
const connStatusAtom = getConnStatusAtom(connection);
|
||||
const connStatus = jotai.useAtomValue(connStatusAtom);
|
||||
let showDisconnectedSlash = false;
|
||||
let connIconElem: React.ReactNode = null;
|
||||
const connColorNum = computeConnColorNum(connStatus);
|
||||
let color = `var(--conn-icon-color-${connColorNum})`;
|
||||
const clickHandler = function () {
|
||||
setConnModalOpen(true);
|
||||
};
|
||||
let titleText = null;
|
||||
let shouldSpin = false;
|
||||
if (isLocal) {
|
||||
color = "var(--grey-text-color)";
|
||||
titleText = "Connected to Local Machine";
|
||||
connIconElem = (
|
||||
<i
|
||||
className={clsx(util.makeIconClass("laptop", false), "fa-stack-1x")}
|
||||
style={{ color: color, marginRight: 2 }}
|
||||
/>
|
||||
);
|
||||
} else {
|
||||
titleText = "Connected to " + connection;
|
||||
let iconName = "arrow-right-arrow-left";
|
||||
let iconSvg = null;
|
||||
if (connStatus?.status == "connecting") {
|
||||
color = "var(--warning-color)";
|
||||
titleText = "Connecting to " + connection;
|
||||
shouldSpin = false;
|
||||
iconSvg = (
|
||||
<div className="connecting-svg">
|
||||
<DotsSvg />
|
||||
</div>
|
||||
);
|
||||
} else if (connStatus?.status == "error") {
|
||||
color = "var(--error-color)";
|
||||
titleText = "Error connecting to " + connection;
|
||||
if (connStatus?.error != null) {
|
||||
titleText += " (" + connStatus.error + ")";
|
||||
}
|
||||
showDisconnectedSlash = true;
|
||||
} else if (!connStatus?.connected) {
|
||||
color = "var(--grey-text-color)";
|
||||
titleText = "Disconnected from " + connection;
|
||||
showDisconnectedSlash = true;
|
||||
}
|
||||
)
|
||||
);
|
||||
if (iconSvg != null) {
|
||||
connIconElem = iconSvg;
|
||||
} else {
|
||||
connIconElem = (
|
||||
<i
|
||||
className={clsx(util.makeIconClass(iconName, false), "fa-stack-1x")}
|
||||
style={{ color: color, marginRight: 2 }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref} className={clsx("connection-button")} onClick={clickHandler} title={titleText}>
|
||||
<span className={clsx("fa-stack connection-icon-box", shouldSpin ? "fa-spin" : null)}>
|
||||
{connIconElem}
|
||||
<i
|
||||
className="fa-slash fa-solid fa-stack-1x"
|
||||
style={{
|
||||
color: color,
|
||||
marginRight: "2px",
|
||||
textShadow: "0 1px black, 0 1.5px black",
|
||||
opacity: showDisconnectedSlash ? 1 : 0,
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
{isLocal ? null : <div className="connection-name">{connection}</div>}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export const Input = React.memo(
|
||||
({ decl, className, preview }: { decl: HeaderInput; className: string; preview: boolean }) => {
|
||||
|
@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import clsx from "clsx";
|
||||
import { forwardRef, memo, ReactNode, useImperativeHandle, useRef } from "react";
|
||||
import { JSX, memo, ReactNode, useImperativeHandle, useRef } from "react";
|
||||
|
||||
import "./button.scss";
|
||||
|
||||
@ -10,38 +10,35 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
className?: string;
|
||||
children?: ReactNode;
|
||||
as?: keyof JSX.IntrinsicElements | React.ComponentType<any>;
|
||||
ref?: React.RefObject<HTMLButtonElement>;
|
||||
}
|
||||
|
||||
const Button = memo(
|
||||
forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ children, disabled, className = "", as: Component = "button", ...props }: ButtonProps, ref) => {
|
||||
const btnRef = useRef<HTMLButtonElement>(null);
|
||||
useImperativeHandle(ref, () => btnRef.current as HTMLButtonElement);
|
||||
const Button = memo(({ children, disabled, className = "", as: Component = "button", ref, ...props }: ButtonProps) => {
|
||||
const btnRef = useRef<HTMLButtonElement>(null);
|
||||
useImperativeHandle(ref, () => btnRef.current as HTMLButtonElement);
|
||||
|
||||
// Check if the className contains any of the categories: solid, outlined, or ghost
|
||||
const containsButtonCategory = /(solid|outline|ghost)/.test(className);
|
||||
// If no category is present, default to 'solid'
|
||||
const categoryClassName = containsButtonCategory ? className : `solid ${className}`;
|
||||
// Check if the className contains any of the categories: solid, outlined, or ghost
|
||||
const containsButtonCategory = /(solid|outline|ghost)/.test(className);
|
||||
// If no category is present, default to 'solid'
|
||||
const categoryClassName = containsButtonCategory ? className : `solid ${className}`;
|
||||
|
||||
// Check if the className contains any of the color options: green, grey, red, or yellow
|
||||
const containsColor = /(green|grey|red|yellow)/.test(categoryClassName);
|
||||
// If no color is present, default to 'green'
|
||||
const finalClassName = containsColor ? categoryClassName : `green ${categoryClassName}`;
|
||||
// Check if the className contains any of the color options: green, grey, red, or yellow
|
||||
const containsColor = /(green|grey|red|yellow)/.test(categoryClassName);
|
||||
// If no color is present, default to 'green'
|
||||
const finalClassName = containsColor ? categoryClassName : `green ${categoryClassName}`;
|
||||
|
||||
return (
|
||||
<Component
|
||||
ref={btnRef}
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
className={clsx("wave-button", finalClassName)}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
}
|
||||
)
|
||||
);
|
||||
return (
|
||||
<Component
|
||||
ref={btnRef}
|
||||
tabIndex={disabled ? -1 : 0}
|
||||
className={clsx("wave-button", finalClassName)}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</Component>
|
||||
);
|
||||
});
|
||||
|
||||
Button.displayName = "Button";
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
import { clsx } from "clsx";
|
||||
import { atom, useAtom } from "jotai";
|
||||
import { Children, ReactElement, ReactNode, cloneElement, isValidElement, useRef } from "react";
|
||||
import { Children, ReactNode, cloneElement, isValidElement, useRef } from "react";
|
||||
|
||||
import "./expandablemenu.scss";
|
||||
|
||||
@ -109,7 +109,7 @@ const ExpandableMenuItemGroup = ({
|
||||
const [openGroups, setOpenGroups] = useAtom(openGroupsAtom);
|
||||
|
||||
// Generate a unique ID for this group using useRef
|
||||
const idRef = useRef<string>();
|
||||
const idRef = useRef<string>(null);
|
||||
|
||||
if (!idRef.current) {
|
||||
// Generate a unique ID when the component is first rendered
|
||||
@ -144,7 +144,8 @@ const ExpandableMenuItemGroup = ({
|
||||
}
|
||||
};
|
||||
|
||||
const renderChildren = Children.map(children, (child: ReactElement) => {
|
||||
// TODO: As of React 19, this is bad practice and considered unsound. See https://react.dev/blog/2024/04/25/react-19-upgrade-guide#changes-to-the-reactelement-typescript-type
|
||||
const renderChildren = Children.map(children, (child: any) => {
|
||||
if (child && child.type === ExpandableMenuItemGroupTitle) {
|
||||
return cloneElement(child, {
|
||||
...child.props,
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
import { FloatingPortal, type Placement, useDismiss, useFloating, useInteractions } from "@floating-ui/react";
|
||||
import clsx from "clsx";
|
||||
import { createRef, Fragment, memo, ReactNode, useRef, useState } from "react";
|
||||
import { createRef, Fragment, JSX, memo, ReactNode, useRef, useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import "./flyoutmenu.scss";
|
||||
|
@ -4,27 +4,25 @@
|
||||
import { useLongClick } from "@/app/hook/useLongClick";
|
||||
import { makeIconClass } from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import { forwardRef, memo, useRef } from "react";
|
||||
import { memo, useRef } from "react";
|
||||
import "./iconbutton.scss";
|
||||
|
||||
type IconButtonProps = { decl: IconButtonDecl; className?: string };
|
||||
export const IconButton = memo(
|
||||
forwardRef<HTMLButtonElement, IconButtonProps>(({ decl, className }, ref) => {
|
||||
ref = ref ?? useRef<HTMLButtonElement>(null);
|
||||
const spin = decl.iconSpin ?? false;
|
||||
useLongClick(ref, decl.click, decl.longClick, decl.disabled);
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
className={clsx("wave-iconbutton", className, decl.className, {
|
||||
disabled: decl.disabled,
|
||||
"no-action": decl.noAction,
|
||||
})}
|
||||
title={decl.title}
|
||||
style={{ color: decl.iconColor ?? "inherit" }}
|
||||
>
|
||||
{typeof decl.icon === "string" ? <i className={makeIconClass(decl.icon, true, { spin })} /> : decl.icon}
|
||||
</button>
|
||||
);
|
||||
})
|
||||
);
|
||||
type IconButtonProps = { decl: IconButtonDecl; className?: string; ref?: React.RefObject<HTMLButtonElement> };
|
||||
export const IconButton = memo(({ decl, className, ref }: IconButtonProps) => {
|
||||
ref = ref ?? useRef<HTMLButtonElement>(null);
|
||||
const spin = decl.iconSpin ?? false;
|
||||
useLongClick(ref, decl.click, decl.longClick, decl.disabled);
|
||||
return (
|
||||
<button
|
||||
ref={ref}
|
||||
className={clsx("wave-iconbutton", className, decl.className, {
|
||||
disabled: decl.disabled,
|
||||
"no-action": decl.noAction,
|
||||
})}
|
||||
title={decl.title}
|
||||
style={{ color: decl.iconColor ?? "inherit" }}
|
||||
>
|
||||
{typeof decl.icon === "string" ? <i className={makeIconClass(decl.icon, true, { spin })} /> : decl.icon}
|
||||
</button>
|
||||
);
|
||||
});
|
||||
|
@ -2,40 +2,39 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import clsx from "clsx";
|
||||
import React, { forwardRef, memo, useImperativeHandle, useRef, useState } from "react";
|
||||
import React, { memo, useImperativeHandle, useRef, useState } from "react";
|
||||
|
||||
import "./input.scss";
|
||||
|
||||
interface InputGroupProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
ref: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const InputGroup = memo(
|
||||
forwardRef<HTMLDivElement, InputGroupProps>(({ children, className }: InputGroupProps, ref) => {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
const InputGroup = memo(({ children, className, ref }: InputGroupProps) => {
|
||||
const [isFocused, setIsFocused] = useState(false);
|
||||
|
||||
const manageFocus = (focused: boolean) => {
|
||||
setIsFocused(focused);
|
||||
};
|
||||
const manageFocus = (focused: boolean) => {
|
||||
setIsFocused(focused);
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx("input-group", className, {
|
||||
focused: isFocused,
|
||||
})}
|
||||
>
|
||||
{React.Children.map(children, (child) => {
|
||||
if (React.isValidElement(child)) {
|
||||
return React.cloneElement(child as any, { manageFocus });
|
||||
}
|
||||
return child;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
);
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx("input-group", className, {
|
||||
focused: isFocused,
|
||||
})}
|
||||
>
|
||||
{React.Children.map(children, (child) => {
|
||||
if (React.isValidElement(child)) {
|
||||
return React.cloneElement(child as any, { manageFocus });
|
||||
}
|
||||
return child;
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
interface InputLeftElementProps {
|
||||
children: React.ReactNode;
|
||||
@ -70,85 +69,81 @@ interface InputProps {
|
||||
autoSelect?: boolean;
|
||||
disabled?: boolean;
|
||||
isNumber?: boolean;
|
||||
inputRef?: React.MutableRefObject<any>;
|
||||
manageFocus?: (isFocused: boolean) => void;
|
||||
ref?: React.RefObject<HTMLInputElement>;
|
||||
}
|
||||
|
||||
const Input = memo(
|
||||
forwardRef<HTMLInputElement, InputProps>(
|
||||
(
|
||||
{
|
||||
value,
|
||||
className,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onFocus,
|
||||
onBlur,
|
||||
placeholder,
|
||||
defaultValue = "",
|
||||
required,
|
||||
maxLength,
|
||||
autoFocus,
|
||||
autoSelect,
|
||||
disabled,
|
||||
isNumber,
|
||||
manageFocus,
|
||||
}: InputProps,
|
||||
ref
|
||||
) => {
|
||||
const [internalValue, setInternalValue] = useState(defaultValue);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
({
|
||||
value,
|
||||
className,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onFocus,
|
||||
onBlur,
|
||||
placeholder,
|
||||
defaultValue = "",
|
||||
required,
|
||||
maxLength,
|
||||
autoFocus,
|
||||
autoSelect,
|
||||
disabled,
|
||||
isNumber,
|
||||
manageFocus,
|
||||
ref,
|
||||
}: InputProps) => {
|
||||
const [internalValue, setInternalValue] = useState(defaultValue);
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);
|
||||
useImperativeHandle(ref, () => inputRef.current as HTMLInputElement);
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<any>) => {
|
||||
const inputValue = e.target.value;
|
||||
const handleInputChange = (e: React.ChangeEvent<any>) => {
|
||||
const inputValue = e.target.value;
|
||||
|
||||
if (isNumber && inputValue !== "" && !/^\d*$/.test(inputValue)) {
|
||||
return;
|
||||
}
|
||||
if (isNumber && inputValue !== "" && !/^\d*$/.test(inputValue)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value === undefined) {
|
||||
setInternalValue(inputValue);
|
||||
}
|
||||
if (value === undefined) {
|
||||
setInternalValue(inputValue);
|
||||
}
|
||||
|
||||
onChange && onChange(inputValue);
|
||||
};
|
||||
onChange && onChange(inputValue);
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
if (autoSelect) {
|
||||
inputRef.current?.select();
|
||||
}
|
||||
manageFocus?.(true);
|
||||
onFocus?.();
|
||||
};
|
||||
const handleFocus = () => {
|
||||
if (autoSelect) {
|
||||
inputRef.current?.select();
|
||||
}
|
||||
manageFocus?.(true);
|
||||
onFocus?.();
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
manageFocus?.(false);
|
||||
onBlur?.();
|
||||
};
|
||||
const handleBlur = () => {
|
||||
manageFocus?.(false);
|
||||
onBlur?.();
|
||||
};
|
||||
|
||||
const inputValue = value ?? internalValue;
|
||||
const inputValue = value ?? internalValue;
|
||||
|
||||
return (
|
||||
<input
|
||||
className={clsx("input", className, {
|
||||
disabled: disabled,
|
||||
})}
|
||||
ref={inputRef}
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={onKeyDown}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
placeholder={placeholder}
|
||||
maxLength={maxLength}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)
|
||||
return (
|
||||
<input
|
||||
className={clsx("input", className, {
|
||||
disabled: disabled,
|
||||
})}
|
||||
ref={inputRef}
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={onKeyDown}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
placeholder={placeholder}
|
||||
maxLength={maxLength}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Input, InputGroup, InputLeftElement, InputRightElement };
|
||||
|
@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import clsx from "clsx";
|
||||
import React, { forwardRef, memo, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import React, { memo, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
|
||||
import "./multilineinput.scss";
|
||||
|
||||
@ -21,122 +21,119 @@ interface MultiLineInputProps {
|
||||
rows?: number;
|
||||
maxRows?: number;
|
||||
manageFocus?: (isFocused: boolean) => void;
|
||||
ref?: React.RefObject<HTMLTextAreaElement>;
|
||||
}
|
||||
|
||||
const MultiLineInput = memo(
|
||||
forwardRef<HTMLTextAreaElement, MultiLineInputProps>(
|
||||
(
|
||||
{
|
||||
value,
|
||||
className,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onFocus,
|
||||
onBlur,
|
||||
placeholder,
|
||||
defaultValue = "",
|
||||
maxLength,
|
||||
autoFocus,
|
||||
disabled,
|
||||
rows = 1,
|
||||
maxRows = 5,
|
||||
manageFocus,
|
||||
}: MultiLineInputProps,
|
||||
ref
|
||||
) => {
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const [internalValue, setInternalValue] = useState(defaultValue);
|
||||
const [lineHeight, setLineHeight] = useState(24); // Default line height fallback of 24px
|
||||
const [paddingTop, setPaddingTop] = useState(0);
|
||||
const [paddingBottom, setPaddingBottom] = useState(0);
|
||||
({
|
||||
value,
|
||||
className,
|
||||
onChange,
|
||||
onKeyDown,
|
||||
onFocus,
|
||||
onBlur,
|
||||
placeholder,
|
||||
defaultValue = "",
|
||||
maxLength,
|
||||
autoFocus,
|
||||
disabled,
|
||||
rows = 1,
|
||||
maxRows = 5,
|
||||
manageFocus,
|
||||
ref,
|
||||
}: MultiLineInputProps) => {
|
||||
const textareaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const [internalValue, setInternalValue] = useState(defaultValue);
|
||||
const [lineHeight, setLineHeight] = useState(24); // Default line height fallback of 24px
|
||||
const [paddingTop, setPaddingTop] = useState(0);
|
||||
const [paddingBottom, setPaddingBottom] = useState(0);
|
||||
|
||||
useImperativeHandle(ref, () => textareaRef.current as HTMLTextAreaElement);
|
||||
useImperativeHandle(ref, () => textareaRef.current as HTMLTextAreaElement);
|
||||
|
||||
// Function to count the number of lines in the textarea value
|
||||
const countLines = (text: string) => {
|
||||
return text.split("\n").length;
|
||||
};
|
||||
// Function to count the number of lines in the textarea value
|
||||
const countLines = (text: string) => {
|
||||
return text.split("\n").length;
|
||||
};
|
||||
|
||||
const adjustTextareaHeight = () => {
|
||||
if (textareaRef.current) {
|
||||
textareaRef.current.style.height = "auto"; // Reset height to auto first
|
||||
const adjustTextareaHeight = () => {
|
||||
if (textareaRef.current) {
|
||||
textareaRef.current.style.height = "auto"; // Reset height to auto first
|
||||
|
||||
const maxHeight = maxRows * lineHeight + paddingTop + paddingBottom; // Max height based on maxRows
|
||||
const currentLines = countLines(textareaRef.current.value); // Count the number of lines
|
||||
const newHeight = Math.min(textareaRef.current.scrollHeight, maxHeight); // Calculate new height
|
||||
const maxHeight = maxRows * lineHeight + paddingTop + paddingBottom; // Max height based on maxRows
|
||||
const currentLines = countLines(textareaRef.current.value); // Count the number of lines
|
||||
const newHeight = Math.min(textareaRef.current.scrollHeight, maxHeight); // Calculate new height
|
||||
|
||||
// If the number of lines is less than or equal to maxRows, set height accordingly
|
||||
const calculatedHeight =
|
||||
currentLines <= maxRows
|
||||
? `${lineHeight * currentLines + paddingTop + paddingBottom}px`
|
||||
: `${newHeight}px`;
|
||||
// If the number of lines is less than or equal to maxRows, set height accordingly
|
||||
const calculatedHeight =
|
||||
currentLines <= maxRows
|
||||
? `${lineHeight * currentLines + paddingTop + paddingBottom}px`
|
||||
: `${newHeight}px`;
|
||||
|
||||
textareaRef.current.style.height = calculatedHeight;
|
||||
}
|
||||
};
|
||||
textareaRef.current.style.height = calculatedHeight;
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setInternalValue(e.target.value);
|
||||
onChange?.(e);
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
||||
setInternalValue(e.target.value);
|
||||
onChange?.(e);
|
||||
|
||||
// Adjust the height of the textarea after text change
|
||||
adjustTextareaHeight();
|
||||
};
|
||||
// Adjust the height of the textarea after text change
|
||||
adjustTextareaHeight();
|
||||
};
|
||||
|
||||
const handleFocus = () => {
|
||||
manageFocus?.(true);
|
||||
onFocus?.();
|
||||
};
|
||||
const handleFocus = () => {
|
||||
manageFocus?.(true);
|
||||
onFocus?.();
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
manageFocus?.(false);
|
||||
onBlur?.();
|
||||
};
|
||||
const handleBlur = () => {
|
||||
manageFocus?.(false);
|
||||
onBlur?.();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) {
|
||||
const computedStyle = window.getComputedStyle(textareaRef.current);
|
||||
const detectedLineHeight = parseFloat(computedStyle.lineHeight);
|
||||
const detectedPaddingTop = parseFloat(computedStyle.paddingTop);
|
||||
const detectedPaddingBottom = parseFloat(computedStyle.paddingBottom);
|
||||
useEffect(() => {
|
||||
if (textareaRef.current) {
|
||||
const computedStyle = window.getComputedStyle(textareaRef.current);
|
||||
const detectedLineHeight = parseFloat(computedStyle.lineHeight);
|
||||
const detectedPaddingTop = parseFloat(computedStyle.paddingTop);
|
||||
const detectedPaddingBottom = parseFloat(computedStyle.paddingBottom);
|
||||
|
||||
setLineHeight(detectedLineHeight);
|
||||
setPaddingTop(detectedPaddingTop);
|
||||
setPaddingBottom(detectedPaddingBottom);
|
||||
}
|
||||
}, [textareaRef]);
|
||||
setLineHeight(detectedLineHeight);
|
||||
setPaddingTop(detectedPaddingTop);
|
||||
setPaddingBottom(detectedPaddingBottom);
|
||||
}
|
||||
}, [textareaRef]);
|
||||
|
||||
useEffect(() => {
|
||||
adjustTextareaHeight();
|
||||
}, [value, maxRows, lineHeight, paddingTop, paddingBottom]);
|
||||
useEffect(() => {
|
||||
adjustTextareaHeight();
|
||||
}, [value, maxRows, lineHeight, paddingTop, paddingBottom]);
|
||||
|
||||
const inputValue = value ?? internalValue;
|
||||
const inputValue = value ?? internalValue;
|
||||
|
||||
return (
|
||||
<textarea
|
||||
className={clsx("multiline-input", className)}
|
||||
ref={textareaRef}
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={onKeyDown}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
placeholder={placeholder}
|
||||
maxLength={maxLength}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
rows={rows}
|
||||
style={{
|
||||
overflowY:
|
||||
textareaRef.current &&
|
||||
textareaRef.current.scrollHeight > maxRows * lineHeight + paddingTop + paddingBottom
|
||||
? "auto"
|
||||
: "hidden",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
)
|
||||
return (
|
||||
<textarea
|
||||
className={clsx("multiline-input", className)}
|
||||
ref={textareaRef}
|
||||
value={inputValue}
|
||||
onChange={handleInputChange}
|
||||
onKeyDown={onKeyDown}
|
||||
onFocus={handleFocus}
|
||||
onBlur={handleBlur}
|
||||
placeholder={placeholder}
|
||||
maxLength={maxLength}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
rows={rows}
|
||||
style={{
|
||||
overflowY:
|
||||
textareaRef.current &&
|
||||
textareaRef.current.scrollHeight > maxRows * lineHeight + paddingTop + paddingBottom
|
||||
? "auto"
|
||||
: "hidden",
|
||||
}}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { MultiLineInput };
|
||||
|
@ -18,8 +18,8 @@ import clsx from "clsx";
|
||||
import {
|
||||
Children,
|
||||
cloneElement,
|
||||
forwardRef,
|
||||
isValidElement,
|
||||
JSX,
|
||||
JSXElementConstructor,
|
||||
memo,
|
||||
ReactElement,
|
||||
@ -36,6 +36,7 @@ interface PopoverProps {
|
||||
offset?: OffsetOptions;
|
||||
onDismiss?: () => void;
|
||||
middleware?: Middleware[];
|
||||
ref?: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const isPopoverButton = (
|
||||
@ -51,67 +52,65 @@ const isPopoverContent = (
|
||||
};
|
||||
|
||||
const Popover = memo(
|
||||
forwardRef<HTMLDivElement, PopoverProps>(
|
||||
({ children, className, placement = "bottom-start", offset = 3, onDismiss, middleware }, ref) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
({ children, className, placement = "bottom-start", offset = 3, onDismiss, middleware, ref }: PopoverProps) => {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setIsOpen(open);
|
||||
if (!open && onDismiss) {
|
||||
onDismiss();
|
||||
}
|
||||
};
|
||||
|
||||
if (offset === undefined) {
|
||||
offset = 3;
|
||||
const handleOpenChange = (open: boolean) => {
|
||||
setIsOpen(open);
|
||||
if (!open && onDismiss) {
|
||||
onDismiss();
|
||||
}
|
||||
};
|
||||
|
||||
middleware ??= [];
|
||||
middleware.push(offsetMiddleware(offset));
|
||||
|
||||
const { refs, floatingStyles, context } = useFloating({
|
||||
placement,
|
||||
open: isOpen,
|
||||
onOpenChange: handleOpenChange,
|
||||
middleware: middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
});
|
||||
|
||||
const click = useClick(context);
|
||||
const dismiss = useDismiss(context);
|
||||
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss]);
|
||||
|
||||
const renderChildren = Children.map(children, (child) => {
|
||||
if (isValidElement(child)) {
|
||||
if (isPopoverButton(child)) {
|
||||
return cloneElement(child as any, {
|
||||
isActive: isOpen,
|
||||
ref: refs.setReference,
|
||||
getReferenceProps,
|
||||
// Do not overwrite onClick
|
||||
});
|
||||
}
|
||||
|
||||
if (isPopoverContent(child)) {
|
||||
return isOpen
|
||||
? cloneElement(child as any, {
|
||||
ref: refs.setFloating,
|
||||
style: floatingStyles,
|
||||
getFloatingProps,
|
||||
})
|
||||
: null;
|
||||
}
|
||||
}
|
||||
return child;
|
||||
});
|
||||
|
||||
return (
|
||||
<div ref={ref} className={clsx("popover", className)}>
|
||||
{renderChildren}
|
||||
</div>
|
||||
);
|
||||
if (offset === undefined) {
|
||||
offset = 3;
|
||||
}
|
||||
)
|
||||
|
||||
middleware ??= [];
|
||||
middleware.push(offsetMiddleware(offset));
|
||||
|
||||
const { refs, floatingStyles, context } = useFloating({
|
||||
placement,
|
||||
open: isOpen,
|
||||
onOpenChange: handleOpenChange,
|
||||
middleware: middleware,
|
||||
whileElementsMounted: autoUpdate,
|
||||
});
|
||||
|
||||
const click = useClick(context);
|
||||
const dismiss = useDismiss(context);
|
||||
const { getReferenceProps, getFloatingProps } = useInteractions([click, dismiss]);
|
||||
|
||||
const renderChildren = Children.map(children, (child) => {
|
||||
if (isValidElement(child)) {
|
||||
if (isPopoverButton(child)) {
|
||||
return cloneElement(child as any, {
|
||||
isActive: isOpen,
|
||||
ref: refs.setReference,
|
||||
getReferenceProps,
|
||||
// Do not overwrite onClick
|
||||
});
|
||||
}
|
||||
|
||||
if (isPopoverContent(child)) {
|
||||
return isOpen
|
||||
? cloneElement(child as any, {
|
||||
ref: refs.setFloating,
|
||||
style: floatingStyles,
|
||||
getFloatingProps,
|
||||
})
|
||||
: null;
|
||||
}
|
||||
}
|
||||
return child;
|
||||
});
|
||||
|
||||
return (
|
||||
<div ref={ref} className={clsx("popover", className)}>
|
||||
{renderChildren}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
Popover.displayName = "Popover";
|
||||
@ -121,72 +120,68 @@ interface PopoverButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElemen
|
||||
children: React.ReactNode;
|
||||
getReferenceProps?: () => any;
|
||||
as?: keyof JSX.IntrinsicElements | React.ComponentType<any>;
|
||||
ref?: React.RefObject<HTMLButtonElement | HTMLInputElement>;
|
||||
}
|
||||
|
||||
const PopoverButton = forwardRef<HTMLButtonElement | HTMLDivElement, PopoverButtonProps>(
|
||||
(
|
||||
{
|
||||
isActive,
|
||||
children,
|
||||
onClick: userOnClick, // Destructured from props
|
||||
getReferenceProps,
|
||||
className,
|
||||
as: Component = "button",
|
||||
...props // The rest of the props, without onClick
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const referenceProps = getReferenceProps?.() || {};
|
||||
const popoverOnClick = referenceProps.onClick;
|
||||
const PopoverButton = ({
|
||||
isActive,
|
||||
children,
|
||||
onClick: userOnClick, // Destructured from props
|
||||
getReferenceProps,
|
||||
className,
|
||||
as: Component = "button",
|
||||
ref,
|
||||
...props // The rest of the props, without onClick
|
||||
}: PopoverButtonProps) => {
|
||||
const referenceProps = getReferenceProps?.() || {};
|
||||
const popoverOnClick = referenceProps.onClick;
|
||||
|
||||
// Remove onClick from referenceProps to prevent it from overwriting our combinedOnClick
|
||||
const { onClick: refOnClick, ...restReferenceProps } = referenceProps;
|
||||
// Remove onClick from referenceProps to prevent it from overwriting our combinedOnClick
|
||||
const { onClick: refOnClick, ...restReferenceProps } = referenceProps;
|
||||
|
||||
const combinedOnClick = (event: React.MouseEvent) => {
|
||||
if (userOnClick) {
|
||||
userOnClick(event as any); // Our custom onClick logic
|
||||
}
|
||||
if (popoverOnClick) {
|
||||
popoverOnClick(event); // Popover's onClick logic
|
||||
}
|
||||
};
|
||||
const combinedOnClick = (event: React.MouseEvent) => {
|
||||
if (userOnClick) {
|
||||
userOnClick(event as any); // Our custom onClick logic
|
||||
}
|
||||
if (popoverOnClick) {
|
||||
popoverOnClick(event); // Popover's onClick logic
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
className={clsx("popover-button", className, { "is-active": isActive })}
|
||||
{...props} // Spread the rest of the props
|
||||
{...restReferenceProps} // Spread referenceProps without onClick
|
||||
onClick={combinedOnClick} // Assign combined onClick after spreading
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
);
|
||||
return (
|
||||
<Button
|
||||
ref={ref}
|
||||
className={clsx("popover-button", className, { "is-active": isActive })}
|
||||
{...props} // Spread the rest of the props
|
||||
{...restReferenceProps} // Spread referenceProps without onClick
|
||||
onClick={combinedOnClick} // Assign combined onClick after spreading
|
||||
>
|
||||
{children}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
interface PopoverContentProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
children: React.ReactNode;
|
||||
getFloatingProps?: () => any;
|
||||
ref?: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const PopoverContent = forwardRef<HTMLDivElement, PopoverContentProps>(
|
||||
({ children, className, getFloatingProps, style, ...props }, ref) => {
|
||||
return (
|
||||
<FloatingPortal>
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx("popover-content", className)}
|
||||
style={style}
|
||||
{...getFloatingProps?.()}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</FloatingPortal>
|
||||
);
|
||||
}
|
||||
);
|
||||
const PopoverContent = ({ children, className, getFloatingProps, style, ref, ...props }: PopoverContentProps) => {
|
||||
return (
|
||||
<FloatingPortal>
|
||||
<div
|
||||
ref={ref}
|
||||
className={clsx("popover-content", className)}
|
||||
style={style}
|
||||
{...getFloatingProps?.()}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</FloatingPortal>
|
||||
);
|
||||
};
|
||||
|
||||
Popover.displayName = "Popover";
|
||||
PopoverButton.displayName = "PopoverButton";
|
||||
|
@ -2,7 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
import { clsx } from "clsx";
|
||||
import React, { forwardRef } from "react";
|
||||
import React from "react";
|
||||
|
||||
import "./windowdrag.scss";
|
||||
|
||||
@ -10,14 +10,15 @@ interface WindowDragProps {
|
||||
className?: string;
|
||||
style?: React.CSSProperties;
|
||||
children?: React.ReactNode;
|
||||
ref: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const WindowDrag = forwardRef<HTMLDivElement, WindowDragProps>(({ children, className, style }, ref) => {
|
||||
const WindowDrag = ({ children, className, style, ref }: WindowDragProps) => {
|
||||
return (
|
||||
<div ref={ref} className={clsx(`window-drag`, className)} style={style}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export { WindowDrag };
|
||||
|
@ -3,7 +3,6 @@
|
||||
|
||||
import { Button } from "@/app/element/button";
|
||||
import clsx from "clsx";
|
||||
import { forwardRef } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import "./modal.scss";
|
||||
@ -17,36 +16,45 @@ interface ModalProps {
|
||||
onOk?: () => void;
|
||||
onCancel?: () => void;
|
||||
onClose?: () => void;
|
||||
ref?: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const Modal = forwardRef<HTMLDivElement, ModalProps>(
|
||||
({ children, className, cancelLabel, okLabel, onCancel, onOk, onClose, onClickBackdrop }: ModalProps, ref) => {
|
||||
const renderBackdrop = (onClick) => <div className="modal-backdrop" onClick={onClick}></div>;
|
||||
const Modal = ({
|
||||
children,
|
||||
className,
|
||||
cancelLabel,
|
||||
okLabel,
|
||||
onCancel,
|
||||
onOk,
|
||||
onClose,
|
||||
onClickBackdrop,
|
||||
ref,
|
||||
}: ModalProps) => {
|
||||
const renderBackdrop = (onClick) => <div className="modal-backdrop" onClick={onClick}></div>;
|
||||
|
||||
const renderFooter = () => {
|
||||
return onOk || onCancel;
|
||||
};
|
||||
const renderFooter = () => {
|
||||
return onOk || onCancel;
|
||||
};
|
||||
|
||||
const renderModal = () => (
|
||||
<div className="modal-wrapper">
|
||||
{renderBackdrop(onClickBackdrop)}
|
||||
<div ref={ref} className={clsx(`modal`, className)}>
|
||||
<Button className="grey ghost modal-close-btn" onClick={onClose} title="Close (ESC)">
|
||||
<i className="fa-sharp fa-solid fa-xmark"></i>
|
||||
</Button>
|
||||
<div className="content-wrapper">
|
||||
<ModalContent>{children}</ModalContent>
|
||||
</div>
|
||||
{renderFooter() && (
|
||||
<ModalFooter onCancel={onCancel} onOk={onOk} cancelLabel={cancelLabel} okLabel={okLabel} />
|
||||
)}
|
||||
const renderModal = () => (
|
||||
<div className="modal-wrapper">
|
||||
{renderBackdrop(onClickBackdrop)}
|
||||
<div ref={ref} className={clsx(`modal`, className)}>
|
||||
<Button className="grey ghost modal-close-btn" onClick={onClose} title="Close (ESC)">
|
||||
<i className="fa-sharp fa-solid fa-xmark"></i>
|
||||
</Button>
|
||||
<div className="content-wrapper">
|
||||
<ModalContent>{children}</ModalContent>
|
||||
</div>
|
||||
{renderFooter() && (
|
||||
<ModalFooter onCancel={onCancel} onOk={onOk} cancelLabel={cancelLabel} okLabel={okLabel} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
);
|
||||
|
||||
return ReactDOM.createPortal(renderModal(), document.getElementById("main"));
|
||||
}
|
||||
);
|
||||
return ReactDOM.createPortal(renderModal(), document.getElementById("main"));
|
||||
};
|
||||
|
||||
interface ModalContentProps {
|
||||
children: React.ReactNode;
|
||||
@ -80,30 +88,28 @@ interface FlexiModalProps {
|
||||
children?: React.ReactNode;
|
||||
className?: string;
|
||||
onClickBackdrop?: () => void;
|
||||
ref: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
interface FlexiModalComponent
|
||||
extends React.ForwardRefExoticComponent<FlexiModalProps & React.RefAttributes<HTMLDivElement>> {
|
||||
interface FlexiModalComponent extends React.FC<FlexiModalProps> {
|
||||
Content: typeof ModalContent;
|
||||
Footer: typeof ModalFooter;
|
||||
}
|
||||
|
||||
const FlexiModal = forwardRef<HTMLDivElement, FlexiModalProps>(
|
||||
({ children, className, onClickBackdrop }: FlexiModalProps, ref) => {
|
||||
const renderBackdrop = (onClick: () => void) => <div className="modal-backdrop" onClick={onClick}></div>;
|
||||
const FlexiModal = ({ children, className, onClickBackdrop, ref }: FlexiModalProps) => {
|
||||
const renderBackdrop = (onClick: () => void) => <div className="modal-backdrop" onClick={onClick}></div>;
|
||||
|
||||
const renderModal = () => (
|
||||
<div className="modal-wrapper">
|
||||
{renderBackdrop(onClickBackdrop)}
|
||||
<div className={`modal ${className}`} ref={ref}>
|
||||
{children}
|
||||
</div>
|
||||
const renderModal = () => (
|
||||
<div className="modal-wrapper">
|
||||
{renderBackdrop(onClickBackdrop)}
|
||||
<div className={`modal ${className}`} ref={ref}>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
</div>
|
||||
);
|
||||
|
||||
return ReactDOM.createPortal(renderModal(), document.getElementById("main")!);
|
||||
}
|
||||
);
|
||||
return ReactDOM.createPortal(renderModal(), document.getElementById("main")!);
|
||||
};
|
||||
|
||||
(FlexiModal as FlexiModalComponent).Content = ModalContent;
|
||||
(FlexiModal as FlexiModalComponent).Footer = ModalFooter;
|
||||
|
@ -5,7 +5,7 @@ import { Input, InputGroup, InputRightElement } from "@/app/element/input";
|
||||
import { useDimensionsWithExistingRef } from "@/app/hook/useDimensions";
|
||||
import { makeIconClass } from "@/util/util";
|
||||
import clsx from "clsx";
|
||||
import React, { forwardRef, useLayoutEffect, useRef } from "react";
|
||||
import React, { useLayoutEffect, useRef } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
|
||||
import "./typeaheadmodal.scss";
|
||||
@ -14,62 +14,60 @@ interface SuggestionsProps {
|
||||
suggestions?: SuggestionsType[];
|
||||
onSelect?: (_: string) => void;
|
||||
selectIndex: number;
|
||||
ref: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const Suggestions = forwardRef<HTMLDivElement, SuggestionsProps>(
|
||||
({ suggestions, onSelect, selectIndex }: SuggestionsProps, ref) => {
|
||||
const renderIcon = (icon: string | React.ReactNode, color: string) => {
|
||||
if (typeof icon === "string") {
|
||||
return <i className={makeIconClass(icon, false)} style={{ color: color }}></i>;
|
||||
}
|
||||
return icon;
|
||||
};
|
||||
const Suggestions = ({ suggestions, onSelect, selectIndex, ref }: SuggestionsProps) => {
|
||||
const renderIcon = (icon: string | React.ReactNode, color: string) => {
|
||||
if (typeof icon === "string") {
|
||||
return <i className={makeIconClass(icon, false)} style={{ color: color }}></i>;
|
||||
}
|
||||
return icon;
|
||||
};
|
||||
|
||||
const renderItem = (item: SuggestionBaseItem | SuggestionConnectionItem, index: number) => (
|
||||
<div
|
||||
key={index}
|
||||
onClick={() => {
|
||||
if ("onSelect" in item && item.onSelect) {
|
||||
item.onSelect(item.value);
|
||||
} else {
|
||||
onSelect(item.value);
|
||||
}
|
||||
}}
|
||||
className={clsx("suggestion-item", { selected: selectIndex === index })}
|
||||
>
|
||||
<div className="typeahead-item-name">
|
||||
{item.icon &&
|
||||
renderIcon(item.icon, "iconColor" in item && item.iconColor ? item.iconColor : "inherit")}
|
||||
{item.label}
|
||||
</div>
|
||||
{"current" in item && item.current && (
|
||||
<i className={clsx(makeIconClass("check", false), "typeahead-current-checkbox")} />
|
||||
)}
|
||||
const renderItem = (item: SuggestionBaseItem | SuggestionConnectionItem, index: number) => (
|
||||
<div
|
||||
key={index}
|
||||
onClick={() => {
|
||||
if ("onSelect" in item && item.onSelect) {
|
||||
item.onSelect(item.value);
|
||||
} else {
|
||||
onSelect(item.value);
|
||||
}
|
||||
}}
|
||||
className={clsx("suggestion-item", { selected: selectIndex === index })}
|
||||
>
|
||||
<div className="typeahead-item-name">
|
||||
{item.icon && renderIcon(item.icon, "iconColor" in item && item.iconColor ? item.iconColor : "inherit")}
|
||||
{item.label}
|
||||
</div>
|
||||
);
|
||||
{"current" in item && item.current && (
|
||||
<i className={clsx(makeIconClass("check", false), "typeahead-current-checkbox")} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
let fullIndex = -1;
|
||||
return (
|
||||
<div ref={ref} className="suggestions">
|
||||
{suggestions.map((item, index) => {
|
||||
if ("headerText" in item) {
|
||||
return (
|
||||
<div key={index}>
|
||||
{item.headerText && <div className="suggestion-header">{item.headerText}</div>}
|
||||
{item.items.map((subItem, subIndex) => {
|
||||
fullIndex += 1;
|
||||
return renderItem(subItem, fullIndex);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
fullIndex += 1;
|
||||
return renderItem(item as SuggestionBaseItem, fullIndex);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
let fullIndex = -1;
|
||||
return (
|
||||
<div ref={ref} className="suggestions">
|
||||
{suggestions.map((item, index) => {
|
||||
if ("headerText" in item) {
|
||||
return (
|
||||
<div key={index}>
|
||||
{item.headerText && <div className="suggestion-header">{item.headerText}</div>}
|
||||
{item.items.map((subItem, subIndex) => {
|
||||
fullIndex += 1;
|
||||
return renderItem(subItem, fullIndex);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
fullIndex += 1;
|
||||
return renderItem(item as SuggestionBaseItem, fullIndex);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
interface TypeAheadModalProps {
|
||||
anchorRef: React.RefObject<HTMLElement>;
|
||||
|
@ -13,7 +13,7 @@ import "./userinputmodal.scss";
|
||||
const UserInputModal = (userInputRequest: UserInputRequest) => {
|
||||
const [responseText, setResponseText] = useState("");
|
||||
const [countdown, setCountdown] = useState(Math.floor(userInputRequest.timeoutms / 1000));
|
||||
const checkboxRef = useRef<HTMLInputElement>();
|
||||
const checkboxRef = useRef<HTMLInputElement>(null);
|
||||
|
||||
const handleSendErrResponse = useCallback(() => {
|
||||
fireAndForget(() =>
|
||||
|
@ -8,7 +8,7 @@ import { Button } from "@/element/button";
|
||||
import { ContextMenuModel } from "@/store/contextmenu";
|
||||
import { fireAndForget } from "@/util/util";
|
||||
import { clsx } from "clsx";
|
||||
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import { memo, useCallback, useEffect, useImperativeHandle, useRef, useState } from "react";
|
||||
import { ObjectService } from "../store/services";
|
||||
import { makeORef, useWaveObjectValue } from "../store/wos";
|
||||
import "./tab.scss";
|
||||
@ -27,226 +27,223 @@ interface TabProps {
|
||||
onDragStart: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
|
||||
onLoaded: () => void;
|
||||
onPinChange: () => void;
|
||||
ref: React.RefObject<HTMLDivElement>;
|
||||
}
|
||||
|
||||
const Tab = memo(
|
||||
forwardRef<HTMLDivElement, TabProps>(
|
||||
(
|
||||
{
|
||||
id,
|
||||
active,
|
||||
isPinned,
|
||||
isBeforeActive,
|
||||
isDragging,
|
||||
tabWidth,
|
||||
isNew,
|
||||
onLoaded,
|
||||
onSelect,
|
||||
onClose,
|
||||
onDragStart,
|
||||
onPinChange,
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [tabData, _] = useWaveObjectValue<Tab>(makeORef("tab", id));
|
||||
const [originalName, setOriginalName] = useState("");
|
||||
const [isEditable, setIsEditable] = useState(false);
|
||||
({
|
||||
id,
|
||||
active,
|
||||
isPinned,
|
||||
isBeforeActive,
|
||||
isDragging,
|
||||
tabWidth,
|
||||
isNew,
|
||||
onLoaded,
|
||||
onSelect,
|
||||
onClose,
|
||||
onDragStart,
|
||||
onPinChange,
|
||||
ref,
|
||||
}: TabProps) => {
|
||||
const [tabData, _] = useWaveObjectValue<Tab>(makeORef("tab", id));
|
||||
const [originalName, setOriginalName] = useState("");
|
||||
const [isEditable, setIsEditable] = useState(false);
|
||||
|
||||
const editableRef = useRef<HTMLDivElement>(null);
|
||||
const editableTimeoutRef = useRef<NodeJS.Timeout>();
|
||||
const loadedRef = useRef(false);
|
||||
const tabRef = useRef<HTMLDivElement>(null);
|
||||
const editableRef = useRef<HTMLDivElement>(null);
|
||||
const editableTimeoutRef = useRef<NodeJS.Timeout>(null);
|
||||
const loadedRef = useRef(false);
|
||||
const tabRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
useImperativeHandle(ref, () => tabRef.current as HTMLDivElement);
|
||||
useImperativeHandle(ref, () => tabRef.current as HTMLDivElement);
|
||||
|
||||
useEffect(() => {
|
||||
if (tabData?.name) {
|
||||
setOriginalName(tabData.name);
|
||||
}
|
||||
}, [tabData]);
|
||||
useEffect(() => {
|
||||
if (tabData?.name) {
|
||||
setOriginalName(tabData.name);
|
||||
}
|
||||
}, [tabData]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (editableTimeoutRef.current) {
|
||||
clearTimeout(editableTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
const selectEditableText = useCallback(() => {
|
||||
if (editableRef.current) {
|
||||
const range = document.createRange();
|
||||
const selection = window.getSelection();
|
||||
range.selectNodeContents(editableRef.current);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleRenameTab: React.MouseEventHandler<HTMLDivElement> = (event) => {
|
||||
event?.stopPropagation();
|
||||
setIsEditable(true);
|
||||
editableTimeoutRef.current = setTimeout(() => {
|
||||
selectEditableText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
const handleBlur = () => {
|
||||
let newText = editableRef.current.innerText.trim();
|
||||
newText = newText || originalName;
|
||||
editableRef.current.innerText = newText;
|
||||
setIsEditable(false);
|
||||
fireAndForget(() => ObjectService.UpdateTabName(id, newText));
|
||||
setTimeout(() => refocusNode(null), 10);
|
||||
};
|
||||
|
||||
const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key === "a") {
|
||||
event.preventDefault();
|
||||
selectEditableText();
|
||||
return;
|
||||
}
|
||||
// this counts glyphs, not characters
|
||||
const curLen = Array.from(editableRef.current.innerText).length;
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (editableRef.current.innerText.trim() === "") {
|
||||
editableRef.current.innerText = originalName;
|
||||
}
|
||||
editableRef.current.blur();
|
||||
} else if (event.key === "Escape") {
|
||||
editableRef.current.innerText = originalName;
|
||||
editableRef.current.blur();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else if (curLen >= 14 && !["Backspace", "Delete", "ArrowLeft", "ArrowRight"].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
if (editableTimeoutRef.current) {
|
||||
clearTimeout(editableTimeoutRef.current);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!loadedRef.current) {
|
||||
onLoaded();
|
||||
loadedRef.current = true;
|
||||
}
|
||||
}, [onLoaded]);
|
||||
const selectEditableText = useCallback(() => {
|
||||
if (editableRef.current) {
|
||||
const range = document.createRange();
|
||||
const selection = window.getSelection();
|
||||
range.selectNodeContents(editableRef.current);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (tabRef.current && isNew) {
|
||||
const initialWidth = `${(tabWidth / 3) * 2}px`;
|
||||
tabRef.current.style.setProperty("--initial-tab-width", initialWidth);
|
||||
tabRef.current.style.setProperty("--final-tab-width", `${tabWidth}px`);
|
||||
}
|
||||
}, [isNew, tabWidth]);
|
||||
const handleRenameTab: React.MouseEventHandler<HTMLDivElement> = (event) => {
|
||||
event?.stopPropagation();
|
||||
setIsEditable(true);
|
||||
editableTimeoutRef.current = setTimeout(() => {
|
||||
selectEditableText();
|
||||
}, 0);
|
||||
};
|
||||
|
||||
// Prevent drag from being triggered on mousedown
|
||||
const handleMouseDownOnClose = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
const handleBlur = () => {
|
||||
let newText = editableRef.current.innerText.trim();
|
||||
newText = newText || originalName;
|
||||
editableRef.current.innerText = newText;
|
||||
setIsEditable(false);
|
||||
fireAndForget(() => ObjectService.UpdateTabName(id, newText));
|
||||
setTimeout(() => refocusNode(null), 10);
|
||||
};
|
||||
|
||||
const handleKeyDown: React.KeyboardEventHandler<HTMLDivElement> = (event) => {
|
||||
if ((event.metaKey || event.ctrlKey) && event.key === "a") {
|
||||
event.preventDefault();
|
||||
selectEditableText();
|
||||
return;
|
||||
}
|
||||
// this counts glyphs, not characters
|
||||
const curLen = Array.from(editableRef.current.innerText).length;
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
};
|
||||
if (editableRef.current.innerText.trim() === "") {
|
||||
editableRef.current.innerText = originalName;
|
||||
}
|
||||
editableRef.current.blur();
|
||||
} else if (event.key === "Escape") {
|
||||
editableRef.current.innerText = originalName;
|
||||
editableRef.current.blur();
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
} else if (curLen >= 14 && !["Backspace", "Delete", "ArrowLeft", "ArrowRight"].includes(event.key)) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
const handleContextMenu = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
let menu: ContextMenuItem[] = [
|
||||
{ label: isPinned ? "Unpin Tab" : "Pin Tab", click: () => onPinChange() },
|
||||
{ label: "Rename Tab", click: () => handleRenameTab(null) },
|
||||
{
|
||||
label: "Copy TabId",
|
||||
click: () => fireAndForget(() => navigator.clipboard.writeText(id)),
|
||||
},
|
||||
{ type: "separator" },
|
||||
];
|
||||
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||
const bgPresets: string[] = [];
|
||||
for (const key in fullConfig?.presets ?? {}) {
|
||||
if (key.startsWith("bg@")) {
|
||||
bgPresets.push(key);
|
||||
}
|
||||
}
|
||||
bgPresets.sort((a, b) => {
|
||||
const aOrder = fullConfig.presets[a]["display:order"] ?? 0;
|
||||
const bOrder = fullConfig.presets[b]["display:order"] ?? 0;
|
||||
return aOrder - bOrder;
|
||||
});
|
||||
if (bgPresets.length > 0) {
|
||||
const submenu: ContextMenuItem[] = [];
|
||||
const oref = makeORef("tab", id);
|
||||
for (const presetName of bgPresets) {
|
||||
const preset = fullConfig.presets[presetName];
|
||||
if (preset == null) {
|
||||
continue;
|
||||
}
|
||||
submenu.push({
|
||||
label: preset["display:name"] ?? presetName,
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
await ObjectService.UpdateObjectMeta(oref, preset);
|
||||
await RpcApi.ActivityCommand(TabRpcClient, { settabtheme: 1 });
|
||||
}),
|
||||
});
|
||||
}
|
||||
menu.push({ label: "Backgrounds", type: "submenu", submenu }, { type: "separator" });
|
||||
}
|
||||
menu.push({ label: "Close Tab", click: () => onClose(null) });
|
||||
ContextMenuModel.showContextMenu(menu, e);
|
||||
},
|
||||
[onPinChange, handleRenameTab, id, onClose, isPinned]
|
||||
);
|
||||
useEffect(() => {
|
||||
if (!loadedRef.current) {
|
||||
onLoaded();
|
||||
loadedRef.current = true;
|
||||
}
|
||||
}, [onLoaded]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={tabRef}
|
||||
className={clsx("tab", {
|
||||
active,
|
||||
dragging: isDragging,
|
||||
"before-active": isBeforeActive,
|
||||
"new-tab": isNew,
|
||||
})}
|
||||
onMouseDown={onDragStart}
|
||||
onClick={onSelect}
|
||||
onContextMenu={handleContextMenu}
|
||||
data-tab-id={id}
|
||||
>
|
||||
<div className="tab-inner">
|
||||
<div
|
||||
ref={editableRef}
|
||||
className={clsx("name", { focused: isEditable })}
|
||||
contentEditable={isEditable}
|
||||
onDoubleClick={handleRenameTab}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
suppressContentEditableWarning={true}
|
||||
>
|
||||
{tabData?.name}
|
||||
</div>
|
||||
{isPinned ? (
|
||||
<Button
|
||||
className="ghost grey pin"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onPinChange();
|
||||
}}
|
||||
title="Unpin Tab"
|
||||
>
|
||||
<i className="fa fa-solid fa-thumbtack" />
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
className="ghost grey close"
|
||||
onClick={onClose}
|
||||
onMouseDown={handleMouseDownOnClose}
|
||||
title="Close Tab"
|
||||
>
|
||||
<i className="fa fa-solid fa-xmark" />
|
||||
</Button>
|
||||
)}
|
||||
useEffect(() => {
|
||||
if (tabRef.current && isNew) {
|
||||
const initialWidth = `${(tabWidth / 3) * 2}px`;
|
||||
tabRef.current.style.setProperty("--initial-tab-width", initialWidth);
|
||||
tabRef.current.style.setProperty("--final-tab-width", `${tabWidth}px`);
|
||||
}
|
||||
}, [isNew, tabWidth]);
|
||||
|
||||
// Prevent drag from being triggered on mousedown
|
||||
const handleMouseDownOnClose = (event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => {
|
||||
event.stopPropagation();
|
||||
};
|
||||
|
||||
const handleContextMenu = useCallback(
|
||||
(e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
|
||||
e.preventDefault();
|
||||
let menu: ContextMenuItem[] = [
|
||||
{ label: isPinned ? "Unpin Tab" : "Pin Tab", click: () => onPinChange() },
|
||||
{ label: "Rename Tab", click: () => handleRenameTab(null) },
|
||||
{
|
||||
label: "Copy TabId",
|
||||
click: () => fireAndForget(() => navigator.clipboard.writeText(id)),
|
||||
},
|
||||
{ type: "separator" },
|
||||
];
|
||||
const fullConfig = globalStore.get(atoms.fullConfigAtom);
|
||||
const bgPresets: string[] = [];
|
||||
for (const key in fullConfig?.presets ?? {}) {
|
||||
if (key.startsWith("bg@")) {
|
||||
bgPresets.push(key);
|
||||
}
|
||||
}
|
||||
bgPresets.sort((a, b) => {
|
||||
const aOrder = fullConfig.presets[a]["display:order"] ?? 0;
|
||||
const bOrder = fullConfig.presets[b]["display:order"] ?? 0;
|
||||
return aOrder - bOrder;
|
||||
});
|
||||
if (bgPresets.length > 0) {
|
||||
const submenu: ContextMenuItem[] = [];
|
||||
const oref = makeORef("tab", id);
|
||||
for (const presetName of bgPresets) {
|
||||
const preset = fullConfig.presets[presetName];
|
||||
if (preset == null) {
|
||||
continue;
|
||||
}
|
||||
submenu.push({
|
||||
label: preset["display:name"] ?? presetName,
|
||||
click: () =>
|
||||
fireAndForget(async () => {
|
||||
await ObjectService.UpdateObjectMeta(oref, preset);
|
||||
await RpcApi.ActivityCommand(TabRpcClient, { settabtheme: 1 });
|
||||
}),
|
||||
});
|
||||
}
|
||||
menu.push({ label: "Backgrounds", type: "submenu", submenu }, { type: "separator" });
|
||||
}
|
||||
menu.push({ label: "Close Tab", click: () => onClose(null) });
|
||||
ContextMenuModel.showContextMenu(menu, e);
|
||||
},
|
||||
[onPinChange, handleRenameTab, id, onClose, isPinned]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={tabRef}
|
||||
className={clsx("tab", {
|
||||
active,
|
||||
dragging: isDragging,
|
||||
"before-active": isBeforeActive,
|
||||
"new-tab": isNew,
|
||||
})}
|
||||
onMouseDown={onDragStart}
|
||||
onClick={onSelect}
|
||||
onContextMenu={handleContextMenu}
|
||||
data-tab-id={id}
|
||||
>
|
||||
<div className="tab-inner">
|
||||
<div
|
||||
ref={editableRef}
|
||||
className={clsx("name", { focused: isEditable })}
|
||||
contentEditable={isEditable}
|
||||
onDoubleClick={handleRenameTab}
|
||||
onBlur={handleBlur}
|
||||
onKeyDown={handleKeyDown}
|
||||
suppressContentEditableWarning={true}
|
||||
>
|
||||
{tabData?.name}
|
||||
</div>
|
||||
{isPinned ? (
|
||||
<Button
|
||||
className="ghost grey pin"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
onPinChange();
|
||||
}}
|
||||
title="Unpin Tab"
|
||||
>
|
||||
<i className="fa fa-solid fa-thumbtack" />
|
||||
</Button>
|
||||
) : (
|
||||
<Button
|
||||
className="ghost grey close"
|
||||
onClick={onClose}
|
||||
onMouseDown={handleMouseDownOnClose}
|
||||
title="Close Tab"
|
||||
>
|
||||
<i className="fa fa-solid fa-xmark" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
)
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export { Tab };
|
||||
|
@ -1,10 +1,10 @@
|
||||
import { Button } from "@/element/button";
|
||||
import { atoms, getApi } from "@/store/global";
|
||||
import { useAtomValue } from "jotai";
|
||||
import { forwardRef, memo, useEffect, useState } from "react";
|
||||
import { memo, useEffect, useState } from "react";
|
||||
import "./updatebanner.scss";
|
||||
|
||||
const UpdateStatusBannerComponent = forwardRef<HTMLButtonElement>((_, ref) => {
|
||||
const UpdateStatusBannerComponent = (ref: React.RefObject<HTMLButtonElement>) => {
|
||||
const appUpdateStatus = useAtomValue(atoms.updaterStatusAtom);
|
||||
let [updateStatusMessage, setUpdateStatusMessage] = useState<string>();
|
||||
const [dismissBannerTimeout, setDismissBannerTimeout] = useState<NodeJS.Timeout>();
|
||||
@ -65,6 +65,6 @@ const UpdateStatusBannerComponent = forwardRef<HTMLButtonElement>((_, ref) => {
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const UpdateStatusBanner = memo(UpdateStatusBannerComponent) as typeof UpdateStatusBannerComponent;
|
||||
|
@ -15,7 +15,7 @@ import clsx from "clsx";
|
||||
import { atom, PrimitiveAtom, useAtom, useAtomValue, useSetAtom } from "jotai";
|
||||
import { splitAtom } from "jotai/utils";
|
||||
import { OverlayScrollbarsComponent } from "overlayscrollbars-react";
|
||||
import { CSSProperties, forwardRef, useCallback, useEffect } from "react";
|
||||
import { CSSProperties, useCallback, useEffect } from "react";
|
||||
import WorkspaceSVG from "../asset/workspace.svg";
|
||||
import { IconButton } from "../element/iconbutton";
|
||||
import { atoms, getApi } from "../store/global";
|
||||
@ -34,7 +34,7 @@ type WorkspaceList = WorkspaceListEntry[];
|
||||
const workspaceMapAtom = atom<WorkspaceList>([]);
|
||||
const workspaceSplitAtom = splitAtom(workspaceMapAtom);
|
||||
const editingWorkspaceAtom = atom<string>();
|
||||
const WorkspaceSwitcher = forwardRef<HTMLDivElement>((_, ref) => {
|
||||
const WorkspaceSwitcher = (ref: React.RefObject<HTMLDivElement>) => {
|
||||
const setWorkspaceList = useSetAtom(workspaceMapAtom);
|
||||
const activeWorkspace = useAtomValueSafe(atoms.workspace);
|
||||
const workspaceList = useAtomValue(workspaceSplitAtom);
|
||||
@ -136,7 +136,7 @@ const WorkspaceSwitcher = forwardRef<HTMLDivElement>((_, ref) => {
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const WorkspaceSwitcherItem = ({
|
||||
entryAtom,
|
||||
|
@ -32,7 +32,7 @@ function evalAsync(Plot: any, d3: any, funcText: string): Promise<unknown> {
|
||||
}
|
||||
|
||||
function PlotView() {
|
||||
const containerRef = React.useRef<HTMLInputElement>();
|
||||
const containerRef = React.useRef<HTMLInputElement>(null);
|
||||
const [plotDef, setPlotDef] = React.useState<string>();
|
||||
const [savedDef, setSavedDef] = React.useState<string>();
|
||||
const [modalUp, setModalUp] = React.useState(false);
|
||||
|
@ -193,7 +193,14 @@ const CSVView = ({ parentRef, filename, content }: CSVViewProps) => {
|
||||
</thead>
|
||||
<tbody style={{ height: `${state.tbodyHeight}px` }} ref={tbodyRef}>
|
||||
{table.getRowModel().rows.map((row, index) => (
|
||||
<tr key={row.id} ref={(el) => (rowRef.current[index] = el)} id={row.id} tabIndex={index}>
|
||||
<tr
|
||||
key={row.id}
|
||||
ref={(el) => {
|
||||
rowRef.current[index] = el;
|
||||
}}
|
||||
id={row.id}
|
||||
tabIndex={index}
|
||||
>
|
||||
{row.getVisibleCells().map((cell) => (
|
||||
<td key={cell.id} id={cell.id} tabIndex={index}>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
|
@ -143,7 +143,7 @@ enum EntryManagerType {
|
||||
}
|
||||
|
||||
type EntryManagerOverlayProps = {
|
||||
forwardRef?: React.Ref<HTMLDivElement>;
|
||||
ref?: React.Ref<HTMLDivElement>;
|
||||
entryManagerType: EntryManagerType;
|
||||
startingValue?: string;
|
||||
onSave: (newValue: string) => void;
|
||||
@ -158,13 +158,13 @@ const EntryManagerOverlay = memo(
|
||||
startingValue,
|
||||
onSave,
|
||||
onCancel,
|
||||
forwardRef,
|
||||
ref,
|
||||
style,
|
||||
getReferenceProps,
|
||||
}: EntryManagerOverlayProps) => {
|
||||
const [value, setValue] = useState(startingValue);
|
||||
return (
|
||||
<div className="entry-manager-overlay" ref={forwardRef} style={style} {...getReferenceProps()}>
|
||||
<div className="entry-manager-overlay" ref={ref} style={style} {...getReferenceProps()}>
|
||||
<div className="entry-manager-type">{entryManagerType}</div>
|
||||
<div className="entry-manager-input">
|
||||
<Input
|
||||
@ -358,8 +358,8 @@ function DirectoryTable({
|
||||
return colSizes;
|
||||
}, [table.getState().columnSizingInfo]);
|
||||
|
||||
const osRef = useRef<OverlayScrollbarsComponentRef>();
|
||||
const bodyRef = useRef<HTMLDivElement>();
|
||||
const osRef = useRef<OverlayScrollbarsComponentRef>(null);
|
||||
const bodyRef = useRef<HTMLDivElement>(null);
|
||||
const [scrollHeight, setScrollHeight] = useState(0);
|
||||
|
||||
const onScroll = useCallback(
|
||||
@ -472,8 +472,8 @@ function TableBody({
|
||||
setRefreshVersion,
|
||||
osRef,
|
||||
}: TableBodyProps) {
|
||||
const dummyLineRef = useRef<HTMLDivElement>();
|
||||
const warningBoxRef = useRef<HTMLDivElement>();
|
||||
const dummyLineRef = useRef<HTMLDivElement>(null);
|
||||
const warningBoxRef = useRef<HTMLDivElement>(null);
|
||||
const rowRefs = useRef<HTMLDivElement[]>([]);
|
||||
const conn = useAtomValue(model.connection);
|
||||
|
||||
@ -632,7 +632,9 @@ function TableBody({
|
||||
const displayRow = useCallback(
|
||||
(row: Row<FileInfo>, idx: number) => (
|
||||
<div
|
||||
ref={(el) => (rowRefs.current[idx] = el)}
|
||||
ref={(el) => {
|
||||
rowRefs.current[idx] = el;
|
||||
}}
|
||||
className={clsx("dir-table-body-row", { focused: focusIndex === idx })}
|
||||
key={row.id}
|
||||
onDoubleClick={() => {
|
||||
@ -914,7 +916,7 @@ function DirectoryPreview({ model }: DirectoryPreviewProps) {
|
||||
{entryManagerProps && (
|
||||
<EntryManagerOverlay
|
||||
{...entryManagerProps}
|
||||
forwardRef={refs.setFloating}
|
||||
ref={refs.setFloating}
|
||||
style={floatingStyles}
|
||||
getReferenceProps={getFloatingProps}
|
||||
onCancel={() => setEntryManagerProps(undefined)}
|
||||
|
@ -409,7 +409,7 @@ function SingleLinePlot({
|
||||
sparkline = false,
|
||||
targetLen,
|
||||
}: SingleLinePlotProps) {
|
||||
const containerRef = React.useRef<HTMLInputElement>();
|
||||
const containerRef = React.useRef<HTMLInputElement>(null);
|
||||
const domRect = useDimensionsWithExistingRef(containerRef, 300);
|
||||
const plotHeight = domRect?.height ?? 0;
|
||||
const plotWidth = domRect?.width ?? 0;
|
||||
@ -521,7 +521,7 @@ const SysinfoViewInner = React.memo(({ model }: SysinfoViewProps) => {
|
||||
const plotData = jotai.useAtomValue(model.dataAtom);
|
||||
const yvals = jotai.useAtomValue(model.metrics);
|
||||
const plotMeta = jotai.useAtomValue(model.plotMetaAtom);
|
||||
const osRef = React.useRef<OverlayScrollbarsComponentRef>();
|
||||
const osRef = React.useRef<OverlayScrollbarsComponentRef>(null);
|
||||
const targetLen = jotai.useAtomValue(model.numPoints) + 1;
|
||||
let title = false;
|
||||
let cols2 = false;
|
||||
|
@ -16,6 +16,7 @@ import {
|
||||
validateAndWrapCss,
|
||||
validateAndWrapReactStyle,
|
||||
} from "@/app/view/vdom/vdom-utils";
|
||||
import { JSX } from "react";
|
||||
import "./vdom.scss";
|
||||
|
||||
const TextTag = "#text";
|
||||
|
@ -16,7 +16,7 @@ import { atom, Atom, PrimitiveAtom, useAtomValue, WritableAtom } from "jotai";
|
||||
import { splitAtom } from "jotai/utils";
|
||||
import type { OverlayScrollbars } from "overlayscrollbars";
|
||||
import { OverlayScrollbarsComponent, OverlayScrollbarsComponentRef } from "overlayscrollbars-react";
|
||||
import { forwardRef, memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
||||
import { memo, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState } from "react";
|
||||
import { debounce, throttle } from "throttle-debounce";
|
||||
import "./waveai.scss";
|
||||
|
||||
@ -508,108 +508,107 @@ interface ChatWindowProps {
|
||||
chatWindowRef: React.RefObject<HTMLDivElement>;
|
||||
msgWidths: Object;
|
||||
model: WaveAiModel;
|
||||
ref: React.RefObject<OverlayScrollbarsComponentRef>;
|
||||
}
|
||||
|
||||
const ChatWindow = memo(
|
||||
forwardRef<OverlayScrollbarsComponentRef, ChatWindowProps>(({ chatWindowRef, msgWidths, model }, ref) => {
|
||||
const isUserScrolling = useRef(false);
|
||||
const osRef = useRef<OverlayScrollbarsComponentRef>(null);
|
||||
const splitMessages = useAtomValue(model.messagesSplitAtom) as Atom<ChatMessageType>[];
|
||||
const latestMessage = useAtomValue(model.latestMessageAtom);
|
||||
const prevMessagesLenRef = useRef(splitMessages.length);
|
||||
const ChatWindow = memo(({ chatWindowRef, msgWidths, model, ref }: ChatWindowProps) => {
|
||||
const isUserScrolling = useRef(false);
|
||||
const osRef = useRef<OverlayScrollbarsComponentRef>(null);
|
||||
const splitMessages = useAtomValue(model.messagesSplitAtom) as Atom<ChatMessageType>[];
|
||||
const latestMessage = useAtomValue(model.latestMessageAtom);
|
||||
const prevMessagesLenRef = useRef(splitMessages.length);
|
||||
|
||||
useImperativeHandle(ref, () => osRef.current as OverlayScrollbarsComponentRef);
|
||||
useImperativeHandle(ref, () => osRef.current as OverlayScrollbarsComponentRef);
|
||||
|
||||
const handleNewMessage = useCallback(
|
||||
throttle(100, (messagesLen: number) => {
|
||||
if (osRef.current?.osInstance()) {
|
||||
console.log("handleNewMessage", messagesLen, isUserScrolling.current);
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
if (prevMessagesLenRef.current !== messagesLen || !isUserScrolling.current) {
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
}
|
||||
|
||||
prevMessagesLenRef.current = messagesLen;
|
||||
}
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
handleNewMessage(splitMessages.length);
|
||||
}, [splitMessages, latestMessage]);
|
||||
|
||||
// Wait 300 ms after the user stops scrolling to determine if the user is within 300px of the bottom of the chat window.
|
||||
// If so, unset the user scrolling flag.
|
||||
const determineUnsetScroll = useCallback(
|
||||
debounce(300, () => {
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
if (viewport.scrollTop > chatWindowRef.current?.clientHeight - viewport.clientHeight - 100) {
|
||||
isUserScrolling.current = false;
|
||||
}
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const handleUserScroll = useCallback(
|
||||
throttle(100, () => {
|
||||
isUserScrolling.current = true;
|
||||
determineUnsetScroll();
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const handleNewMessage = useCallback(
|
||||
throttle(100, (messagesLen: number) => {
|
||||
if (osRef.current?.osInstance()) {
|
||||
console.log("handleNewMessage", messagesLen, isUserScrolling.current);
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
if (prevMessagesLenRef.current !== messagesLen || !isUserScrolling.current) {
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
}
|
||||
|
||||
viewport.addEventListener("wheel", handleUserScroll, { passive: true });
|
||||
viewport.addEventListener("touchmove", handleUserScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
viewport.removeEventListener("wheel", handleUserScroll);
|
||||
viewport.removeEventListener("touchmove", handleUserScroll);
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
osRef.current.osInstance().destroy();
|
||||
}
|
||||
};
|
||||
prevMessagesLenRef.current = messagesLen;
|
||||
}
|
||||
}, []);
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
const handleScrollbarInitialized = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
handleNewMessage(splitMessages.length);
|
||||
}, [splitMessages, latestMessage]);
|
||||
|
||||
const handleScrollbarUpdated = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
};
|
||||
// Wait 300 ms after the user stops scrolling to determine if the user is within 300px of the bottom of the chat window.
|
||||
// If so, unset the user scrolling flag.
|
||||
const determineUnsetScroll = useCallback(
|
||||
debounce(300, () => {
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
if (viewport.scrollTop > chatWindowRef.current?.clientHeight - viewport.clientHeight - 100) {
|
||||
isUserScrolling.current = false;
|
||||
}
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<OverlayScrollbarsComponent
|
||||
ref={osRef}
|
||||
className="chat-window-container"
|
||||
options={{ scrollbars: { autoHide: "leave" } }}
|
||||
events={{ initialized: handleScrollbarInitialized, updated: handleScrollbarUpdated }}
|
||||
>
|
||||
<div ref={chatWindowRef} className="chat-window" style={msgWidths}>
|
||||
<div className="filler"></div>
|
||||
{splitMessages.map((chitem, idx) => (
|
||||
<ChatItem key={idx} chatItemAtom={chitem} model={model} />
|
||||
))}
|
||||
</div>
|
||||
</OverlayScrollbarsComponent>
|
||||
);
|
||||
})
|
||||
);
|
||||
const handleUserScroll = useCallback(
|
||||
throttle(100, () => {
|
||||
isUserScrolling.current = true;
|
||||
determineUnsetScroll();
|
||||
}),
|
||||
[]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (osRef.current?.osInstance()) {
|
||||
const { viewport } = osRef.current.osInstance().elements();
|
||||
|
||||
viewport.addEventListener("wheel", handleUserScroll, { passive: true });
|
||||
viewport.addEventListener("touchmove", handleUserScroll, { passive: true });
|
||||
|
||||
return () => {
|
||||
viewport.removeEventListener("wheel", handleUserScroll);
|
||||
viewport.removeEventListener("touchmove", handleUserScroll);
|
||||
if (osRef.current && osRef.current.osInstance()) {
|
||||
osRef.current.osInstance().destroy();
|
||||
}
|
||||
};
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleScrollbarInitialized = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
viewport.scrollTo({
|
||||
behavior: "auto",
|
||||
top: chatWindowRef.current?.scrollHeight || 0,
|
||||
});
|
||||
};
|
||||
|
||||
const handleScrollbarUpdated = (instance: OverlayScrollbars) => {
|
||||
const { viewport } = instance.elements();
|
||||
viewport.removeAttribute("tabindex");
|
||||
};
|
||||
|
||||
return (
|
||||
<OverlayScrollbarsComponent
|
||||
ref={osRef}
|
||||
className="chat-window-container"
|
||||
options={{ scrollbars: { autoHide: "leave" } }}
|
||||
events={{ initialized: handleScrollbarInitialized, updated: handleScrollbarUpdated }}
|
||||
>
|
||||
<div ref={chatWindowRef} className="chat-window" style={msgWidths}>
|
||||
<div className="filler"></div>
|
||||
{splitMessages.map((chitem, idx) => (
|
||||
<ChatItem key={idx} chatItemAtom={chitem} model={model} />
|
||||
))}
|
||||
</div>
|
||||
</OverlayScrollbarsComponent>
|
||||
);
|
||||
});
|
||||
|
||||
interface ChatInputProps {
|
||||
value: string;
|
||||
@ -618,63 +617,62 @@ interface ChatInputProps {
|
||||
onKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
|
||||
onMouseDown: (e: React.MouseEvent<HTMLTextAreaElement>) => void;
|
||||
model: WaveAiModel;
|
||||
ref: React.RefObject<HTMLTextAreaElement>;
|
||||
}
|
||||
|
||||
const ChatInput = forwardRef<HTMLTextAreaElement, ChatInputProps>(
|
||||
({ value, onChange, onKeyDown, onMouseDown, baseFontSize, model }, ref) => {
|
||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||
const ChatInput = ({ value, onChange, onKeyDown, onMouseDown, baseFontSize, model, ref }: ChatInputProps) => {
|
||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||
|
||||
useImperativeHandle(ref, () => textAreaRef.current as HTMLTextAreaElement);
|
||||
useImperativeHandle(ref, () => textAreaRef.current as HTMLTextAreaElement);
|
||||
|
||||
useEffect(() => {
|
||||
model.textAreaRef = textAreaRef;
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
model.textAreaRef = textAreaRef;
|
||||
}, []);
|
||||
|
||||
const adjustTextAreaHeight = useCallback(
|
||||
(value: string) => {
|
||||
if (textAreaRef.current == null) {
|
||||
return;
|
||||
}
|
||||
const adjustTextAreaHeight = useCallback(
|
||||
(value: string) => {
|
||||
if (textAreaRef.current == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Adjust the height of the textarea to fit the text
|
||||
const textAreaMaxLines = 5;
|
||||
const textAreaLineHeight = baseFontSize * 1.5;
|
||||
const textAreaMinHeight = textAreaLineHeight;
|
||||
const textAreaMaxHeight = textAreaLineHeight * textAreaMaxLines;
|
||||
|
||||
if (value === "") {
|
||||
textAreaRef.current.style.height = `${textAreaLineHeight}px`;
|
||||
return;
|
||||
}
|
||||
// Adjust the height of the textarea to fit the text
|
||||
const textAreaMaxLines = 5;
|
||||
const textAreaLineHeight = baseFontSize * 1.5;
|
||||
const textAreaMinHeight = textAreaLineHeight;
|
||||
const textAreaMaxHeight = textAreaLineHeight * textAreaMaxLines;
|
||||
|
||||
if (value === "") {
|
||||
textAreaRef.current.style.height = `${textAreaLineHeight}px`;
|
||||
const scrollHeight = textAreaRef.current.scrollHeight;
|
||||
const newHeight = Math.min(Math.max(scrollHeight, textAreaMinHeight), textAreaMaxHeight);
|
||||
textAreaRef.current.style.height = newHeight + "px";
|
||||
},
|
||||
[baseFontSize]
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
adjustTextAreaHeight(value);
|
||||
}, [value]);
|
||||
textAreaRef.current.style.height = `${textAreaLineHeight}px`;
|
||||
const scrollHeight = textAreaRef.current.scrollHeight;
|
||||
const newHeight = Math.min(Math.max(scrollHeight, textAreaMinHeight), textAreaMaxHeight);
|
||||
textAreaRef.current.style.height = newHeight + "px";
|
||||
},
|
||||
[baseFontSize]
|
||||
);
|
||||
|
||||
return (
|
||||
<textarea
|
||||
ref={textAreaRef}
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="waveai-input"
|
||||
onMouseDown={onMouseDown} // When the user clicks on the textarea
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
style={{ fontSize: baseFontSize }}
|
||||
placeholder="Ask anything..."
|
||||
value={value}
|
||||
></textarea>
|
||||
);
|
||||
}
|
||||
);
|
||||
useEffect(() => {
|
||||
adjustTextAreaHeight(value);
|
||||
}, [value]);
|
||||
|
||||
return (
|
||||
<textarea
|
||||
ref={textAreaRef}
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
className="waveai-input"
|
||||
onMouseDown={onMouseDown} // When the user clicks on the textarea
|
||||
onChange={onChange}
|
||||
onKeyDown={onKeyDown}
|
||||
style={{ fontSize: baseFontSize }}
|
||||
placeholder="Ask anything..."
|
||||
value={value}
|
||||
></textarea>
|
||||
);
|
||||
};
|
||||
|
||||
const WaveAi = ({ model }: { model: WaveAiModel; blockId: string }) => {
|
||||
const { sendMessage } = model.useWaveAi();
|
||||
|
16
package.json
16
package.json
@ -29,7 +29,7 @@
|
||||
"devDependencies": {
|
||||
"@chromatic-com/storybook": "^3.2.2",
|
||||
"@eslint/js": "^9.16.0",
|
||||
"@rollup/plugin-node-resolve": "^15.3.0",
|
||||
"@rollup/plugin-node-resolve": "^16.0.0",
|
||||
"@storybook/addon-essentials": "^8.4.7",
|
||||
"@storybook/addon-interactions": "^8.4.7",
|
||||
"@storybook/addon-links": "^8.4.7",
|
||||
@ -47,8 +47,8 @@
|
||||
"@types/papaparse": "^5",
|
||||
"@types/pngjs": "^6.0.5",
|
||||
"@types/prop-types": "^15",
|
||||
"@types/react": "^18.3.13",
|
||||
"@types/react-dom": "^18.3.1",
|
||||
"@types/react": "^19.0.2",
|
||||
"@types/react-dom": "^19.0.2",
|
||||
"@types/semver": "^7",
|
||||
"@types/shell-quote": "^1",
|
||||
"@types/sprintf-js": "^1",
|
||||
@ -75,8 +75,8 @@
|
||||
"tslib": "^2.8.1",
|
||||
"tsx": "^4.19.2",
|
||||
"typescript": "^5.7.2",
|
||||
"typescript-eslint": "^8.18.0",
|
||||
"vite": "^6.0.3",
|
||||
"typescript-eslint": "^8.18.2",
|
||||
"vite": "^6.0.6",
|
||||
"vite-plugin-image-optimizer": "^1.1.8",
|
||||
"vite-plugin-static-copy": "^2.2.0",
|
||||
"vite-plugin-svgr": "^4.3.0",
|
||||
@ -84,7 +84,7 @@
|
||||
"vitest": "^2.1.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@floating-ui/react": "^0.26.28",
|
||||
"@floating-ui/react": "^0.27.2",
|
||||
"@monaco-editor/loader": "^1.4.0",
|
||||
"@monaco-editor/react": "^4.6.0",
|
||||
"@observablehq/plot": "^0.6.16",
|
||||
@ -119,10 +119,10 @@
|
||||
"parse-srcset": "^1.0.2",
|
||||
"pngjs": "^7.0.0",
|
||||
"prop-types": "^15.8.1",
|
||||
"react": "^18.3.1",
|
||||
"react": "^19.0.0",
|
||||
"react-dnd": "^16.0.1",
|
||||
"react-dnd-html5-backend": "^16.0.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-frame-component": "^5.2.7",
|
||||
"react-gauge-chart": "^0.5.1",
|
||||
"react-markdown": "^9.0.1",
|
||||
|
479
yarn.lock
479
yarn.lock
@ -3181,6 +3181,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/aix-ppc64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/aix-ppc64@npm:0.24.2"
|
||||
conditions: os=aix & cpu=ppc64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/android-arm64@npm:0.21.5"
|
||||
@ -3202,6 +3209,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/android-arm64@npm:0.24.2"
|
||||
conditions: os=android & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/android-arm@npm:0.21.5"
|
||||
@ -3223,6 +3237,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-arm@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/android-arm@npm:0.24.2"
|
||||
conditions: os=android & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/android-x64@npm:0.21.5"
|
||||
@ -3244,6 +3265,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/android-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/android-x64@npm:0.24.2"
|
||||
conditions: os=android & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-arm64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/darwin-arm64@npm:0.21.5"
|
||||
@ -3265,6 +3293,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-arm64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/darwin-arm64@npm:0.24.2"
|
||||
conditions: os=darwin & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/darwin-x64@npm:0.21.5"
|
||||
@ -3286,6 +3321,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/darwin-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/darwin-x64@npm:0.24.2"
|
||||
conditions: os=darwin & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-arm64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/freebsd-arm64@npm:0.21.5"
|
||||
@ -3307,6 +3349,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-arm64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/freebsd-arm64@npm:0.24.2"
|
||||
conditions: os=freebsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/freebsd-x64@npm:0.21.5"
|
||||
@ -3328,6 +3377,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/freebsd-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/freebsd-x64@npm:0.24.2"
|
||||
conditions: os=freebsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-arm64@npm:0.21.5"
|
||||
@ -3349,6 +3405,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-arm64@npm:0.24.2"
|
||||
conditions: os=linux & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-arm@npm:0.21.5"
|
||||
@ -3370,6 +3433,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-arm@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-arm@npm:0.24.2"
|
||||
conditions: os=linux & cpu=arm
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ia32@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-ia32@npm:0.21.5"
|
||||
@ -3391,6 +3461,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ia32@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-ia32@npm:0.24.2"
|
||||
conditions: os=linux & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-loong64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-loong64@npm:0.21.5"
|
||||
@ -3412,6 +3489,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-loong64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-loong64@npm:0.24.2"
|
||||
conditions: os=linux & cpu=loong64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-mips64el@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-mips64el@npm:0.21.5"
|
||||
@ -3433,6 +3517,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-mips64el@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-mips64el@npm:0.24.2"
|
||||
conditions: os=linux & cpu=mips64el
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ppc64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-ppc64@npm:0.21.5"
|
||||
@ -3454,6 +3545,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-ppc64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-ppc64@npm:0.24.2"
|
||||
conditions: os=linux & cpu=ppc64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-riscv64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-riscv64@npm:0.21.5"
|
||||
@ -3475,6 +3573,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-riscv64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-riscv64@npm:0.24.2"
|
||||
conditions: os=linux & cpu=riscv64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-s390x@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-s390x@npm:0.21.5"
|
||||
@ -3496,6 +3601,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-s390x@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-s390x@npm:0.24.2"
|
||||
conditions: os=linux & cpu=s390x
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/linux-x64@npm:0.21.5"
|
||||
@ -3517,6 +3629,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/linux-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/linux-x64@npm:0.24.2"
|
||||
conditions: os=linux & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/netbsd-arm64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/netbsd-arm64@npm:0.24.2"
|
||||
conditions: os=netbsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/netbsd-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/netbsd-x64@npm:0.21.5"
|
||||
@ -3538,6 +3664,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/netbsd-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/netbsd-x64@npm:0.24.2"
|
||||
conditions: os=netbsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-arm64@npm:0.23.1":
|
||||
version: 0.23.1
|
||||
resolution: "@esbuild/openbsd-arm64@npm:0.23.1"
|
||||
@ -3552,6 +3685,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-arm64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/openbsd-arm64@npm:0.24.2"
|
||||
conditions: os=openbsd & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/openbsd-x64@npm:0.21.5"
|
||||
@ -3573,6 +3713,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/openbsd-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/openbsd-x64@npm:0.24.2"
|
||||
conditions: os=openbsd & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/sunos-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/sunos-x64@npm:0.21.5"
|
||||
@ -3594,6 +3741,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/sunos-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/sunos-x64@npm:0.24.2"
|
||||
conditions: os=sunos & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-arm64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/win32-arm64@npm:0.21.5"
|
||||
@ -3615,6 +3769,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-arm64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/win32-arm64@npm:0.24.2"
|
||||
conditions: os=win32 & cpu=arm64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-ia32@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/win32-ia32@npm:0.21.5"
|
||||
@ -3636,6 +3797,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-ia32@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/win32-ia32@npm:0.24.2"
|
||||
conditions: os=win32 & cpu=ia32
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-x64@npm:0.21.5":
|
||||
version: 0.21.5
|
||||
resolution: "@esbuild/win32-x64@npm:0.21.5"
|
||||
@ -3657,6 +3825,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@esbuild/win32-x64@npm:0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "@esbuild/win32-x64@npm:0.24.2"
|
||||
conditions: os=win32 & cpu=x64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@eslint-community/eslint-utils@npm:^4.2.0, @eslint-community/eslint-utils@npm:^4.4.0":
|
||||
version: 4.4.1
|
||||
resolution: "@eslint-community/eslint-utils@npm:4.4.1"
|
||||
@ -3764,17 +3939,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@floating-ui/react@npm:^0.26.28":
|
||||
version: 0.26.28
|
||||
resolution: "@floating-ui/react@npm:0.26.28"
|
||||
"@floating-ui/react@npm:^0.27.2":
|
||||
version: 0.27.2
|
||||
resolution: "@floating-ui/react@npm:0.27.2"
|
||||
dependencies:
|
||||
"@floating-ui/react-dom": "npm:^2.1.2"
|
||||
"@floating-ui/utils": "npm:^0.2.8"
|
||||
tabbable: "npm:^6.0.0"
|
||||
peerDependencies:
|
||||
react: ">=16.8.0"
|
||||
react-dom: ">=16.8.0"
|
||||
checksum: 10c0/a42df129e1e976fe8ba3f4c8efdda265a0196c1b66b83f2b9b27423d08dcc765406f893aeff9d830e70e3f14a9d4c490867eb4c32983317cbaa33863b0fae6f6
|
||||
react: ">=17.0.0"
|
||||
react-dom: ">=17.0.0"
|
||||
checksum: 10c0/7de7810b501422a12e4d4089042dc8ab9de8a95f53003a4a5e2b25fd8b2ee0dddcfab996a26558ec4614c2e15ce1b68d2e06f188bec55de7346c904610d50837
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -4803,9 +4978,9 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@rollup/plugin-node-resolve@npm:^15.3.0":
|
||||
version: 15.3.0
|
||||
resolution: "@rollup/plugin-node-resolve@npm:15.3.0"
|
||||
"@rollup/plugin-node-resolve@npm:^16.0.0":
|
||||
version: 16.0.0
|
||||
resolution: "@rollup/plugin-node-resolve@npm:16.0.0"
|
||||
dependencies:
|
||||
"@rollup/pluginutils": "npm:^5.0.1"
|
||||
"@types/resolve": "npm:1.20.2"
|
||||
@ -4817,7 +4992,7 @@ __metadata:
|
||||
peerDependenciesMeta:
|
||||
rollup:
|
||||
optional: true
|
||||
checksum: 10c0/5f3b11f9f6d00fe9fd3fe1977cc71f6a99c2b13d0ee82ad6822c4c4ecfc98854791c5a505798762f7e2332d9d67568a561e89aa8268ed3b1668563be1845109e
|
||||
checksum: 10c0/b63deb6fc14b37070ccaffacc8c10c9720f28ce7632f4fe2ee77064c0c79bcc3fe060fb77160e673c9fd847307252f25a2983030bd54f1888324063c69ae1399
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -6522,12 +6697,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react-dom@npm:^18.3.1":
|
||||
version: 18.3.1
|
||||
resolution: "@types/react-dom@npm:18.3.1"
|
||||
dependencies:
|
||||
"@types/react": "npm:*"
|
||||
checksum: 10c0/8b416551c60bb6bd8ec10e198c957910cfb271bc3922463040b0d57cf4739cdcd24b13224f8d68f10318926e1ec3cd69af0af79f0291b599a992f8c80d47f1eb
|
||||
"@types/react-dom@npm:^19.0.2":
|
||||
version: 19.0.2
|
||||
resolution: "@types/react-dom@npm:19.0.2"
|
||||
peerDependencies:
|
||||
"@types/react": ^19.0.0
|
||||
checksum: 10c0/3d0c7b78dbe8df64ea769f30af990a5950173a8321c745fe11094d765423f7964c3519dca6e7cd36b4be6521c8efc690bdd3b79b327b229dd1e9d5a8bad677dd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -6573,13 +6748,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:^18.3.13":
|
||||
version: 18.3.13
|
||||
resolution: "@types/react@npm:18.3.13"
|
||||
"@types/react@npm:^19.0.2":
|
||||
version: 19.0.2
|
||||
resolution: "@types/react@npm:19.0.2"
|
||||
dependencies:
|
||||
"@types/prop-types": "npm:*"
|
||||
csstype: "npm:^3.0.2"
|
||||
checksum: 10c0/91815e00157deb179fa670aa2dfc491952698b7743ffddca0e3e0f16e7a18454f3f5ef72321a07386c49e721563b9d280dbbdfae039face764e2fdd8ad949d4b
|
||||
checksum: 10c0/8992f39701fcf1bf893ef8f94a56196445667baf08fe4f6050a14e229a17aad3265ad3efc01595ff3b4d5d5c69da885f9aa4ff80f164a613018734efcff1eb8f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -6793,15 +6967,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/eslint-plugin@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.18.0"
|
||||
"@typescript-eslint/eslint-plugin@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/eslint-plugin@npm:8.18.2"
|
||||
dependencies:
|
||||
"@eslint-community/regexpp": "npm:^4.10.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.18.0"
|
||||
"@typescript-eslint/type-utils": "npm:8.18.0"
|
||||
"@typescript-eslint/utils": "npm:8.18.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.18.2"
|
||||
"@typescript-eslint/type-utils": "npm:8.18.2"
|
||||
"@typescript-eslint/utils": "npm:8.18.2"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.2"
|
||||
graphemer: "npm:^1.4.0"
|
||||
ignore: "npm:^5.3.1"
|
||||
natural-compare: "npm:^1.4.0"
|
||||
@ -6810,64 +6984,64 @@ __metadata:
|
||||
"@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/c338da1b96c41d7b94401a6711659d0fef3acb691eff7a958f9d3aa0442a858830daad67e3575288a4f4669572e2b690517a513519b404a465ad68fe0a82d3ec
|
||||
checksum: 10c0/ce854835a12747cd8efea5b70921e1a80b62af2a2d311b09343862a6af225b821a6729784547d37eb5f8eb286d1f086f41f305445adc3a054e37cc8c71561ccd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/parser@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/parser@npm:8.18.0"
|
||||
"@typescript-eslint/parser@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/parser@npm:8.18.2"
|
||||
dependencies:
|
||||
"@typescript-eslint/scope-manager": "npm:8.18.0"
|
||||
"@typescript-eslint/types": "npm:8.18.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.18.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.18.2"
|
||||
"@typescript-eslint/types": "npm:8.18.2"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.18.2"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.2"
|
||||
debug: "npm:^4.3.4"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/d3a062511c24dfcf522a645db1153022d49aa3bb05e288c22474cf04dc1d836f877eb9d2733947e448981ffb16e4de50d4ebe7570a268733a641f228ca6c4849
|
||||
checksum: 10c0/ea28130e0a2733e3e40708ddfbb7b6522d9644e49cae2c3dc3faddd7ac7e7f73ed9775f19463ca0deca55edb52f5d9d522c206bb2a14fe3c9c6eef03d144b41f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/scope-manager@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.18.0"
|
||||
"@typescript-eslint/scope-manager@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/scope-manager@npm:8.18.2"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.18.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.0"
|
||||
checksum: 10c0/6bf6532fd43f2b55b9b47fa8b0217c5b5a03f022e869a6a21228fc3ae04c0ac6c5ae5d6026866d189ba424d2f98cc6fbd2a34f909d241c9b86c031afd808f90c
|
||||
"@typescript-eslint/types": "npm:8.18.2"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.2"
|
||||
checksum: 10c0/2c05f5361e84d687555717bfb15988d5c11601c1094edeaafc8db5c961359982d7aeb192d775d348ab65ac43c5a6c968f3e8503ee1e6bf875aca27588907139f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/type-utils@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.18.0"
|
||||
"@typescript-eslint/type-utils@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/type-utils@npm:8.18.2"
|
||||
dependencies:
|
||||
"@typescript-eslint/typescript-estree": "npm:8.18.0"
|
||||
"@typescript-eslint/utils": "npm:8.18.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.18.2"
|
||||
"@typescript-eslint/utils": "npm:8.18.2"
|
||||
debug: "npm:^4.3.4"
|
||||
ts-api-utils: "npm:^1.3.0"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/c0fcf201c3b53f9374c0571198a639c81536170141caa08fd0f47094a596b1f82f839a849eac5832f954345c567dccb45b2ee1c0872c513331165f7bcb812396
|
||||
checksum: 10c0/0441ca33f7381abae559e188bd7b2844159806e8bf5ab8d6f6d9b3a7a6bf9f9d0babf8452e83565da0e9841f656b25f44fd96f40bda1006c934535e37a997c6a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/types@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/types@npm:8.18.0"
|
||||
checksum: 10c0/2dd7468c3f1c305545268b72c3a333488e6ab1b628c5f65081d895866422b9376c21634a7aac437805f84b22e352b6a8fc4dcf925ef4a8fd7d1898b8359f71be
|
||||
"@typescript-eslint/types@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/types@npm:8.18.2"
|
||||
checksum: 10c0/4abf252671dd7c3a5c9b7ae2f523d91b04d937dbb601f3bc0182c234d50e4958be67248c1bb37833584ff0128844243145753614c7e80615b6cd6813f0713872
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/typescript-estree@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.18.0"
|
||||
"@typescript-eslint/typescript-estree@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/typescript-estree@npm:8.18.2"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.18.0"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.0"
|
||||
"@typescript-eslint/types": "npm:8.18.2"
|
||||
"@typescript-eslint/visitor-keys": "npm:8.18.2"
|
||||
debug: "npm:^4.3.4"
|
||||
fast-glob: "npm:^3.3.2"
|
||||
is-glob: "npm:^4.0.3"
|
||||
@ -6876,32 +7050,32 @@ __metadata:
|
||||
ts-api-utils: "npm:^1.3.0"
|
||||
peerDependencies:
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/87b432b190b627314f007b17b2371898db78baaa3df67a0d9a94d080d88a7a307906b54a735084cacef37f6421e2b9c3320040617e73fe54eac2bf22c610f1ec
|
||||
checksum: 10c0/648296d6c95d80d37bdb5ee6662554af425ff85f1c4805ea344234a1c386c91a36b05cddf52c80264912b29693d3e1b9a45d84414a3aee1393ace2d0babc9e95
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/utils@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/utils@npm:8.18.0"
|
||||
"@typescript-eslint/utils@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/utils@npm:8.18.2"
|
||||
dependencies:
|
||||
"@eslint-community/eslint-utils": "npm:^4.4.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.18.0"
|
||||
"@typescript-eslint/types": "npm:8.18.0"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.18.0"
|
||||
"@typescript-eslint/scope-manager": "npm:8.18.2"
|
||||
"@typescript-eslint/types": "npm:8.18.2"
|
||||
"@typescript-eslint/typescript-estree": "npm:8.18.2"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/58a2fc1e404d1f905c2a958d995824eb4abc6e73836b186717550677f8b1d17954acc369feddb83277350915388bc3d8b721423c37777b8b8017fc29c89ec6ee
|
||||
checksum: 10c0/1cb86e2e4f4e29cbaebe4272c15d98f6193b1476f65dd028d77bf4fd09e715b01d82619509c466b95056148db8d3e04f0a3ef27dc2f034a7c7ab4b2d429e58bb
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@typescript-eslint/visitor-keys@npm:8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.18.0"
|
||||
"@typescript-eslint/visitor-keys@npm:8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "@typescript-eslint/visitor-keys@npm:8.18.2"
|
||||
dependencies:
|
||||
"@typescript-eslint/types": "npm:8.18.0"
|
||||
"@typescript-eslint/types": "npm:8.18.2"
|
||||
eslint-visitor-keys: "npm:^4.2.0"
|
||||
checksum: 10c0/d4cdc2adab553098b5be7117fb7df76fb66cfd380528881a0a8c2a9eee03bf8baddda07d15ca0bd3ed8b35c379b3f449292183df18e3e81898dbcadafcb708b8
|
||||
checksum: 10c0/b8fe05bc3bafa7930d6671c2e1807ae47788060eb573e6a000c9597690dfaff6a4eb9f6f934719a18bae631d238ca32847510aeecc61032170e58ab45244e869
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -10711,7 +10885,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0, esbuild@npm:^0.24.0":
|
||||
"esbuild@npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0":
|
||||
version: 0.24.0
|
||||
resolution: "esbuild@npm:0.24.0"
|
||||
dependencies:
|
||||
@ -10874,6 +11048,92 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"esbuild@npm:^0.24.2":
|
||||
version: 0.24.2
|
||||
resolution: "esbuild@npm:0.24.2"
|
||||
dependencies:
|
||||
"@esbuild/aix-ppc64": "npm:0.24.2"
|
||||
"@esbuild/android-arm": "npm:0.24.2"
|
||||
"@esbuild/android-arm64": "npm:0.24.2"
|
||||
"@esbuild/android-x64": "npm:0.24.2"
|
||||
"@esbuild/darwin-arm64": "npm:0.24.2"
|
||||
"@esbuild/darwin-x64": "npm:0.24.2"
|
||||
"@esbuild/freebsd-arm64": "npm:0.24.2"
|
||||
"@esbuild/freebsd-x64": "npm:0.24.2"
|
||||
"@esbuild/linux-arm": "npm:0.24.2"
|
||||
"@esbuild/linux-arm64": "npm:0.24.2"
|
||||
"@esbuild/linux-ia32": "npm:0.24.2"
|
||||
"@esbuild/linux-loong64": "npm:0.24.2"
|
||||
"@esbuild/linux-mips64el": "npm:0.24.2"
|
||||
"@esbuild/linux-ppc64": "npm:0.24.2"
|
||||
"@esbuild/linux-riscv64": "npm:0.24.2"
|
||||
"@esbuild/linux-s390x": "npm:0.24.2"
|
||||
"@esbuild/linux-x64": "npm:0.24.2"
|
||||
"@esbuild/netbsd-arm64": "npm:0.24.2"
|
||||
"@esbuild/netbsd-x64": "npm:0.24.2"
|
||||
"@esbuild/openbsd-arm64": "npm:0.24.2"
|
||||
"@esbuild/openbsd-x64": "npm:0.24.2"
|
||||
"@esbuild/sunos-x64": "npm:0.24.2"
|
||||
"@esbuild/win32-arm64": "npm:0.24.2"
|
||||
"@esbuild/win32-ia32": "npm:0.24.2"
|
||||
"@esbuild/win32-x64": "npm:0.24.2"
|
||||
dependenciesMeta:
|
||||
"@esbuild/aix-ppc64":
|
||||
optional: true
|
||||
"@esbuild/android-arm":
|
||||
optional: true
|
||||
"@esbuild/android-arm64":
|
||||
optional: true
|
||||
"@esbuild/android-x64":
|
||||
optional: true
|
||||
"@esbuild/darwin-arm64":
|
||||
optional: true
|
||||
"@esbuild/darwin-x64":
|
||||
optional: true
|
||||
"@esbuild/freebsd-arm64":
|
||||
optional: true
|
||||
"@esbuild/freebsd-x64":
|
||||
optional: true
|
||||
"@esbuild/linux-arm":
|
||||
optional: true
|
||||
"@esbuild/linux-arm64":
|
||||
optional: true
|
||||
"@esbuild/linux-ia32":
|
||||
optional: true
|
||||
"@esbuild/linux-loong64":
|
||||
optional: true
|
||||
"@esbuild/linux-mips64el":
|
||||
optional: true
|
||||
"@esbuild/linux-ppc64":
|
||||
optional: true
|
||||
"@esbuild/linux-riscv64":
|
||||
optional: true
|
||||
"@esbuild/linux-s390x":
|
||||
optional: true
|
||||
"@esbuild/linux-x64":
|
||||
optional: true
|
||||
"@esbuild/netbsd-arm64":
|
||||
optional: true
|
||||
"@esbuild/netbsd-x64":
|
||||
optional: true
|
||||
"@esbuild/openbsd-arm64":
|
||||
optional: true
|
||||
"@esbuild/openbsd-x64":
|
||||
optional: true
|
||||
"@esbuild/sunos-x64":
|
||||
optional: true
|
||||
"@esbuild/win32-arm64":
|
||||
optional: true
|
||||
"@esbuild/win32-ia32":
|
||||
optional: true
|
||||
"@esbuild/win32-x64":
|
||||
optional: true
|
||||
bin:
|
||||
esbuild: bin/esbuild
|
||||
checksum: 10c0/5a25bb08b6ba23db6e66851828d848bd3ff87c005a48c02d83e38879058929878a6baa5a414e1141faee0d1dece3f32b5fbc2a87b82ed6a7aa857cf40359aeb5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"esbuild@npm:~0.23.0":
|
||||
version: 0.23.1
|
||||
resolution: "esbuild@npm:0.23.1"
|
||||
@ -17805,7 +18065,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0, react-dom@npm:^18.0.0, react-dom@npm:^18.3.1":
|
||||
"react-dom@npm:^16.8.0 || ^17.0.0 || ^18.0.0":
|
||||
version: 18.3.1
|
||||
resolution: "react-dom@npm:18.3.1"
|
||||
dependencies:
|
||||
@ -17817,6 +18077,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-dom@npm:^19.0.0":
|
||||
version: 19.0.0
|
||||
resolution: "react-dom@npm:19.0.0"
|
||||
dependencies:
|
||||
scheduler: "npm:^0.25.0"
|
||||
peerDependencies:
|
||||
react: ^19.0.0
|
||||
checksum: 10c0/a36ce7ab507b237ae2759c984cdaad4af4096d8199fb65b3815c16825e5cfeb7293da790a3fc2184b52bfba7ba3ff31c058c01947aff6fd1a3701632aabaa6a9
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react-error-overlay@npm:^6.0.11":
|
||||
version: 6.0.11
|
||||
resolution: "react-error-overlay@npm:6.0.11"
|
||||
@ -18019,7 +18290,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:^16.8.0 || ^17.0.0 || ^18.0.0, react@npm:^18.0.0, react@npm:^18.3.1":
|
||||
"react@npm:^16.8.0 || ^17.0.0 || ^18.0.0":
|
||||
version: 18.3.1
|
||||
resolution: "react@npm:18.3.1"
|
||||
dependencies:
|
||||
@ -18028,6 +18299,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"react@npm:^19.0.0":
|
||||
version: 19.0.0
|
||||
resolution: "react@npm:19.0.0"
|
||||
checksum: 10c0/9cad8f103e8e3a16d15cb18a0d8115d8bd9f9e1ce3420310aea381eb42aa0a4f812cf047bb5441349257a05fba8a291515691e3cb51267279b2d2c3253f38471
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"read-binary-file-arch@npm:^1.0.6":
|
||||
version: 1.0.6
|
||||
resolution: "read-binary-file-arch@npm:1.0.6"
|
||||
@ -19404,6 +19682,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"scheduler@npm:^0.25.0":
|
||||
version: 0.25.0
|
||||
resolution: "scheduler@npm:0.25.0"
|
||||
checksum: 10c0/a4bb1da406b613ce72c1299db43759526058fdcc413999c3c3e0db8956df7633acf395cb20eb2303b6a65d658d66b6585d344460abaee8080b4aa931f10eaafe
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"schema-utils@npm:2.7.0":
|
||||
version: 2.7.0
|
||||
resolution: "schema-utils@npm:2.7.0"
|
||||
@ -20960,17 +21245,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"typescript-eslint@npm:^8.18.0":
|
||||
version: 8.18.0
|
||||
resolution: "typescript-eslint@npm:8.18.0"
|
||||
"typescript-eslint@npm:^8.18.2":
|
||||
version: 8.18.2
|
||||
resolution: "typescript-eslint@npm:8.18.2"
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.18.0"
|
||||
"@typescript-eslint/parser": "npm:8.18.0"
|
||||
"@typescript-eslint/utils": "npm:8.18.0"
|
||||
"@typescript-eslint/eslint-plugin": "npm:8.18.2"
|
||||
"@typescript-eslint/parser": "npm:8.18.2"
|
||||
"@typescript-eslint/utils": "npm:8.18.2"
|
||||
peerDependencies:
|
||||
eslint: ^8.57.0 || ^9.0.0
|
||||
typescript: ">=4.8.4 <5.8.0"
|
||||
checksum: 10c0/dda882cbfc1ebad6903864571bc69bfd7e32e17fec67d98fdfab2bd652348d425c6a1c3697734d59cd5dd15d26d496db3c3808c1de5840fa29b9e76184fa1865
|
||||
checksum: 10c0/30a0314a2484bcbe286fc6eda55784d9954605c7e60ddd35281da90c6fcb75a40bd3abd84617814dff4e1504d762234407c99153fdd812dce712cef11bbb9b3f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -21730,11 +22015,11 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"vite@npm:^6.0.3":
|
||||
version: 6.0.3
|
||||
resolution: "vite@npm:6.0.3"
|
||||
"vite@npm:^6.0.6":
|
||||
version: 6.0.6
|
||||
resolution: "vite@npm:6.0.6"
|
||||
dependencies:
|
||||
esbuild: "npm:^0.24.0"
|
||||
esbuild: "npm:^0.24.2"
|
||||
fsevents: "npm:~2.3.3"
|
||||
postcss: "npm:^8.4.49"
|
||||
rollup: "npm:^4.23.0"
|
||||
@ -21778,7 +22063,7 @@ __metadata:
|
||||
optional: true
|
||||
bin:
|
||||
vite: bin/vite.js
|
||||
checksum: 10c0/764ebed14770426a638575b23a51127c630ace873999ab896b0184484d8107e7255cdf64cfb36c65c1ef1d583e44b70a1d14c0f05b89612e834a5806e3964475
|
||||
checksum: 10c0/144c3f80a7920a4b2fa14f00f99b58ece246455ca9313561a67a227b45dadac3343e406d3c1dbfafa79992ac88f54cb2b040b229997e432daf47594fe8cacec2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -21923,8 +22208,8 @@ __metadata:
|
||||
prettier-plugin-jsdoc: "npm:^1.3.0"
|
||||
prettier-plugin-organize-imports: "npm:^4.1.0"
|
||||
prism-react-renderer: "npm:^2.3.0"
|
||||
react: "npm:^18.0.0"
|
||||
react-dom: "npm:^18.0.0"
|
||||
react: "npm:^19.0.0"
|
||||
react-dom: "npm:^19.0.0"
|
||||
remark-cli: "npm:^12.0.1"
|
||||
remark-frontmatter: "npm:^5.0.0"
|
||||
remark-gfm: "npm:^4.0.0"
|
||||
@ -21933,7 +22218,7 @@ __metadata:
|
||||
remark-preset-lint-recommended: "npm:^7.0.0"
|
||||
remark-typescript-code-import: "npm:^1.0.1"
|
||||
typescript: "npm:^5.7.2"
|
||||
typescript-eslint: "npm:^8.18.0"
|
||||
typescript-eslint: "npm:^8.18.2"
|
||||
ua-parser-js: "npm:^2.0.0"
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@ -21944,12 +22229,12 @@ __metadata:
|
||||
dependencies:
|
||||
"@chromatic-com/storybook": "npm:^3.2.2"
|
||||
"@eslint/js": "npm:^9.16.0"
|
||||
"@floating-ui/react": "npm:^0.26.28"
|
||||
"@floating-ui/react": "npm:^0.27.2"
|
||||
"@monaco-editor/loader": "npm:^1.4.0"
|
||||
"@monaco-editor/react": "npm:^4.6.0"
|
||||
"@observablehq/plot": "npm:^0.6.16"
|
||||
"@react-hook/resize-observer": "npm:^2.0.2"
|
||||
"@rollup/plugin-node-resolve": "npm:^15.3.0"
|
||||
"@rollup/plugin-node-resolve": "npm:^16.0.0"
|
||||
"@storybook/addon-essentials": "npm:^8.4.7"
|
||||
"@storybook/addon-interactions": "npm:^8.4.7"
|
||||
"@storybook/addon-links": "npm:^8.4.7"
|
||||
@ -21970,8 +22255,8 @@ __metadata:
|
||||
"@types/papaparse": "npm:^5"
|
||||
"@types/pngjs": "npm:^6.0.5"
|
||||
"@types/prop-types": "npm:^15"
|
||||
"@types/react": "npm:^18.3.13"
|
||||
"@types/react-dom": "npm:^18.3.1"
|
||||
"@types/react": "npm:^19.0.2"
|
||||
"@types/react-dom": "npm:^19.0.2"
|
||||
"@types/semver": "npm:^7"
|
||||
"@types/shell-quote": "npm:^1"
|
||||
"@types/sprintf-js": "npm:^1"
|
||||
@ -22016,10 +22301,10 @@ __metadata:
|
||||
prettier-plugin-jsdoc: "npm:^1.3.0"
|
||||
prettier-plugin-organize-imports: "npm:^4.1.0"
|
||||
prop-types: "npm:^15.8.1"
|
||||
react: "npm:^18.3.1"
|
||||
react: "npm:^19.0.0"
|
||||
react-dnd: "npm:^16.0.1"
|
||||
react-dnd-html5-backend: "npm:^16.0.1"
|
||||
react-dom: "npm:^18.3.1"
|
||||
react-dom: "npm:^19.0.0"
|
||||
react-frame-component: "npm:^5.2.7"
|
||||
react-gauge-chart: "npm:^0.5.1"
|
||||
react-markdown: "npm:^9.0.1"
|
||||
@ -22045,9 +22330,9 @@ __metadata:
|
||||
tslib: "npm:^2.8.1"
|
||||
tsx: "npm:^4.19.2"
|
||||
typescript: "npm:^5.7.2"
|
||||
typescript-eslint: "npm:^8.18.0"
|
||||
typescript-eslint: "npm:^8.18.2"
|
||||
use-device-pixel-ratio: "npm:^1.1.2"
|
||||
vite: "npm:^6.0.3"
|
||||
vite: "npm:^6.0.6"
|
||||
vite-plugin-image-optimizer: "npm:^1.1.8"
|
||||
vite-plugin-static-copy: "npm:^2.2.0"
|
||||
vite-plugin-svgr: "npm:^4.3.0"
|
||||
|
Loading…
Reference in New Issue
Block a user