= {};
+ str.split(";").forEach((el) => {
+ const [property, value] = el.split(":");
+ if (!property) return;
+
+ const formattedProperty = formatStringToCamelCase(property.trim());
+ style[formattedProperty] = value.trim();
+ });
+ return style;
+});
+
+const DiffString = ({
+ rawLine,
+ diffLine,
+ operator,
+ plainLine,
+ enableWrap,
+}: {
+ rawLine: string;
+ diffLine?: DiffLine;
+ operator?: "add" | "del";
+ plainLine?: File["plainFile"][number];
+ enableWrap?: boolean;
+}) => {
+ const changes = diffLine?.changes;
+
+ if (changes?.hasLineChange) {
+ const isNewLineSymbolChanged = changes.newLineSymbol;
+
+ if (!diffLine?.plainTemplate && typeof getPlainDiffTemplate === "function") {
+ getPlainDiffTemplate({ diffLine: diffLine!, rawLine, operator: operator! });
+ }
+
+ if (diffLine?.plainTemplate) {
+ return (
+
+
+ {isNewLineSymbolChanged === NewLineSymbol.NEWLINE && (
+
+
+
+ )}
+
+ );
+ }
+ }
+
+ if (plainLine && !plainLine?.template) {
+ // eslint-disable-next-line react-hooks/immutability
+ plainLine.template = getPlainLineTemplate(plainLine.value);
+ }
+
+ if (plainLine?.template) {
+ return (
+
+
+
+ );
+ }
+
+ return {rawLine};
+};
+
+const DiffSyntax = ({
+ rawLine,
+ diffFile,
+ diffLine,
+ operator,
+ syntaxLine,
+ enableWrap,
+}: {
+ rawLine: string;
+ diffFile: DiffFile;
+ diffLine?: DiffLine;
+ syntaxLine?: File["syntaxFile"][number];
+ operator?: "add" | "del";
+ enableWrap?: boolean;
+}) => {
+ if (!syntaxLine) {
+ return ;
+ }
+
+ const changes = diffLine?.changes;
+
+ if (changes?.hasLineChange) {
+ const isNewLineSymbolChanged = changes.newLineSymbol;
+
+ if (!diffLine?.syntaxTemplate && typeof getSyntaxDiffTemplate === "function") {
+ getSyntaxDiffTemplate({ diffFile, diffLine: diffLine!, syntaxLine, operator: operator! });
+ }
+
+ if (diffLine?.syntaxTemplate) {
+ return (
+
+
+ {isNewLineSymbolChanged === NewLineSymbol.NEWLINE && (
+
+
+
+ )}
+
+ );
+ }
+ }
+
+ if (!syntaxLine.template) {
+ // eslint-disable-next-line react-hooks/immutability
+ syntaxLine.template = getSyntaxLineTemplate(syntaxLine);
+ }
+
+ if (syntaxLine?.template) {
+ return (
+
+
+
+ );
+ }
+
+ return (
+
+ {syntaxLine?.nodeList?.map(({ node, wrapper }, index) => (
+
+ {node.value}
+
+ ))}
+
+ );
+};
+
+export const DiffContent = ({
+ diffFile,
+ diffLine,
+ rawLine,
+ plainLine,
+ syntaxLine,
+ enableWrap,
+ enableHighlight,
+}: {
+ rawLine: string;
+ plainLine?: File["plainFile"][number];
+ syntaxLine?: File["syntaxFile"][number];
+ diffLine?: DiffLine;
+ diffFile: DiffFile;
+ enableWrap: boolean;
+ enableHighlight: boolean;
+}) => {
+ const isAdded = diffLine?.type === DiffLineType.Add;
+
+ const isDelete = diffLine?.type === DiffLineType.Delete;
+
+ const isMaxLineLengthToIgnoreSyntax = syntaxLine && syntaxLine?.nodeList?.length > 150;
+
+ return (
+
+
+ {isAdded ? "+" : isDelete ? "-" : " "}
+
+ {enableHighlight && syntaxLine && !isMaxLineLengthToIgnoreSyntax ? (
+
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/packages/octane/src/components/DiffExpand.tsrx b/packages/octane/src/components/DiffExpand.tsrx
new file mode 100644
index 0000000..58af9c6
--- /dev/null
+++ b/packages/octane/src/components/DiffExpand.tsrx
@@ -0,0 +1,23 @@
+export const ExpandDown = ({ className }: { className?: string }) => {
+ return (
+
+ );
+};
+
+export const ExpandUp = ({ className }: { className?: string }) => {
+ return (
+
+ );
+};
+
+export const ExpandAll = ({ className }: { className?: string }) => {
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffNoNewLine.tsrx b/packages/octane/src/components/DiffNoNewLine.tsrx
new file mode 100644
index 0000000..cbc29b9
--- /dev/null
+++ b/packages/octane/src/components/DiffNoNewLine.tsrx
@@ -0,0 +1,8 @@
+export const DiffNoNewLine = () => {
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffSplitContentLineNormal.tsrx b/packages/octane/src/components/DiffSplitContentLineNormal.tsrx
new file mode 100644
index 0000000..b7d6ea5
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitContentLineNormal.tsrx
@@ -0,0 +1,162 @@
+import { DiffLineType, type DiffFile, checkDiffLineIncludeChange } from "@git-diff-view/core";
+import {
+ getContentBG,
+ getLineNumberBG,
+ plainLineNumberColorName,
+ diffAsideWidthName,
+ emptyBGName,
+ expandLineNumberColorName,
+} from "@git-diff-view/utils";
+
+import { SplitSide } from "..";
+
+import { DiffSplitAddWidget } from "./DiffAddWidget.tsrx";
+import { DiffContent } from "./DiffContent.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+import { useDiffWidgetContext } from "./DiffWidgetContext";
+
+const InternalDiffSplitLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ side,
+ enableAddWidget,
+ enableHighlight,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableHighlight: boolean;
+ enableAddWidget: boolean;
+}) => {
+ const getCurrentSyntaxLine = side === SplitSide.old ? diffFile.getOldSyntaxLine : diffFile.getNewSyntaxLine;
+
+ const getCurrentPlainLine = side === SplitSide.old ? diffFile.getOldPlainLine : diffFile.getNewPlainLine;
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const currentLine = side === SplitSide.old ? oldLine : newLine;
+
+ const hasDiff = !!currentLine?.diff;
+
+ const hasContent = !!currentLine?.lineNumber;
+
+ const hasChange = checkDiffLineIncludeChange(currentLine?.diff);
+
+ const isAdded = currentLine?.diff?.type === DiffLineType.Add;
+
+ const isDelete = currentLine?.diff?.type === DiffLineType.Delete;
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const onAddWidgetClick = useDiffContext.getReadonlyState().onAddWidgetClick;
+
+ const { useWidget } = useDiffWidgetContext();
+
+ const setWidget = useWidget.getReadonlyState().setWidget;
+
+ const contentBG = getContentBG(isAdded, isDelete, hasDiff);
+
+ const lineNumberBG = getLineNumberBG(isAdded, isDelete, hasDiff);
+
+ const syntaxLine = getCurrentSyntaxLine(currentLine.lineNumber ?? -1);
+
+ const plainLine = getCurrentPlainLine(currentLine.lineNumber ?? -1);
+
+ return (
+
+ {hasContent ? (
+ <>
+ |
+ {hasDiff && enableAddWidget && (
+ onAddWidgetClick.current?.(...props)}
+ className="absolute left-[100%] z-[1] translate-x-[-50%]"
+ onOpenAddWidget={(lineNumber, side) => setWidget({ lineNumber: lineNumber, side: side })}
+ />
+ )}
+
+ {currentLine.lineNumber}
+
+ |
+
+
+ |
+ >
+ ) : (
+
+
+ |
+ )}
+
+ );
+};
+
+export const DiffSplitContentLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ side,
+ enableAddWidget,
+ enableHighlight,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableHighlight: boolean;
+ enableAddWidget: boolean;
+}) => {
+ const getCurrentLine = side === SplitSide.old ? diffFile.getSplitLeftLine : diffFile.getSplitRightLine;
+
+ const currentLine = getCurrentLine(index);
+
+ if (currentLine?.isHidden) return null;
+
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffSplitContentLineWrap.tsrx b/packages/octane/src/components/DiffSplitContentLineWrap.tsrx
new file mode 100644
index 0000000..1da83af
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitContentLineWrap.tsrx
@@ -0,0 +1,235 @@
+import { DiffLineType, type DiffFile, checkDiffLineIncludeChange } from "@git-diff-view/core";
+import {
+ getContentBG,
+ getLineNumberBG,
+ plainLineNumberColorName,
+ emptyBGName,
+ borderColorName,
+ expandLineNumberColorName,
+} from "@git-diff-view/utils";
+
+import { SplitSide } from "..";
+
+import { DiffSplitAddWidget } from "./DiffAddWidget.tsrx";
+import { DiffContent } from "./DiffContent.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+import { useDiffWidgetContext } from "./DiffWidgetContext";
+
+const InternalDiffSplitLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableAddWidget,
+ enableHighlight,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableHighlight: boolean;
+ enableAddWidget: boolean;
+}) => {
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const oldSyntaxLine = diffFile.getOldSyntaxLine(oldLine?.lineNumber ?? -1);
+
+ const oldPlainLine = diffFile.getOldPlainLine(oldLine.lineNumber ?? -1);
+
+ const newSyntaxLine = diffFile.getNewSyntaxLine(newLine?.lineNumber ?? -1);
+
+ const newPlainLine = diffFile.getNewPlainLine(newLine.lineNumber ?? -1);
+
+ const hasDiff = !!oldLine?.diff || !!newLine?.diff;
+
+ const hasChange = checkDiffLineIncludeChange(oldLine?.diff) || checkDiffLineIncludeChange(newLine?.diff);
+
+ const oldLineIsDelete = oldLine?.diff?.type === DiffLineType.Delete;
+
+ const newLineIsAdded = newLine?.diff?.type === DiffLineType.Add;
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const onAddWidgetClick = useDiffContext.getReadonlyState().onAddWidgetClick;
+
+ const { useWidget } = useDiffWidgetContext();
+
+ const setWidget = useWidget.getReadonlyState().setWidget;
+
+ const hasOldLine = !!oldLine.lineNumber;
+
+ const hasNewLine = !!newLine.lineNumber;
+
+ const oldLineContentBG = getContentBG(false, oldLineIsDelete, hasDiff);
+
+ const oldLineNumberBG = getLineNumberBG(false, oldLineIsDelete, hasDiff);
+
+ const newLineContentBG = getContentBG(newLineIsAdded, false, hasDiff);
+
+ const newLineNumberBG = getLineNumberBG(newLineIsAdded, false, hasDiff);
+
+ return (
+
+ {hasOldLine ? (
+ <>
+ |
+ {hasDiff && enableAddWidget && (
+ onAddWidgetClick.current?.(...props)}
+ className="absolute left-[100%] z-[1] translate-x-[-50%]"
+ onOpenAddWidget={(lineNumber, side) => setWidget({ lineNumber: lineNumber, side: side })}
+ />
+ )}
+
+ {oldLine.lineNumber}
+
+ |
+
+ {hasDiff && enableAddWidget && (
+ onAddWidgetClick.current?.(...props)}
+ className="absolute right-[100%] z-[1] translate-x-[50%]"
+ onOpenAddWidget={(lineNumber, side) => setWidget({ lineNumber: lineNumber, side: side })}
+ />
+ )}
+
+ |
+ >
+ ) : (
+
+
+ |
+ )}
+ {hasNewLine ? (
+ <>
+
+ {hasDiff && enableAddWidget && (
+ onAddWidgetClick.current?.(...props)}
+ className="absolute left-[100%] z-[1] translate-x-[-50%]"
+ onOpenAddWidget={(lineNumber, side) => setWidget({ lineNumber: lineNumber, side: side })}
+ />
+ )}
+
+ {newLine.lineNumber}
+
+ |
+
+ {hasDiff && enableAddWidget && (
+ onAddWidgetClick.current?.(...props)}
+ className="absolute right-[100%] z-[1] translate-x-[50%]"
+ onOpenAddWidget={(lineNumber, side) => setWidget({ lineNumber: lineNumber, side: side })}
+ />
+ )}
+
+ |
+ >
+ ) : (
+
+
+ |
+ )}
+
+ );
+};
+
+export const DiffSplitContentLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableAddWidget,
+ enableHighlight,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableHighlight: boolean;
+ enableAddWidget: boolean;
+}) => {
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ if (oldLine?.isHidden && newLine?.isHidden) return null;
+
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffSplitExtendLineNormal.tsrx b/packages/octane/src/components/DiffSplitExtendLineNormal.tsrx
new file mode 100644
index 0000000..5432eec
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitExtendLineNormal.tsrx
@@ -0,0 +1,150 @@
+import { emptyBGName } from "@git-diff-view/utils";
+import * as Octane from "octane";
+
+import { SplitSide } from "..";
+import { useDomWidth } from "../hooks/useDomWidth";
+import { useSyncHeight } from "../hooks/useSyncHeight";
+
+import { useDiffViewContext } from "./DiffViewContext";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+const InternalDiffSplitExtendLine = ({
+ index,
+ diffFile,
+ oldLineExtend,
+ newLineExtend,
+ side,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ oldLineExtend: { data: any };
+ newLineExtend: { data: any };
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const renderExtendLine = useDiffContext.useShallowStableSelector((s) => s.renderExtendLine);
+
+ const currentExtend = side === SplitSide.old ? oldLineExtend : newLineExtend;
+
+ const otherSide = side === SplitSide.old ? SplitSide.new : SplitSide.old;
+
+ const currentLineNumber = side === SplitSide.old ? oldLine.lineNumber : newLine.lineNumber;
+
+ const currentSideHasExtend = currentExtend?.data !== undefined && currentExtend?.data !== null;
+
+ const hasExtend =
+ (oldLineExtend?.data !== undefined && oldLineExtend?.data !== null) ||
+ (newLineExtend?.data !== undefined && newLineExtend?.data !== null);
+
+ const currentExtendRendered =
+ hasExtend &&
+ renderExtendLine?.({
+ diffFile,
+ side,
+ lineNumber: currentLineNumber ?? -1,
+ data: currentExtend?.data,
+ onUpdate: diffFile.notifyAll,
+ });
+
+ useSyncHeight({
+ selector: `div[data-line="${lineNumber}-extend-content"]`,
+ wrapper: `tr[data-line="${lineNumber}-extend"]`,
+ side: SplitSide[currentSideHasExtend ? side : otherSide],
+ enable: hasExtend && typeof renderExtendLine === "function",
+ });
+
+ const width = useDomWidth({
+ selector: side === SplitSide.old ? ".old-diff-table-wrapper" : ".new-diff-table-wrapper",
+ enable: currentSideHasExtend && typeof renderExtendLine === "function",
+ });
+
+ if (!renderExtendLine) return null;
+
+ return (
+
+ {currentSideHasExtend ? (
+ |
+
+ {width > 0 && currentExtendRendered}
+
+ |
+ ) : (
+
+
+ |
+ )}
+
+ );
+};
+
+export const DiffSplitExtendLine = ({
+ index,
+ diffFile,
+ side,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const { oldLineExtend, newLineExtend } = useDiffContext(
+ Octane.useCallback(
+ (s) => ({
+ oldLineExtend: s.extendData?.oldFile?.[oldLine?.lineNumber ?? -1],
+ newLineExtend: s.extendData?.newFile?.[newLine?.lineNumber ?? -1],
+ }),
+ [oldLine?.lineNumber, newLine?.lineNumber]
+ )
+ );
+
+ const hasExtend = oldLineExtend?.data || newLineExtend?.data;
+
+ // if the expand action not enabled, the `isHidden` property will never change
+ const enableExpand = diffFile.getExpandEnabled();
+
+ const currentLine = side === SplitSide.old ? oldLine : newLine;
+
+ const currentIsShow = hasExtend && (!currentLine.isHidden || !enableExpand);
+
+ if (!currentIsShow) return null;
+
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffSplitExtendLineWrap.tsrx b/packages/octane/src/components/DiffSplitExtendLineWrap.tsrx
new file mode 100644
index 0000000..f0b3ecb
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitExtendLineWrap.tsrx
@@ -0,0 +1,133 @@
+import { emptyBGName, borderColorName } from "@git-diff-view/utils";
+import * as Octane from "octane";
+
+import { SplitSide } from "..";
+
+import { useDiffViewContext } from "./DiffViewContext";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+const InternalDiffSplitExtendLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ oldLineExtend,
+ newLineExtend,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ oldLineExtend: { data: any };
+ newLineExtend: { data: any };
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ // 需要显示的时候才进行方法订阅,可以大幅度提高性能
+ const renderExtendLine = useDiffContext.useShallowStableSelector((s) => s.renderExtendLine);
+
+ if (!renderExtendLine) return null;
+
+ const oldExtendRendered =
+ oldLineExtend?.data &&
+ renderExtendLine?.({
+ diffFile,
+ side: SplitSide.old,
+ lineNumber: oldLine.lineNumber ?? -1,
+ data: oldLineExtend.data,
+ onUpdate: diffFile.notifyAll,
+ });
+
+ const newExtendRendered =
+ newLineExtend?.data &&
+ renderExtendLine?.({
+ diffFile,
+ side: SplitSide.new,
+ lineNumber: newLine.lineNumber ?? -1,
+ data: newLineExtend.data,
+ onUpdate: diffFile.notifyAll,
+ });
+
+ return (
+
+ {oldExtendRendered ? (
+ |
+ {oldExtendRendered}
+ |
+ ) : (
+ |
+ )}
+ {newExtendRendered ? (
+
+ {newExtendRendered}
+ |
+ ) : (
+ |
+ )}
+
+ );
+};
+
+export const DiffSplitExtendLine = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const { oldLineExtend, newLineExtend } = useDiffContext(
+ Octane.useCallback(
+ (s) => ({
+ oldLineExtend: s.extendData?.oldFile?.[oldLine?.lineNumber ?? -1],
+ newLineExtend: s.extendData?.newFile?.[newLine?.lineNumber ?? -1],
+ }),
+ [oldLine?.lineNumber, newLine?.lineNumber]
+ )
+ );
+
+ const hasExtend = oldLineExtend?.data || newLineExtend?.data;
+
+ // if the expand action not enabled, the `isHidden` property will never change
+ const enableExpand = diffFile.getExpandEnabled();
+
+ const currentIsShow = hasExtend && ((!oldLine?.isHidden && !newLine?.isHidden) || !enableExpand);
+
+ if (!currentIsShow) return null;
+
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffSplitHunkLineNormal.tsrx b/packages/octane/src/components/DiffSplitHunkLineNormal.tsrx
new file mode 100644
index 0000000..329560a
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitHunkLineNormal.tsrx
@@ -0,0 +1,315 @@
+import { composeLen, type DiffFile } from "@git-diff-view/core";
+import {
+ hunkLineNumberBGName,
+ plainLineNumberColorName,
+ diffAsideWidthName,
+ hunkContentBGName,
+ hunkContentColorName,
+} from "@git-diff-view/utils";
+
+import { DiffModeEnum, SplitSide } from "..";
+import { useSyncHeight } from "../hooks/useSyncHeight";
+
+import { ExpandAll, ExpandDown, ExpandUp } from "./DiffExpand.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+
+const InternalDiffSplitHunkLineGitHub = ({
+ index,
+ diffFile,
+ side,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getSplitHunkLine(index);
+
+ const expandEnabled = diffFile.getExpandEnabled();
+
+ useSyncHeight({
+ selector: `tr[data-line="${lineNumber}-hunk"]`,
+ side: SplitSide[SplitSide.old],
+ enable: side === SplitSide.new,
+ });
+
+ const enableHunkAction = side === SplitSide.old;
+
+ const couldExpand = expandEnabled && currentHunk && currentHunk.splitInfo;
+
+ const isExpandAll =
+ currentHunk &&
+ currentHunk.splitInfo &&
+ currentHunk.splitInfo.endHiddenIndex - currentHunk.splitInfo.startHiddenIndex < composeLen;
+
+ const isFirstLine = currentHunk && currentHunk.isFirst;
+
+ const isLastLine = currentHunk && currentHunk.isLast;
+
+ return (
+
+ {enableHunkAction ? (
+ <>
+ |
+ {couldExpand ? (
+ isFirstLine ? (
+
+ ) : isLastLine ? (
+
+ ) : isExpandAll ? (
+
+ ) : (
+ <>
+
+
+ >
+ )
+ ) : (
+
+ )}
+ |
+
+
+ {currentHunk.splitInfo?.plainText || currentHunk.text}
+
+ |
+ >
+ ) : (
+
+
+ |
+ )}
+
+ );
+};
+
+const InternalDiffSplitHunkLineGitLab = ({
+ index,
+ diffFile,
+ side,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getSplitHunkLine(index);
+
+ const expandEnabled = diffFile.getExpandEnabled();
+
+ useSyncHeight({
+ selector: `tr[data-line="${lineNumber}-hunk"]`,
+ side: SplitSide[SplitSide.old],
+ enable: side === SplitSide.new,
+ });
+
+ const couldExpand = expandEnabled && currentHunk && currentHunk.splitInfo;
+
+ const isExpandAll =
+ currentHunk &&
+ currentHunk.splitInfo &&
+ currentHunk.splitInfo.endHiddenIndex - currentHunk.splitInfo.startHiddenIndex < composeLen;
+
+ const isFirstLine = currentHunk && currentHunk.isFirst;
+
+ const isLastLine = currentHunk && currentHunk.isLast;
+
+ return (
+
+ |
+ {couldExpand ? (
+ isFirstLine ? (
+
+ ) : isLastLine ? (
+
+ ) : isExpandAll ? (
+
+ ) : (
+ <>
+
+
+ >
+ )
+ ) : (
+
+ )}
+ |
+
+
+ {currentHunk.splitInfo?.plainText || currentHunk.text}
+
+ |
+
+ );
+};
+
+const InternalDiffSplitHunkLine = ({
+ index,
+ diffFile,
+ side,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const diffViewMode = useDiffContext.useShallowStableSelector((s) => s.mode);
+
+ if (
+ diffViewMode === DiffModeEnum.SplitGitHub ||
+ diffViewMode === DiffModeEnum.Split ||
+ diffViewMode === DiffModeEnum.Unified
+ ) {
+ return ;
+ } else {
+ return ;
+ }
+};
+
+export const DiffSplitHunkLine = ({
+ index,
+ diffFile,
+ side,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getSplitHunkLine(index);
+
+ const currentIsShow =
+ currentHunk &&
+ currentHunk.splitInfo &&
+ currentHunk.splitInfo.startHiddenIndex < currentHunk.splitInfo.endHiddenIndex;
+
+ const currentIsPureHunk = currentHunk && diffFile._getIsPureDiffRender() && !currentHunk.splitInfo;
+
+ if (!currentIsShow && !currentIsPureHunk) return null;
+
+ return ;
+};
diff --git a/packages/octane/src/components/DiffSplitHunkLineWrap.tsrx b/packages/octane/src/components/DiffSplitHunkLineWrap.tsrx
new file mode 100644
index 0000000..6b0cb76
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitHunkLineWrap.tsrx
@@ -0,0 +1,339 @@
+import { composeLen, type DiffFile } from "@git-diff-view/core";
+import {
+ hunkLineNumberBGName,
+ plainLineNumberColorName,
+ hunkContentBGName,
+ hunkContentColorName,
+ borderColorName,
+} from "@git-diff-view/utils";
+
+import { DiffModeEnum } from "..";
+
+import { ExpandAll, ExpandDown, ExpandUp } from "./DiffExpand.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+
+const DiffSplitHunkLineGitHub = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getSplitHunkLine(index);
+
+ const expandEnabled = diffFile.getExpandEnabled();
+
+ const couldExpand = expandEnabled && currentHunk && currentHunk.splitInfo;
+
+ const isExpandAll =
+ currentHunk &&
+ currentHunk.splitInfo &&
+ currentHunk.splitInfo.endHiddenIndex - currentHunk.splitInfo.startHiddenIndex < composeLen;
+
+ const isFirstLine = currentHunk && currentHunk.isFirst;
+
+ const isLastLine = currentHunk && currentHunk.isLast;
+
+ return (
+
+ |
+ {couldExpand ? (
+ isFirstLine ? (
+
+ ) : isLastLine ? (
+
+ ) : isExpandAll ? (
+
+ ) : (
+ <>
+
+
+ >
+ )
+ ) : (
+
+ )}
+ |
+
+
+ {currentHunk.splitInfo?.plainText || currentHunk.text}
+
+ |
+
+ );
+};
+
+const DiffSplitHunkLineGitLab = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getSplitHunkLine(index);
+
+ const expandEnabled = diffFile.getExpandEnabled();
+
+ const couldExpand = expandEnabled && currentHunk && currentHunk.splitInfo;
+
+ const isExpandAll =
+ currentHunk &&
+ currentHunk.splitInfo &&
+ currentHunk.splitInfo.endHiddenIndex - currentHunk.splitInfo.startHiddenIndex < composeLen;
+
+ const isFirstLine = currentHunk && currentHunk.isFirst;
+
+ const isLastLine = currentHunk && currentHunk.isLast;
+
+ return (
+
+ |
+ {couldExpand ? (
+ isFirstLine ? (
+
+ ) : isLastLine ? (
+
+ ) : isExpandAll ? (
+
+ ) : (
+ <>
+
+
+ >
+ )
+ ) : (
+
+ )}
+ |
+
+
+ {currentHunk.splitInfo?.plainText || currentHunk.text}
+
+ |
+
+ {couldExpand ? (
+ isFirstLine ? (
+
+ ) : isLastLine ? (
+
+ ) : isExpandAll ? (
+
+ ) : (
+ <>
+
+
+ >
+ )
+ ) : (
+
+ )}
+ |
+
+
+ {currentHunk.splitInfo?.plainText || currentHunk.text}
+
+ |
+
+ );
+};
+
+const InternalDiffSplitHunkLine = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const diffViewMode = useDiffContext.useShallowStableSelector((s) => s.mode);
+
+ if (
+ diffViewMode === DiffModeEnum.SplitGitHub ||
+ diffViewMode === DiffModeEnum.Split ||
+ diffViewMode === DiffModeEnum.Unified
+ ) {
+ return ;
+ } else {
+ return ;
+ }
+};
+
+export const DiffSplitHunkLine = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getSplitHunkLine(index);
+
+ const currentIsShow =
+ currentHunk &&
+ currentHunk.splitInfo &&
+ currentHunk.splitInfo.startHiddenIndex < currentHunk.splitInfo.endHiddenIndex;
+
+ const currentIsPureHunk = currentHunk && diffFile._getIsPureDiffRender() && !currentHunk.splitInfo;
+
+ if (!currentIsShow && !currentIsPureHunk) return null;
+
+ return ;
+};
diff --git a/packages/octane/src/components/DiffSplitView.tsrx b/packages/octane/src/components/DiffSplitView.tsrx
new file mode 100644
index 0000000..9d560a9
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitView.tsrx
@@ -0,0 +1,43 @@
+import { memo, useEffect, useMemo, useRef } from "octane";
+
+import { DiffSplitViewNormal } from "./DiffSplitViewNormal.tsrx";
+import { DiffSplitViewWrap } from "./DiffSplitViewWrap.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+import { DiffWidgetContext } from "./DiffWidgetContext";
+import { createDiffWidgetStore } from "./tools";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+export const DiffSplitView = memo(({ diffFile }: { diffFile: DiffFile }) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const useDiffContextRef = useRef(useDiffContext);
+
+ useDiffContextRef.current = useDiffContext;
+
+ const { enableWrap, onCreateUseWidgetHook } = useDiffContext.useShallowStableSelector((s) => ({
+ enableWrap: s.enableWrap,
+ onCreateUseWidgetHook: s.onCreateUseWidgetHook,
+ }));
+
+ // performance optimization
+ const useWidget = useMemo(() => createDiffWidgetStore(useDiffContextRef), []);
+
+ const contextValue = useMemo(() => ({ useWidget }), [useWidget]);
+
+ useEffect(() => {
+ const { setWidget } = useWidget.getReadonlyState();
+
+ setWidget({});
+ }, [diffFile, useWidget]);
+
+ useEffect(() => {
+ onCreateUseWidgetHook?.(useWidget);
+ }, [useWidget, onCreateUseWidgetHook]);
+
+ return (
+
+ {enableWrap ? : }
+
+ );
+});
diff --git a/packages/octane/src/components/DiffSplitViewNormal.tsrx b/packages/octane/src/components/DiffSplitViewNormal.tsrx
new file mode 100644
index 0000000..84d8334
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitViewNormal.tsrx
@@ -0,0 +1,217 @@
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+import { getSplitContentLines, type DiffFile } from "@git-diff-view/core";
+import {
+ removeAllSelection,
+ syncScroll,
+ diffFontSizeName,
+ borderColorName,
+ diffAsideWidthName,
+ getDiffIdFromElement,
+} from "@git-diff-view/utils";
+import { Fragment, memo, useEffect, useRef } from "octane";
+import * as Octane from "octane";
+// @ts-ignore
+import { useSyncExternalStore } from "octane";
+
+import { useTextWidth } from "../hooks/useTextWidth";
+
+import { DiffSplitContentLine } from "./DiffSplitContentLineNormal.tsrx";
+import { DiffSplitExtendLine } from "./DiffSplitExtendLineNormal.tsrx";
+import { DiffSplitHunkLine } from "./DiffSplitHunkLineNormal.tsrx";
+import { DiffSplitWidgetLine } from "./DiffSplitWidgetLineNormal.tsrx";
+import { SplitSide } from "./DiffView.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+
+import type { NativeMouseEventHandler, OctaneStyle } from "../octane-types";
+
+const DiffSplitViewTable = ({
+ side,
+ diffFile,
+ enableAddWidget,
+ enableHighlight,
+ onMouseDown,
+}: {
+ side: SplitSide;
+ diffFile: DiffFile;
+ enableHighlight: boolean;
+ enableAddWidget: boolean;
+ onMouseDown?: NativeMouseEventHandler;
+}) => {
+ const className = side === SplitSide.new ? "new-diff-table" : "old-diff-table";
+
+ const lines = getSplitContentLines(diffFile);
+
+ return (
+
+
+
+
+
+
+
+ | {SplitSide[side]} line number |
+ {SplitSide[side]} line content |
+
+
+
+ {lines.map((line) => (
+
+
+
+
+
+
+ ))}
+
+
+
+ );
+};
+
+export const DiffSplitViewNormal = memo(({ diffFile }: { diffFile: DiffFile }) => {
+ const ref1 = useRef(null);
+
+ const ref2 = useRef(null);
+
+ const ref = useRef(null);
+
+ const tempRef = useRef(undefined);
+
+ const splitLineLength = Math.max(diffFile.splitLineLength, diffFile.fileLineLength);
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const { fontSize, enableAddWidget, enableHighlight } = useDiffContext.useShallowStableSelector((s) => ({
+ fontSize: s.fontSize,
+ enableAddWidget: s.enableAddWidget,
+ enableHighlight: s.enableHighlight,
+ }));
+
+ useSyncExternalStore(diffFile.subscribe, diffFile.getUpdateCount, diffFile.getUpdateCount);
+
+ useEffect(() => {
+ const left = ref1.current;
+ const right = ref2.current;
+ if (!left || !right) return;
+ return syncScroll(left, right);
+ }, []);
+
+ const font = Octane.useMemo(
+ () => ({ fontSize: fontSize + "px", fontFamily: "Menlo, Consolas, monospace" }),
+ [fontSize]
+ );
+
+ const _width = useTextWidth({
+ text: splitLineLength.toString(),
+ font,
+ });
+
+ const width = Math.max(40, _width + 25);
+
+ const setStyle = (side?: SplitSide) => {
+ if (!ref.current) return;
+ if (!side) {
+ ref.current.textContent = "";
+ } else {
+ const id = `diff-root${diffFile.getId()}`;
+ ref.current.textContent = `#${id} [data-state="extend"] {user-select: none} \n#${id} [data-state="hunk"] {user-select: none} \n#${id} [data-state="widget"] {user-select: none}`;
+ }
+ };
+
+ const onMouseDown: NativeMouseEventHandler = (e) => {
+ let ele: Element | null = e.target as Element;
+
+ // need remove all the selection
+ if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
+ removeAllSelection();
+ return;
+ }
+
+ const id = getDiffIdFromElement(ele as HTMLElement);
+
+ if (id && id !== `diff-root${diffFile.getId()}`) {
+ return;
+ }
+
+ while (ele && ele instanceof HTMLElement) {
+ const state = ele.getAttribute("data-state");
+ const side = ele.getAttribute("data-side") as unknown as SplitSide;
+ if (side) {
+ if (tempRef.current !== (SplitSide[side] as unknown as SplitSide)) {
+ tempRef.current = SplitSide[side] as unknown as SplitSide;
+ setStyle(SplitSide[side] as unknown as SplitSide);
+ removeAllSelection();
+ }
+ }
+ if (state) {
+ if (state === "extend" || state === "hunk" || state === "widget") {
+ if (tempRef.current !== undefined) {
+ tempRef.current = undefined;
+ setStyle(undefined);
+ removeAllSelection();
+ }
+ return;
+ } else {
+ return;
+ }
+ }
+
+ ele = ele.parentElement;
+ }
+ };
+
+ return (
+
+ );
+});
diff --git a/packages/octane/src/components/DiffSplitViewWrap.tsrx b/packages/octane/src/components/DiffSplitViewWrap.tsrx
new file mode 100644
index 0000000..1cf09e2
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitViewWrap.tsrx
@@ -0,0 +1,152 @@
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+import { type DiffFile, getSplitContentLines } from "@git-diff-view/core";
+import { diffAsideWidthName, diffFontSizeName, getDiffIdFromElement, removeAllSelection } from "@git-diff-view/utils";
+import { Fragment, memo, useMemo, useRef } from "octane";
+// SEE https://github.com/facebook/react/pull/25231
+// @ts-ignore
+import { useSyncExternalStore } from "octane";
+
+import { SplitSide } from "..";
+import { useTextWidth } from "../hooks/useTextWidth";
+
+import { DiffSplitContentLine } from "./DiffSplitContentLineWrap.tsrx";
+import { DiffSplitExtendLine } from "./DiffSplitExtendLineWrap.tsrx";
+import { DiffSplitHunkLine } from "./DiffSplitHunkLineWrap.tsrx";
+import { DiffSplitWidgetLine } from "./DiffSplitWidgetLineWrap.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+
+import type { NativeMouseEventHandler, OctaneStyle } from "../octane-types";
+
+export const DiffSplitViewWrap = memo(({ diffFile }: { diffFile: DiffFile }) => {
+ const splitLineLength = Math.max(diffFile.splitLineLength, diffFile.fileLineLength);
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const ref = useRef(null);
+
+ const tempRef = useRef(undefined);
+
+ const { fontSize, enableAddWidget, enableHighlight } = useDiffContext.useShallowStableSelector((s) => ({
+ fontSize: s.fontSize,
+ enableAddWidget: s.enableAddWidget,
+ enableHighlight: s.enableHighlight,
+ }));
+
+ useSyncExternalStore(diffFile.subscribe, diffFile.getUpdateCount, diffFile.getUpdateCount);
+
+ const font = useMemo(() => ({ fontSize: fontSize + "px", fontFamily: "Menlo, Consolas, monospace" }), [fontSize]);
+
+ const _width = useTextWidth({
+ text: splitLineLength.toString(),
+ font,
+ });
+
+ const width = Math.max(40, _width + 25);
+
+ const lines = getSplitContentLines(diffFile);
+
+ const setStyle = (side?: SplitSide) => {
+ if (!ref.current) return;
+ if (!side) {
+ ref.current.textContent = "";
+ } else {
+ const id = `diff-root${diffFile.getId()}`;
+ const targetSide = side === SplitSide.old ? SplitSide.new : SplitSide.old;
+ ref.current.textContent = `#${id} [data-side="${SplitSide[targetSide]}"] {user-select: none} \n#${id} [data-state="extend"] {user-select: none} \n#${id} [data-state="hunk"] {user-select: none} \n#${id} [data-state="widget"] {user-select: none}`;
+ }
+ };
+
+ const onMouseDown: NativeMouseEventHandler = (e) => {
+ let ele: Element | null = e.target as Element;
+
+ // need remove all the selection
+ if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
+ removeAllSelection();
+ return;
+ }
+
+ const id = getDiffIdFromElement(ele as HTMLElement);
+
+ if (id && id !== `diff-root${diffFile.getId()}`) {
+ return;
+ }
+
+ while (ele && ele instanceof HTMLElement) {
+ const state = ele.getAttribute("data-state");
+ const side = ele.getAttribute("data-side") as unknown as SplitSide;
+ if (side) {
+ if (tempRef.current !== (SplitSide[side] as unknown as SplitSide)) {
+ tempRef.current = SplitSide[side] as unknown as SplitSide;
+ setStyle(SplitSide[side] as unknown as SplitSide);
+ removeAllSelection();
+ }
+ }
+ if (state) {
+ if (state === "extend" || state === "hunk" || state === "widget") {
+ if (tempRef.current !== undefined) {
+ tempRef.current = undefined;
+ setStyle(undefined);
+ removeAllSelection();
+ }
+ return;
+ } else {
+ return;
+ }
+ }
+
+ ele = ele.parentElement;
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+ | old line number |
+ old line content |
+ new line number |
+ new line content |
+
+
+
+ {lines.map((line) => (
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+ );
+});
diff --git a/packages/octane/src/components/DiffSplitWidgetLineNormal.tsrx b/packages/octane/src/components/DiffSplitWidgetLineNormal.tsrx
new file mode 100644
index 0000000..09c471f
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitWidgetLineNormal.tsrx
@@ -0,0 +1,149 @@
+import { emptyBGName } from "@git-diff-view/utils";
+import * as Octane from "octane";
+
+import { SplitSide } from "..";
+import { useDomWidth } from "../hooks/useDomWidth";
+import { useSyncHeight } from "../hooks/useSyncHeight";
+
+import { useDiffViewContext } from "./DiffViewContext";
+import { useDiffWidgetContext } from "./DiffWidgetContext";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+const InternalDiffSplitWidgetLine = ({
+ index,
+ side,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useWidget } = useDiffWidgetContext();
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const widgetSide = useWidget.useShallowStableSelector((s) => s.widgetSide);
+
+ const widgetLineNumber = useWidget.getReadonlyState().widgetLineNumber;
+
+ const setWidget = useWidget.getReadonlyState().setWidget;
+
+ const oldLineWidget = oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
+
+ const newLineWidget = newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
+
+ const currentLine = side === SplitSide.old ? oldLine : newLine;
+
+ const otherSide = side === SplitSide.old ? SplitSide.new : SplitSide.old;
+
+ const currentHasWidget = side === SplitSide.old ? oldLineWidget : newLineWidget;
+
+ const hasWidget = oldLineWidget || newLineWidget;
+
+ const renderWidgetLine = useDiffContext.useShallowStableSelector((s) => s.renderWidgetLine);
+
+ const currentWidgetRendered =
+ currentHasWidget &&
+ renderWidgetLine?.({
+ diffFile,
+ side,
+ lineNumber: currentLine.lineNumber ?? -1,
+ onClose: () => setWidget({}),
+ });
+
+ useSyncHeight({
+ selector: `div[data-line="${lineNumber}-widget-content"]`,
+ wrapper: `tr[data-line="${lineNumber}-widget"]`,
+ side: SplitSide[currentHasWidget ? side : otherSide],
+ enable: !!hasWidget && typeof renderWidgetLine === "function",
+ });
+
+ const width = useDomWidth({
+ selector: side === SplitSide.old ? ".old-diff-table-wrapper" : ".new-diff-table-wrapper",
+ enable: !!currentHasWidget && typeof renderWidgetLine === "function",
+ });
+
+ if (!renderWidgetLine) return null;
+
+ return (
+
+ {currentHasWidget ? (
+ |
+
+ {width > 0 && currentWidgetRendered}
+
+ |
+ ) : (
+
+
+ |
+ )}
+
+ );
+};
+
+// TODO! improve performance
+export const DiffSplitWidgetLine = ({
+ index,
+ side,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useWidget } = useDiffWidgetContext();
+
+ const currentIsShow = useWidget.useShallowSelector(
+ Octane.useCallback(
+ (s) => {
+ const widgetLineNumber = s.widgetLineNumber;
+
+ const widgetSide = s.widgetSide;
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const oldLineWidget =
+ oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
+
+ const newLineWidget =
+ newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
+
+ const currentIsShow = oldLineWidget || newLineWidget;
+
+ return currentIsShow;
+ },
+ [diffFile, index]
+ ),
+ (p, c) => p === c
+ );
+
+ if (!currentIsShow) return null;
+
+ return ;
+};
diff --git a/packages/octane/src/components/DiffSplitWidgetLineWrap.tsrx b/packages/octane/src/components/DiffSplitWidgetLineWrap.tsrx
new file mode 100644
index 0000000..30085a7
--- /dev/null
+++ b/packages/octane/src/components/DiffSplitWidgetLineWrap.tsrx
@@ -0,0 +1,137 @@
+import { borderColorName, emptyBGName } from "@git-diff-view/utils";
+import * as Octane from "octane";
+
+import { SplitSide } from "..";
+
+import { useDiffViewContext } from "./DiffViewContext";
+import { useDiffWidgetContext } from "./DiffWidgetContext";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+const InternalDiffSplitWidgetLine = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useWidget } = useDiffWidgetContext();
+
+ const setWidget = useWidget.getReadonlyState().setWidget;
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const renderWidgetLine = useDiffContext.useShallowStableSelector((s) => s.renderWidgetLine);
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const widgetSide = useWidget.useShallowStableSelector((s) => s.widgetSide);
+
+ const widgetLineNumber = useWidget.getReadonlyState().widgetLineNumber;
+
+ const oldLineWidget = oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
+
+ const newLineWidget = newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
+
+ const oldWidgetRendered =
+ oldLineWidget &&
+ renderWidgetLine?.({
+ diffFile,
+ side: SplitSide.old,
+ lineNumber: oldLine.lineNumber ?? -1,
+ onClose: () => setWidget({}),
+ });
+
+ const newWidgetRendered =
+ newLineWidget &&
+ renderWidgetLine?.({
+ diffFile,
+ side: SplitSide.new,
+ lineNumber: newLine.lineNumber ?? -1,
+ onClose: () => setWidget({}),
+ });
+
+ if (!renderWidgetLine) return null;
+
+ return (
+
+ {oldWidgetRendered ? (
+ |
+ {oldWidgetRendered}
+ |
+ ) : (
+ |
+ )}
+ {newWidgetRendered ? (
+
+ {newWidgetRendered}
+ |
+ ) : (
+ |
+ )}
+
+ );
+};
+
+// TODO! improve performance
+export const DiffSplitWidgetLine = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const { useWidget } = useDiffWidgetContext();
+
+ const currentIsShow = useWidget.useShallowSelector(
+ Octane.useCallback(
+ (s) => {
+ const widgetLineNumber = s.widgetLineNumber;
+
+ const widgetSide = s.widgetSide;
+
+ const oldLine = diffFile.getSplitLeftLine(index);
+
+ const newLine = diffFile.getSplitRightLine(index);
+
+ const oldLineWidget =
+ oldLine.lineNumber && widgetSide === SplitSide.old && widgetLineNumber === oldLine.lineNumber;
+
+ const newLineWidget =
+ newLine.lineNumber && widgetSide === SplitSide.new && widgetLineNumber === newLine.lineNumber;
+
+ const currentIsShow = oldLineWidget || newLineWidget;
+
+ return currentIsShow;
+ },
+ [diffFile, index]
+ ),
+ (p, c) => p === c
+ );
+
+ if (!currentIsShow) return null;
+
+ return ;
+};
diff --git a/packages/octane/src/components/DiffUnifiedContentLine.tsrx b/packages/octane/src/components/DiffUnifiedContentLine.tsrx
new file mode 100644
index 0000000..93418c2
--- /dev/null
+++ b/packages/octane/src/components/DiffUnifiedContentLine.tsrx
@@ -0,0 +1,336 @@
+import { type DiffFile, type DiffLine, checkDiffLineIncludeChange, type File } from "@git-diff-view/core";
+import {
+ diffAsideWidthName,
+ addContentBGName,
+ addLineNumberBGName,
+ delContentBGName,
+ delLineNumberBGName,
+ expandContentBGName,
+ plainContentBGName,
+ plainLineNumberBGName,
+ plainLineNumberColorName,
+ expandLineNumberColorName,
+} from "@git-diff-view/utils";
+
+import { SplitSide } from "..";
+
+import { DiffUnifiedAddWidget } from "./DiffAddWidget.tsrx";
+import { DiffContent } from "./DiffContent.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+import { useDiffWidgetContext } from "./DiffWidgetContext";
+
+import type { DiffViewProps } from "..";
+
+const DiffUnifiedOldLine = ({
+ index,
+ diffLine,
+ rawLine,
+ plainLine,
+ syntaxLine,
+ lineNumber,
+ diffFile,
+ setWidget,
+ enableWrap,
+ enableAddWidget,
+ enableHighlight,
+ onAddWidgetClick,
+}: {
+ index: number;
+ lineNumber: number;
+ rawLine: string;
+ plainLine?: File["plainFile"][number];
+ syntaxLine?: File["syntaxFile"][number];
+ diffLine?: DiffLine;
+ diffFile: DiffFile;
+ enableWrap: boolean;
+ enableAddWidget: boolean;
+ enableHighlight: boolean;
+ onAddWidgetClick?: DiffViewProps["onAddWidgetClick"];
+ setWidget: (props: { side?: SplitSide; lineNumber?: number }) => void;
+}) => {
+ return (
+
+ |
+ {enableAddWidget && (
+ setWidget({ lineNumber, side })}
+ />
+ )}
+
+
+ {lineNumber}
+
+
+
+
+ |
+
+
+ |
+
+ );
+};
+
+const DiffUnifiedNewLine = ({
+ index,
+ diffLine,
+ rawLine,
+ plainLine,
+ syntaxLine,
+ lineNumber,
+ diffFile,
+ setWidget,
+ enableWrap,
+ enableAddWidget,
+ enableHighlight,
+ onAddWidgetClick,
+}: {
+ index: number;
+ lineNumber: number;
+ rawLine: string;
+ plainLine?: File["plainFile"][number];
+ syntaxLine?: File["syntaxFile"][number];
+ diffLine?: DiffLine;
+ diffFile: DiffFile;
+ enableWrap: boolean;
+ enableAddWidget: boolean;
+ enableHighlight: boolean;
+ onAddWidgetClick?: DiffViewProps["onAddWidgetClick"];
+ setWidget: (props: { side?: SplitSide; lineNumber?: number }) => void;
+}) => {
+ return (
+
+ |
+ {enableAddWidget && (
+ setWidget({ lineNumber, side })}
+ />
+ )}
+
+
+
+
+ {lineNumber}
+
+
+ |
+
+
+ |
+
+ );
+};
+
+const InternalDiffUnifiedLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableWrap,
+ enableAddWidget,
+ enableHighlight,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableWrap: boolean;
+ enableHighlight: boolean;
+ enableAddWidget: boolean;
+}) => {
+ const unifiedLine = diffFile.getUnifiedLine(index);
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const onAddWidgetClick = useDiffContext.getReadonlyState().onAddWidgetClick;
+
+ const { useWidget } = useDiffWidgetContext();
+
+ const setWidget = useWidget.getReadonlyState().setWidget;
+
+ const hasDiff = unifiedLine.diff;
+
+ const hasChange = checkDiffLineIncludeChange(unifiedLine.diff);
+
+ const rawLine = unifiedLine.value || "";
+
+ const diffLine = unifiedLine.diff;
+
+ const newLineNumber = unifiedLine.newLineNumber;
+
+ const oldLinenumber = unifiedLine.oldLineNumber;
+
+ const syntaxLine = newLineNumber
+ ? diffFile.getNewSyntaxLine(newLineNumber)
+ : oldLinenumber
+ ? diffFile.getOldSyntaxLine(oldLinenumber)
+ : undefined;
+
+ const plainLine = newLineNumber
+ ? diffFile.getNewPlainLine(newLineNumber)
+ : oldLinenumber
+ ? diffFile.getOldPlainLine(oldLinenumber)
+ : undefined;
+
+ if (hasChange) {
+ if (unifiedLine.oldLineNumber) {
+ return (
+ onAddWidgetClick.current?.(...props)}
+ />
+ );
+ } else {
+ return (
+ onAddWidgetClick.current?.(...props)}
+ />
+ );
+ }
+ } else {
+ return (
+
+ |
+ {enableAddWidget && hasDiff && (
+ onAddWidgetClick.current?.(...props)}
+ onOpenAddWidget={(lineNumber, side) => setWidget({ lineNumber, side })}
+ />
+ )}
+
+
+ {unifiedLine.oldLineNumber}
+
+
+
+ {unifiedLine.newLineNumber}
+
+
+ |
+
+
+ |
+
+ );
+ }
+};
+
+export const DiffUnifiedContentLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableWrap,
+ enableHighlight,
+ enableAddWidget,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableWrap: boolean;
+ enableHighlight: boolean;
+ enableAddWidget: boolean;
+}) => {
+ const unifiedLine = diffFile.getUnifiedLine(index);
+
+ if (unifiedLine?.isHidden) return null;
+
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffUnifiedExtendLine.tsrx b/packages/octane/src/components/DiffUnifiedExtendLine.tsrx
new file mode 100644
index 0000000..f5682bc
--- /dev/null
+++ b/packages/octane/src/components/DiffUnifiedExtendLine.tsrx
@@ -0,0 +1,108 @@
+import { useCallback } from "octane";
+
+import { SplitSide } from "..";
+import { useDomWidth } from "../hooks/useDomWidth";
+
+import { useDiffViewContext } from "./DiffViewContext";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+const InternalDiffUnifiedExtendLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableWrap,
+ oldLineExtend,
+ newLineExtend,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableWrap: boolean;
+ oldLineExtend: { data: any };
+ newLineExtend: { data: any };
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const renderExtendLine = useDiffContext.useShallowStableSelector((s) => s.renderExtendLine);
+
+ const unifiedItem = diffFile.getUnifiedLine(index);
+
+ // TODO use css variable to get width
+ const width = useDomWidth({
+ selector: ".unified-diff-table-wrapper",
+ enable: typeof renderExtendLine === "function",
+ });
+
+ if (!renderExtendLine) return null;
+
+ return (
+
+ |
+
+ {(enableWrap ? true : width > 0) &&
+ oldLineExtend?.data !== undefined &&
+ oldLineExtend?.data !== null &&
+ renderExtendLine?.({
+ diffFile,
+ side: SplitSide.old,
+ lineNumber: unifiedItem.oldLineNumber ?? -1,
+ data: oldLineExtend.data,
+ onUpdate: diffFile.notifyAll,
+ })}
+ {(enableWrap ? true : width > 0) &&
+ newLineExtend?.data !== undefined &&
+ newLineExtend?.data !== null &&
+ renderExtendLine?.({
+ diffFile,
+ side: SplitSide.new,
+ lineNumber: unifiedItem.newLineNumber ?? -1,
+ data: newLineExtend.data,
+ onUpdate: diffFile.notifyAll,
+ })}
+
+ |
+
+ );
+};
+
+export const DiffUnifiedExtendLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableWrap,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableWrap: boolean;
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const unifiedItem = diffFile.getUnifiedLine(index);
+
+ const { oldLineExtend, newLineExtend } = useDiffContext(
+ useCallback(
+ (s) => ({
+ oldLineExtend: s.extendData?.oldFile?.[unifiedItem?.oldLineNumber ?? -1],
+ newLineExtend: s.extendData?.newFile?.[unifiedItem?.newLineNumber ?? -1],
+ }),
+ [unifiedItem.oldLineNumber, unifiedItem.newLineNumber]
+ )
+ );
+
+ const hasExtend = oldLineExtend?.data || newLineExtend?.data;
+
+ if (!hasExtend || !unifiedItem || unifiedItem.isHidden) return null;
+
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffUnifiedHunkLine.tsrx b/packages/octane/src/components/DiffUnifiedHunkLine.tsrx
new file mode 100644
index 0000000..9a2ade0
--- /dev/null
+++ b/packages/octane/src/components/DiffUnifiedHunkLine.tsrx
@@ -0,0 +1,147 @@
+import { composeLen } from "@git-diff-view/core";
+import {
+ diffAsideWidthName,
+ hunkContentBGName,
+ hunkContentColorName,
+ hunkLineNumberBGName,
+ plainLineNumberColorName,
+} from "@git-diff-view/utils";
+
+import { ExpandAll, ExpandDown, ExpandUp } from "./DiffExpand.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+const InternalDiffUnifiedHunkLine = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getUnifiedHunkLine(index);
+
+ const expandEnabled = diffFile.getExpandEnabled();
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const enableWrap = useDiffContext.useShallowStableSelector((s) => s.enableWrap);
+
+ const couldExpand = expandEnabled && currentHunk && currentHunk.unifiedInfo;
+
+ const isExpandAll =
+ currentHunk &&
+ currentHunk.unifiedInfo &&
+ currentHunk.unifiedInfo.endHiddenIndex - currentHunk.unifiedInfo.startHiddenIndex < composeLen;
+
+ const isFirstLine = currentHunk && currentHunk.isFirst;
+
+ const isLastLine = currentHunk && currentHunk.isLast;
+
+ return (
+
+ |
+ {couldExpand ? (
+ isFirstLine ? (
+
+ ) : isLastLine ? (
+
+ ) : isExpandAll ? (
+
+ ) : (
+ <>
+
+
+ >
+ )
+ ) : (
+
+ )}
+ |
+
+
+ {currentHunk.unifiedInfo?.plainText || currentHunk.text}
+
+ |
+
+ );
+};
+
+export const DiffUnifiedHunkLine = ({
+ index,
+ diffFile,
+ lineNumber,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+}) => {
+ const currentHunk = diffFile.getUnifiedHunkLine(index);
+
+ const currentIsShow =
+ currentHunk &&
+ currentHunk.unifiedInfo &&
+ currentHunk.unifiedInfo.startHiddenIndex < currentHunk.unifiedInfo.endHiddenIndex;
+
+ const currentIsPureHunk = currentHunk && diffFile._getIsPureDiffRender() && !currentHunk.unifiedInfo;
+
+ if (!currentIsShow && !currentIsPureHunk) return null;
+
+ return ;
+};
diff --git a/packages/octane/src/components/DiffUnifiedView.tsrx b/packages/octane/src/components/DiffUnifiedView.tsrx
new file mode 100644
index 0000000..aad0485
--- /dev/null
+++ b/packages/octane/src/components/DiffUnifiedView.tsrx
@@ -0,0 +1,180 @@
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+import { getUnifiedContentLine, SplitSide } from "@git-diff-view/core";
+import { diffFontSizeName, removeAllSelection, diffAsideWidthName, getDiffIdFromElement } from "@git-diff-view/utils";
+import { Fragment, memo, useEffect, useMemo, useRef } from "octane";
+// @ts-ignore
+import { useSyncExternalStore } from "octane";
+
+import { useTextWidth } from "../hooks/useTextWidth";
+
+import { DiffUnifiedContentLine } from "./DiffUnifiedContentLine.tsrx";
+import { DiffUnifiedExtendLine } from "./DiffUnifiedExtendLine.tsrx";
+import { DiffUnifiedHunkLine } from "./DiffUnifiedHunkLine.tsrx";
+import { DiffUnifiedWidgetLine } from "./DiffUnifiedWidgetLine.tsrx";
+import { useDiffViewContext } from "./DiffViewContext";
+import { DiffWidgetContext } from "./DiffWidgetContext";
+import { createDiffWidgetStore } from "./tools";
+
+import type { DiffFile } from "@git-diff-view/core";
+import type { NativeMouseEventHandler, OctaneStyle } from "../octane-types";
+
+export const DiffUnifiedView = memo(({ diffFile }: { diffFile: DiffFile }) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const ref = useRef(null);
+
+ const tempRef = useRef(undefined);
+
+ const useDiffContextRef = useRef(useDiffContext);
+
+ useDiffContextRef.current = useDiffContext;
+
+ // performance optimization
+ const useWidget = useMemo(() => createDiffWidgetStore(useDiffContextRef), []);
+
+ const contextValue = useMemo(() => ({ useWidget }), [useWidget]);
+
+ const { fontSize, enableWrap, enableHighlight, enableAddWidget, onCreateUseWidgetHook } =
+ useDiffContext.useShallowStableSelector((s) => ({
+ fontSize: s.fontSize,
+ enableWrap: s.enableWrap,
+ enableHighlight: s.enableHighlight,
+ enableAddWidget: s.enableAddWidget,
+ onCreateUseWidgetHook: s.onCreateUseWidgetHook,
+ }));
+
+ useSyncExternalStore(diffFile.subscribe, diffFile.getUpdateCount, diffFile.getUpdateCount);
+
+ useEffect(() => {
+ const { setWidget } = useWidget.getReadonlyState();
+
+ setWidget({});
+ }, [diffFile, useWidget]);
+
+ useEffect(() => {
+ onCreateUseWidgetHook?.(useWidget);
+ }, [useWidget, onCreateUseWidgetHook]);
+
+ const unifiedLineLength = Math.max(diffFile.unifiedLineLength, diffFile.fileLineLength);
+
+ const _width = useTextWidth({
+ text: unifiedLineLength.toString(),
+ font: useMemo(() => ({ fontSize: fontSize + "px", fontFamily: "Menlo, Consolas, monospace" }), [fontSize]),
+ });
+
+ const width = Math.max(40, _width + 10);
+
+ const lines = getUnifiedContentLine(diffFile);
+
+ const setStyle = (side?: SplitSide) => {
+ if (!ref.current) return;
+ if (!side) {
+ ref.current.textContent = "";
+ } else {
+ const id = `diff-root${diffFile.getId()}`;
+ ref.current.textContent = `#${id} [data-state="extend"] {user-select: none} \n#${id} [data-state="hunk"] {user-select: none} \n#${id} [data-state="widget"] {user-select: none}`;
+ }
+ };
+
+ const onMouseDown: NativeMouseEventHandler = (e) => {
+ let ele: Element | null = e.target as Element;
+
+ // need remove all the selection
+ if (ele && ele instanceof HTMLElement && ele.nodeName === "BUTTON") {
+ removeAllSelection();
+ return;
+ }
+
+ const id = getDiffIdFromElement(ele as HTMLElement);
+
+ if (id && id !== `diff-root${diffFile.getId()}`) {
+ return;
+ }
+
+ while (ele && ele instanceof HTMLElement) {
+ const state = ele.getAttribute("data-state");
+ if (state) {
+ if (state === "extend" || state === "hunk" || state === "widget") {
+ if (tempRef.current !== undefined) {
+ tempRef.current = undefined;
+ setStyle(undefined);
+ removeAllSelection();
+ }
+ return;
+ } else {
+ if (tempRef.current !== SplitSide.new) {
+ tempRef.current = SplitSide.new;
+ setStyle(SplitSide.new);
+ removeAllSelection();
+ }
+ return;
+ }
+ }
+
+ ele = ele.parentElement;
+ }
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ | line number |
+ line content |
+
+
+
+ {lines.map((item) => (
+
+
+
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+});
diff --git a/packages/octane/src/components/DiffUnifiedWidgetLine.tsrx b/packages/octane/src/components/DiffUnifiedWidgetLine.tsrx
new file mode 100644
index 0000000..74e29b0
--- /dev/null
+++ b/packages/octane/src/components/DiffUnifiedWidgetLine.tsrx
@@ -0,0 +1,110 @@
+import * as Octane from "octane";
+
+import { SplitSide } from "..";
+import { useDomWidth } from "../hooks/useDomWidth";
+
+import { useDiffViewContext } from "./DiffViewContext";
+import { useDiffWidgetContext } from "./DiffWidgetContext";
+
+import type { DiffFile } from "@git-diff-view/core";
+
+const InternalDiffUnifiedWidgetLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableWrap,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableWrap: boolean;
+}) => {
+ const { useWidget } = useDiffWidgetContext();
+
+ const setWidget = useWidget.getReadonlyState().setWidget;
+
+ const unifiedItem = diffFile.getUnifiedLine(index);
+
+ const onClose = () => setWidget({});
+
+ const widgetSide = useWidget.getReadonlyState().widgetSide;
+
+ const widgetLineNumber = useWidget.getReadonlyState().widgetLineNumber;
+
+ const oldWidget =
+ unifiedItem.oldLineNumber && widgetSide === SplitSide.old && widgetLineNumber === unifiedItem.oldLineNumber;
+
+ const newWidget =
+ unifiedItem.newLineNumber && widgetSide === SplitSide.new && widgetLineNumber === unifiedItem.newLineNumber;
+
+ const { useDiffContext } = useDiffViewContext();
+
+ // 需要显示的时候才进行方法订阅,可以大幅度提高性能
+ const renderWidgetLine = useDiffContext.useShallowStableSelector((s) => s.renderWidgetLine);
+
+ const width = useDomWidth({
+ selector: ".unified-diff-table-wrapper",
+ enable: typeof renderWidgetLine === "function",
+ });
+
+ if (!renderWidgetLine) return null;
+
+ return (
+
+ |
+
+ {(enableWrap ? true : width > 0) &&
+ oldWidget &&
+ renderWidgetLine?.({ diffFile, side: SplitSide.old, lineNumber: unifiedItem.oldLineNumber ?? -1, onClose })}
+ {(enableWrap ? true : width > 0) &&
+ newWidget &&
+ renderWidgetLine?.({ diffFile, side: SplitSide.new, lineNumber: unifiedItem.newLineNumber ?? -1, onClose })}
+
+ |
+
+ );
+};
+
+export const DiffUnifiedWidgetLine = ({
+ index,
+ diffFile,
+ lineNumber,
+ enableWrap,
+}: {
+ index: number;
+ diffFile: DiffFile;
+ lineNumber: number;
+ enableWrap: boolean;
+}) => {
+ const { useWidget } = useDiffWidgetContext();
+
+ const currentIsShow = useWidget.useShallowSelector(
+ Octane.useCallback(
+ (s) => {
+ const widgetLineNumber = s.widgetLineNumber;
+
+ const widgetSide = s.widgetSide;
+
+ const unifiedItem = diffFile.getUnifiedLine(index);
+
+ const oldWidget =
+ unifiedItem.oldLineNumber && widgetSide === SplitSide.old && widgetLineNumber === unifiedItem.oldLineNumber;
+
+ const newWidget =
+ unifiedItem.newLineNumber && widgetSide === SplitSide.new && widgetLineNumber === unifiedItem.newLineNumber;
+
+ const currentIsShow = oldWidget || newWidget;
+
+ return currentIsShow;
+ },
+ [diffFile, index]
+ ),
+ (p, c) => p === c
+ );
+
+ if (!currentIsShow) return null;
+
+ return (
+
+ );
+};
diff --git a/packages/octane/src/components/DiffView.tsrx b/packages/octane/src/components/DiffView.tsrx
new file mode 100644
index 0000000..cca6cb0
--- /dev/null
+++ b/packages/octane/src/components/DiffView.tsrx
@@ -0,0 +1,391 @@
+/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
+/* eslint-disable @typescript-eslint/ban-ts-comment */
+import { DiffFile, _cacheMap, SplitSide, highlighter as buildInHighlighter } from "@git-diff-view/core";
+import { diffFontSizeName, DiffModeEnum } from "@git-diff-view/utils";
+import { memo, useEffect, useMemo, useImperativeHandle, useRef } from "octane";
+
+import { useIsMounted } from "../hooks/useIsMounted";
+import { useUnmount } from "../hooks/useUnmount";
+
+import type { OctaneElement, OctaneImperativeRef, OctaneNode, OctaneRefObject, OctaneStyle } from "../octane-types";
+
+import { DiffSplitView } from "./DiffSplitView.tsrx";
+import { DiffUnifiedView } from "./DiffUnifiedView.tsrx";
+import { DiffViewContext } from "./DiffViewContext";
+import { createDiffConfigStore } from "./tools";
+// import { DiffSplitView } from "./v2/DiffSplitView_v2.tsrx";
+
+import type { createDiffWidgetStore } from "./tools";
+import type { DiffHighlighter, DiffHighlighterLang } from "@git-diff-view/core";
+
+_cacheMap.name = "@git-diff-view/octane";
+
+export { SplitSide, DiffModeEnum };
+
+export type DiffViewProps = {
+ data?: {
+ oldFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | string | null; content?: string | null };
+ newFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | string | null; content?: string | null };
+ hunks: string[];
+ };
+ extendData?: { oldFile?: Record; newFile?: Record };
+ diffFile?: DiffFile;
+ className?: string;
+ style?: OctaneStyle;
+ /**
+ * provide a custom highlighter
+ * eg: lowlight, refractor, starry-night, shiki
+ */
+ registerHighlighter?: Omit;
+ diffViewMode?: DiffModeEnum;
+ diffViewWrap?: boolean;
+ diffViewTheme?: "light" | "dark";
+ diffViewFontSize?: number;
+ diffViewHighlight?: boolean;
+ diffViewAddWidget?: boolean;
+ renderWidgetLine?: ({
+ diffFile,
+ side,
+ lineNumber,
+ onClose,
+ }: {
+ lineNumber: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ onClose: () => void;
+ }) => OctaneNode;
+ renderExtendLine?: ({
+ diffFile,
+ side,
+ data,
+ lineNumber,
+ onUpdate,
+ }: {
+ lineNumber: number;
+ side: SplitSide;
+ data: T;
+ diffFile: DiffFile;
+ onUpdate: () => void;
+ }) => OctaneNode;
+ onAddWidgetClick?: (lineNumber: number, side: SplitSide) => void;
+ onCreateUseWidgetHook?: (hook: ReturnType) => void;
+};
+
+type DiffViewProps_1 = Omit, "data"> & {
+ data?: {
+ oldFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | null; content?: string | null };
+ newFile?: { fileName?: string | null; fileLang?: DiffHighlighterLang | null; content?: string | null };
+ hunks: string[];
+ };
+};
+
+type DiffViewProps_2 = Omit, "data"> & {
+ data?: {
+ oldFile?: { fileName?: string | null; fileLang?: string | null; content?: string | null };
+ newFile?: { fileName?: string | null; fileLang?: string | null; content?: string | null };
+ hunks: string[];
+ };
+};
+
+const InternalDiffView = (
+ props: Omit, "data" | "registerHighlighter"> & {
+ isMounted: boolean;
+ wrapperRef: OctaneRefObject;
+ }
+) => {
+ const {
+ diffFile,
+ className,
+ style,
+ wrapperRef,
+ diffViewMode,
+ diffViewWrap,
+ diffViewFontSize,
+ diffViewHighlight,
+ renderWidgetLine,
+ renderExtendLine,
+ extendData,
+ diffViewAddWidget,
+ onAddWidgetClick,
+ onCreateUseWidgetHook,
+ isMounted,
+ } = props;
+
+ const diffFileId = useMemo(() => diffFile!.getId(), [diffFile]);
+
+ // performance optimization
+ const useDiffContext = useMemo(
+ () => createDiffConfigStore(props, diffFileId),
+ // eslint-disable-next-line react-hooks/exhaustive-deps
+ []
+ );
+
+ useEffect(() => {
+ const {
+ id,
+ setId,
+ mode,
+ setMode,
+ mounted,
+ setMounted,
+ enableAddWidget,
+ setEnableAddWidget,
+ enableHighlight,
+ setEnableHighlight,
+ enableWrap,
+ setEnableWrap,
+ setExtendData,
+ fontSize,
+ setFontSize,
+ onAddWidgetClick: _onAddWidgetClick,
+ setOnAddWidgetClick,
+ renderExtendLine: _renderExtendLine,
+ setRenderExtendLine,
+ renderWidgetLine: _renderWidgetLine,
+ setRenderWidgetLine,
+ onCreateUseWidgetHook: _onCreateUseWidgetHook,
+ setOnCreateUseWidgetHook,
+ } = useDiffContext.getReadonlyState();
+
+ if (diffFileId && diffFileId !== id) {
+ setId(diffFileId);
+ }
+
+ if (diffViewMode && diffViewMode !== mode) {
+ setMode(diffViewMode);
+ }
+
+ if (mounted !== isMounted) {
+ setMounted(isMounted);
+ }
+
+ if (diffViewAddWidget !== enableAddWidget) {
+ setEnableAddWidget(!!diffViewAddWidget);
+ }
+
+ if (diffViewHighlight !== enableHighlight) {
+ setEnableHighlight(!!diffViewHighlight);
+ }
+
+ if (diffViewWrap !== enableWrap) {
+ setEnableWrap(!!diffViewWrap);
+ }
+
+ if (extendData) {
+ setExtendData(extendData);
+ }
+
+ if (diffViewFontSize && diffViewFontSize !== fontSize) {
+ setFontSize(diffViewFontSize);
+ }
+
+ if (onAddWidgetClick !== _onAddWidgetClick.current) {
+ setOnAddWidgetClick({ current: onAddWidgetClick });
+ }
+
+ if (onCreateUseWidgetHook !== _onCreateUseWidgetHook) {
+ setOnCreateUseWidgetHook(onCreateUseWidgetHook);
+ }
+
+ if (renderExtendLine !== _renderExtendLine) {
+ setRenderExtendLine(renderExtendLine);
+ }
+
+ if (renderWidgetLine !== _renderWidgetLine) {
+ setRenderWidgetLine(renderWidgetLine);
+ }
+ }, [
+ useDiffContext,
+ diffViewFontSize,
+ diffViewHighlight,
+ diffViewMode,
+ diffViewWrap,
+ diffViewAddWidget,
+ diffFileId,
+ isMounted,
+ renderWidgetLine,
+ renderExtendLine,
+ extendData,
+ onAddWidgetClick,
+ onCreateUseWidgetHook,
+ ]);
+
+ useEffect(() => {
+ if (wrapperRef?.current) {
+ useDiffContext.getReadonlyState().setDom(wrapperRef?.current);
+ }
+ }, [useDiffContext, wrapperRef]);
+
+ const value = useMemo(() => ({ useDiffContext }), [useDiffContext]);
+
+ return (
+
+
+
+
+ {diffViewMode! & DiffModeEnum.Split ? (
+
+ ) : (
+
+ )}
+
+
+
+
+ );
+};
+
+const MemoedInternalDiffView = memo(InternalDiffView) as typeof InternalDiffView;
+
+const DiffViewWithRef = (
+ props: DiffViewProps & { ref?: OctaneImperativeRef<{ getDiffFileInstance: () => DiffFile | null }> }
+) => {
+ const { ref, registerHighlighter, data, diffViewTheme, diffFile: _diffFile, ...restProps } = props;
+
+ const diffFile = useMemo(() => {
+ if (_diffFile) {
+ // missing data for plain file render
+ // TODO next release update ?
+ // will cause more complex for diffFile flow control, keep current
+ const diffFile = DiffFile.createInstance({});
+ diffFile._mergeFullBundle(_diffFile._getFullBundle());
+ return diffFile;
+ } else if (data) {
+ return new DiffFile(
+ data?.oldFile?.fileName || "",
+ data?.oldFile?.content || "",
+ data?.newFile?.fileName || "",
+ data?.newFile?.content || "",
+ data?.hunks || [],
+ data?.oldFile?.fileLang || "",
+ data?.newFile?.fileLang || ""
+ );
+ }
+ return null;
+ }, [data, _diffFile]);
+
+ const diffFileRef = useRef(diffFile);
+
+ const wrapperRef = useRef(null);
+
+ // eslint-disable-next-line react-hooks/refs
+ if (diffFileRef.current && diffFileRef.current !== diffFile) {
+ // eslint-disable-next-line react-hooks/refs
+ diffFileRef.current.clear?.();
+ diffFileRef.current = diffFile;
+ }
+
+ const isMounted = useIsMounted();
+
+ useEffect(() => {
+ if (_diffFile && diffFile) {
+ _diffFile._addClonedInstance(diffFile);
+ return () => {
+ _diffFile._delClonedInstance(diffFile);
+ };
+ }
+ }, [diffFile, _diffFile]);
+
+ useEffect(() => {
+ if (!diffFile) return;
+ diffFile.initTheme(diffViewTheme);
+
+ diffFile.initRaw();
+
+ diffFile.buildSplitDiffLines();
+
+ diffFile.buildUnifiedDiffLines();
+ }, [diffFile, diffViewTheme]);
+
+ useEffect(() => {
+ if (!diffFile) return;
+
+ if (props.diffViewHighlight) {
+ if (registerHighlighter) {
+ if (
+ registerHighlighter.name !== diffFile._getHighlighterName() ||
+ registerHighlighter.type !== diffFile._getHighlighterType() ||
+ registerHighlighter.type !== "class"
+ ) {
+ diffFile.initSyntax({ registerHighlighter: registerHighlighter });
+ diffFile.notifyAll();
+ }
+ } else if (
+ (!diffFile._getIsCloned() && diffFile._getHighlighterName() !== buildInHighlighter.name) ||
+ diffFile._getHighlighterType() !== "class"
+ ) {
+ diffFile.initSyntax();
+ diffFile.notifyAll();
+ }
+ }
+ }, [diffFile, props.diffViewHighlight, registerHighlighter, diffViewTheme]);
+
+ useEffect(() => {
+ if (!diffFile) return;
+
+ const init = () => {
+ wrapperRef.current?.setAttribute("data-theme", diffFile._getTheme() || "light");
+ wrapperRef.current?.setAttribute("data-highlighter", diffFile._getHighlighterName());
+ };
+
+ init();
+
+ const cb = diffFile.subscribe(init);
+
+ return cb;
+ }, [diffFile, diffViewTheme]);
+
+ // fix react strict mode error
+ useUnmount(() => (__DEV__ ? diffFile?._destroy?.() : diffFile?.clear?.()), [diffFile]);
+
+ useImperativeHandle(ref, () => ({ getDiffFileInstance: () => diffFile }), [diffFile]);
+
+ if (!diffFile) return null;
+
+ return (
+
+ );
+};
+
+// type helper function
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+function OctaneDiffView(
+ props: DiffViewProps_1 & { ref?: OctaneImperativeRef<{ getDiffFileInstance: () => DiffFile | null }> }
+): OctaneElement;
+function OctaneDiffView(
+ props: DiffViewProps_2 & { ref?: OctaneImperativeRef<{ getDiffFileInstance: () => DiffFile | null }> }
+): OctaneElement;
+function OctaneDiffView(
+ _props: DiffViewProps & { ref?: OctaneImperativeRef<{ getDiffFileInstance: () => DiffFile | null }> }
+) {
+ return <>>;
+}
+
+export const DiffView = DiffViewWithRef as typeof OctaneDiffView;
+
+export const version = __VERSION__;
diff --git a/packages/octane/src/components/DiffViewContext.ts b/packages/octane/src/components/DiffViewContext.ts
new file mode 100644
index 0000000..9008699
--- /dev/null
+++ b/packages/octane/src/components/DiffViewContext.ts
@@ -0,0 +1,11 @@
+import { createContext, useContext } from "octane";
+
+import type { createDiffConfigStore } from "./tools";
+
+export const DiffViewContext = createContext<{
+ useDiffContext: ReturnType;
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+}>(null);
+
+export const useDiffViewContext = () => useContext(DiffViewContext);
diff --git a/packages/octane/src/components/DiffViewWithMultiSelect.tsrx b/packages/octane/src/components/DiffViewWithMultiSelect.tsrx
new file mode 100644
index 0000000..7523dd2
--- /dev/null
+++ b/packages/octane/src/components/DiffViewWithMultiSelect.tsrx
@@ -0,0 +1,323 @@
+import { useCallback, useEffect, useMemo, useRef, useImperativeHandle } from "octane";
+
+import { multiSelectClassNames, createDiffMultiSelectManager } from "..";
+import { useCallbackRef } from "../hooks/useCallbackRef";
+import { useUpdateEffect } from "../hooks/useUpdateEffect";
+
+import type { OctaneImperativeRef, OctaneNode } from "../octane-types";
+
+import { DiffModeEnum, DiffView, SplitSide } from "./DiffView.tsrx";
+
+import type {
+ MultiSelectResult,
+ LineRange,
+ MultiSelectState,
+ DiffFile,
+ DiffMultiSelectManager,
+ MultiSelectOptions,
+ extendDataToPreselectedLines,
+} from "..";
+import type { DiffViewProps } from "./DiffView.tsrx";
+
+export interface DiffViewWithMultiSelectProps extends Omit<
+ DiffViewProps,
+ "renderWidgetLine" | "onAddWidgetClick"
+> {
+ /**
+ * Enable multi-select feature
+ * @default true
+ */
+ enableMultiSelect?: boolean;
+
+ /**
+ * Callback when multi-line selection is complete
+ * Use this to open a comment dialog or handle the selection
+ */
+ onMultiSelectComplete?: (result: MultiSelectResult) => void;
+
+ /**
+ * Callback when selection changes (during drag)
+ */
+ onMultiSelectChange?: (range: LineRange | null, state: MultiSelectState) => void;
+
+ /**
+ * Custom function to scope selection to one hunk
+ * Return the scoped range or null to cancel selection
+ */
+ scopeMultiSelectToHunk?: (range: LineRange) => LineRange | null;
+
+ onAddWidgetClick?: (props: { lineNumber: number; fromLineNumber?: number; side: SplitSide }) => void;
+
+ renderWidgetLine?: (props: {
+ lineNumber: number;
+ fromLineNumber: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ onClose: () => void;
+ }) => OctaneNode;
+}
+
+export interface DiffViewWithMultiSelectRef {
+ getDiffFileInstance: () => DiffFile | null;
+ getSelectionResult: () => MultiSelectResult | null;
+ getSelectionState: () => MultiSelectState;
+ clearSelection: () => void;
+ setPreselectedLines: (lines: { old: number[]; new: number[] }) => void;
+}
+
+type MultiResult = ReturnType;
+
+/* eslint-disable @typescript-eslint/no-unnecessary-type-constraint */
+const InternalDiffViewWithMultiSelect = (
+ props: DiffViewWithMultiSelectProps & { ref?: OctaneImperativeRef }
+) => {
+ const {
+ ref,
+ enableMultiSelect = true,
+ extendData,
+ onMultiSelectComplete,
+ onMultiSelectChange,
+ scopeMultiSelectToHunk,
+ renderWidgetLine,
+ onAddWidgetClick,
+ diffViewMode = DiffModeEnum.SplitGitHub,
+ ...restProps
+ } = props;
+
+ const memoSelectChange = useCallbackRef(onMultiSelectChange);
+
+ const memoSelectComplete = useCallbackRef(onMultiSelectComplete);
+
+ const memoScopeSelectToHunk = useCallbackRef(scopeMultiSelectToHunk);
+
+ const containerRef = useRef(null);
+ const diffViewRef = useRef<{ getDiffFileInstance: () => DiffFile | null } | null>(null);
+ const managerRef = useRef(null);
+
+ const multiResultRef = useRef(undefined);
+
+ const isUnifiedMode = !(diffViewMode & DiffModeEnum.Split);
+
+ const updateMultiResult = useCallback((result?: MultiResult) => {
+ multiResultRef.current = result;
+ managerRef.current?.setPreselectedLines(result || { old: [], new: [] });
+ }, []);
+
+ useUpdateEffect(() => {
+ updateMultiResult(undefined);
+ }, [props.diffViewWrap, diffViewMode]);
+
+ const getDiffFile = useCallback(() => {
+ return diffViewRef.current?.getDiffFileInstance() ?? null;
+ }, []);
+
+ useEffect(() => {
+ const container = containerRef.current;
+ const diffFile = getDiffFile();
+
+ if (!container || !diffFile || !enableMultiSelect) {
+ managerRef.current?.destroy();
+ managerRef.current = null;
+ return;
+ }
+
+ const managerOptions: MultiSelectOptions = {
+ enabled: enableMultiSelect,
+ isUnifiedMode,
+ selectedClassName: multiSelectClassNames.selected,
+ onSelectionChange: (range, state) => {
+ if (state.isSelecting) {
+ containerRef.current?.classList.add(multiSelectClassNames.selecting);
+ } else {
+ containerRef.current?.classList.remove(multiSelectClassNames.selecting);
+ }
+ if (state.isSelecting && multiResultRef.current) {
+ updateMultiResult(undefined);
+ }
+ memoSelectChange?.(range, state);
+ },
+ onSelectionComplete: (result) => {
+ containerRef.current?.classList.remove(multiSelectClassNames.selecting);
+ if (result && result.lines.length > 0) {
+ memoSelectComplete?.(result);
+ const finalResult = {
+ [result.range.side as "old" | "new"]: [result.range.startLineNumber, result.range.endLineNumber],
+ } as MultiResult;
+ updateMultiResult(finalResult);
+ } else {
+ updateMultiResult(undefined);
+ }
+ },
+ scopeToHunk: memoScopeSelectToHunk,
+ };
+
+ if (managerRef.current) {
+ managerRef.current.updateContainer(container);
+ managerRef.current.updateDiffFile(diffFile);
+ managerRef.current.updateOptions(managerOptions);
+ } else {
+ managerRef.current = createDiffMultiSelectManager(container, diffFile, managerOptions);
+ }
+
+ return () => {
+ managerRef.current?.destroy();
+ managerRef.current = null;
+ };
+ }, [
+ enableMultiSelect,
+ isUnifiedMode,
+ memoScopeSelectToHunk,
+ memoSelectChange,
+ memoSelectComplete,
+ getDiffFile,
+ updateMultiResult,
+ ]);
+
+ const convertedExtendData = useMemo(() => {
+ if (!extendData) return undefined;
+
+ const result: { oldFile?: Record; newFile?: Record } = {};
+
+ if (extendData.oldFile) {
+ result.oldFile = {};
+ for (const [key, value] of Object.entries(extendData.oldFile)) {
+ result.oldFile[key] = { data: value.data };
+ }
+ }
+
+ if (extendData.newFile) {
+ result.newFile = {};
+ for (const [key, value] of Object.entries(extendData.newFile)) {
+ result.newFile[key] = { data: value.data };
+ }
+ }
+
+ return result;
+ }, [extendData]);
+
+ const internalRenderWidgetLine = useCallback(
+ ({
+ lineNumber,
+ side,
+ diffFile,
+ onClose,
+ }: {
+ lineNumber: number;
+ side: SplitSide;
+ diffFile: DiffFile;
+ onClose: () => void;
+ }) => {
+ if (!renderWidgetLine) return null;
+
+ const sideKey = side === SplitSide.old ? "old" : "new";
+ const multiResultItem = multiResultRef.current?.[sideKey] as number[];
+ const fromLineNumber = multiResultItem ? Math.min(...multiResultItem) : lineNumber;
+ const toLineNumber = multiResultItem ? Math.max(...multiResultItem) : lineNumber;
+
+ return renderWidgetLine({
+ lineNumber: toLineNumber,
+ fromLineNumber,
+ side,
+ diffFile,
+ onClose,
+ });
+ },
+ [renderWidgetLine]
+ );
+
+ const getSelectionResult = useCallback(() => {
+ return managerRef.current?.getSelectionResult() ?? null;
+ }, []);
+
+ const getSelectionState = useCallback(() => {
+ return (
+ managerRef.current?.getState() ?? {
+ isSelecting: false,
+ startInfo: null,
+ currentRange: null,
+ }
+ );
+ }, []);
+
+ const clearSelection = useCallback(() => {
+ managerRef.current?.clearSelection();
+ }, []);
+
+ const setPreselectedLines = updateMultiResult;
+
+ useImperativeHandle(
+ ref,
+ () => ({
+ getDiffFileInstance: getDiffFile,
+ getSelectionResult,
+ getSelectionState,
+ clearSelection,
+ setPreselectedLines,
+ }),
+ [getDiffFile, getSelectionResult, getSelectionState, clearSelection, setPreselectedLines]
+ );
+
+ return (
+
+ {
+ managerRef.current?.clearSelection();
+ const multiResult = multiResultRef.current;
+ if (multiResult) {
+ const currentSide = SplitSide[side] as unknown as "new" | "old";
+ const currentMultiResult = multiResult[currentSide] as number[];
+ const otherSide = currentSide === "new" ? "old" : "new";
+ const otherMultiResult = multiResult[otherSide] as number[];
+ if (currentMultiResult?.length) {
+ const max = Math.max(...currentMultiResult);
+ if (max === lineNum) {
+ const finalResult = { [currentSide]: currentMultiResult };
+ updateMultiResult(finalResult as MultiResult);
+ onAddWidgetClick?.({ lineNumber: max, fromLineNumber: Math.min(...currentMultiResult), side });
+ return;
+ }
+ }
+ if (isUnifiedMode && otherMultiResult?.length) {
+ const max = Math.max(...otherMultiResult);
+ const diffFile = getDiffFile();
+ if (!diffFile) return;
+ const index = diffFile.getUnifiedLineIndexByLineNumber(lineNum, side);
+ const unifiedItem = diffFile.getUnifiedLine(index);
+ const otherSideLineNum = side === SplitSide.old ? unifiedItem.newLineNumber : unifiedItem.oldLineNumber;
+ if (max === otherSideLineNum) {
+ const finalResult = { [otherSide]: otherMultiResult };
+ updateMultiResult(finalResult as MultiResult);
+ onAddWidgetClick?.({
+ lineNumber: max,
+ fromLineNumber: Math.min(...otherMultiResult),
+ side: otherSide === "old" ? SplitSide.old : SplitSide.new,
+ });
+ return;
+ }
+ }
+ updateMultiResult(undefined);
+ onAddWidgetClick?.({ lineNumber: lineNum, fromLineNumber: lineNum, side });
+ } else {
+ updateMultiResult(undefined);
+ onAddWidgetClick?.({ lineNumber: lineNum, fromLineNumber: lineNum, side });
+ }
+ }}
+ renderWidgetLine={renderWidgetLine ? internalRenderWidgetLine : undefined}
+ />
+
+ );
+};
+
+// type helper function
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+function OctaneDiffView(
+ _props: DiffViewWithMultiSelectProps & { ref?: OctaneImperativeRef }
+) {
+ return <>>;
+}
+
+export const DiffViewWithMultiSelect = InternalDiffViewWithMultiSelect as typeof OctaneDiffView;
diff --git a/packages/octane/src/components/DiffWidgetContext.ts b/packages/octane/src/components/DiffWidgetContext.ts
new file mode 100644
index 0000000..b8f3df7
--- /dev/null
+++ b/packages/octane/src/components/DiffWidgetContext.ts
@@ -0,0 +1,17 @@
+import { createContext, useContext } from "octane";
+
+import type { SplitSide } from "..";
+import type { Ref, UseSelectorWithStore } from "reactivity-store/octane";
+
+export const DiffWidgetContext = createContext<{
+ useWidget: UseSelectorWithStore<{
+ widgetSide: Ref;
+ widgetLineNumber: Ref;
+
+ setWidget: (props: { side?: SplitSide; lineNumber?: number }) => void;
+ }>;
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+}>(null);
+
+export const useDiffWidgetContext = () => useContext(DiffWidgetContext);
diff --git a/packages/octane/src/components/tools.ts b/packages/octane/src/components/tools.ts
new file mode 100644
index 0000000..bffdc5a
--- /dev/null
+++ b/packages/octane/src/components/tools.ts
@@ -0,0 +1,139 @@
+import { createStore, ref } from "reactivity-store/octane";
+
+import type { OctaneRefObject } from "../octane-types";
+import type { DiffModeEnum, DiffViewProps, SplitSide } from "./DiffView.tsrx";
+
+export const createDiffConfigStore = (props: DiffViewProps & { isMounted: boolean }, diffFileId: string) => {
+ return createStore(() => {
+ const dom = ref();
+
+ const setDom = (_dom: HTMLElement) => (dom.value = _dom);
+
+ const id = ref(diffFileId);
+
+ const setId = (_id: string) => (id.value = _id);
+
+ const mode = ref(props.diffViewMode);
+
+ const setMode = (_mode: DiffModeEnum) => (mode.value = _mode);
+
+ const mounted = ref(props.isMounted);
+
+ const setMounted = (_mounted: boolean) => (mounted.value = _mounted);
+
+ const enableWrap = ref(props.diffViewWrap);
+
+ const setEnableWrap = (_enableWrap: boolean) => (enableWrap.value = _enableWrap);
+
+ const enableAddWidget = ref(props.diffViewAddWidget);
+
+ const setEnableAddWidget = (_enableAddWidget: boolean) => (enableAddWidget.value = _enableAddWidget);
+
+ const enableHighlight = ref(props.diffViewHighlight);
+
+ const setEnableHighlight = (_enableHighlight: boolean) => (enableHighlight.value = _enableHighlight);
+
+ const fontSize = ref(props.diffViewFontSize);
+
+ const setFontSize = (_fontSize: number) => (fontSize.value = _fontSize);
+
+ const extendData = ref({
+ oldFile: { ...props.extendData?.oldFile },
+ newFile: { ...props.extendData?.newFile },
+ });
+
+ const setExtendData = (__extendData: DiffViewProps["extendData"]) => {
+ const _extendData = __extendData || {};
+ const existOldKeys = Object.keys(extendData.value.oldFile || {});
+ const inComingOldKeys = Object.keys(_extendData.oldFile || {});
+ for (const key of existOldKeys) {
+ if (!inComingOldKeys.includes(key)) {
+ delete extendData.value.oldFile[key];
+ }
+ }
+ for (const key of inComingOldKeys) {
+ extendData.value.oldFile[key] = _extendData.oldFile![key];
+ }
+ const existNewKeys = Object.keys(extendData.value.newFile || {});
+ const inComingNewKeys = Object.keys(_extendData.newFile || {});
+ for (const key of existNewKeys) {
+ if (!inComingNewKeys.includes(key)) {
+ delete extendData.value.newFile[key];
+ }
+ }
+ for (const key of inComingNewKeys) {
+ extendData.value.newFile[key] = _extendData.newFile![key];
+ }
+ };
+
+ const renderWidgetLine = ref(props.renderWidgetLine);
+
+ const setRenderWidgetLine = (_renderWidgetLine: typeof renderWidgetLine.value) =>
+ (renderWidgetLine.value = _renderWidgetLine);
+
+ const renderExtendLine = ref(props.renderExtendLine);
+
+ const setRenderExtendLine = (_renderExtendLine: typeof renderExtendLine.value) =>
+ (renderExtendLine.value = _renderExtendLine);
+
+ const onCreateUseWidgetHook = ref(props.onCreateUseWidgetHook);
+
+ const setOnCreateUseWidgetHook = (_onCreateUseWidgetHook: typeof onCreateUseWidgetHook.value) =>
+ (onCreateUseWidgetHook.value = _onCreateUseWidgetHook);
+
+ // 避免无意义的订阅
+ const onAddWidgetClick = { current: props.onAddWidgetClick };
+
+ const setOnAddWidgetClick = (_onAddWidgetClick: typeof onAddWidgetClick) =>
+ (onAddWidgetClick.current = _onAddWidgetClick.current);
+
+ return {
+ id,
+ setId,
+ dom,
+ setDom,
+ mode,
+ setMode,
+ mounted,
+ setMounted,
+ enableWrap,
+ setEnableWrap,
+ enableAddWidget,
+ setEnableAddWidget,
+ enableHighlight,
+ setEnableHighlight,
+ fontSize,
+ setFontSize,
+ extendData,
+ setExtendData,
+ renderWidgetLine,
+ setRenderWidgetLine,
+ renderExtendLine,
+ setRenderExtendLine,
+ onAddWidgetClick,
+ setOnAddWidgetClick,
+ onCreateUseWidgetHook,
+ setOnCreateUseWidgetHook,
+ };
+ });
+};
+
+export const createDiffWidgetStore = (useDiffContextRef: OctaneRefObject>) => {
+ return createStore(() => {
+ const widgetSide = ref(undefined);
+
+ const widgetLineNumber = ref(undefined);
+
+ const setWidget = ({ side, lineNumber }: { side?: SplitSide; lineNumber?: number }) => {
+ const { renderWidgetLine } = useDiffContextRef.current?.getReadonlyState?.() || {};
+
+ if (typeof renderWidgetLine !== "function") return;
+
+ widgetSide.value = side;
+
+ widgetLineNumber.value = lineNumber;
+ };
+
+ return { widgetSide, widgetLineNumber, setWidget };
+ });
+};
diff --git a/packages/octane/src/global.d.ts b/packages/octane/src/global.d.ts
new file mode 100644
index 0000000..88be071
--- /dev/null
+++ b/packages/octane/src/global.d.ts
@@ -0,0 +1,12 @@
+declare global {
+ const __DEV__: boolean;
+ const __VERSION__: string;
+
+ namespace NodeJS {
+ interface ProcessEnv {
+ NODE_ENV: "development" | "production" | "test";
+ }
+ }
+}
+
+export {};
diff --git a/packages/octane/src/hooks/useCallbackRef.ts b/packages/octane/src/hooks/useCallbackRef.ts
new file mode 100644
index 0000000..8f54cd0
--- /dev/null
+++ b/packages/octane/src/hooks/useCallbackRef.ts
@@ -0,0 +1,12 @@
+/* eslint-disable @typescript-eslint/no-unsafe-function-type */
+import { useCallback, useRef } from "octane";
+
+export const useCallbackRef = (cb?: T) => {
+ const cbRef = useRef(cb);
+
+ cbRef.current = cb;
+
+ return useCallback((...args: any[]) => {
+ return cbRef.current?.(...args);
+ }, []) as unknown as T;
+};
diff --git a/packages/octane/src/hooks/useDomWidth.ts b/packages/octane/src/hooks/useDomWidth.ts
new file mode 100644
index 0000000..6097b4a
--- /dev/null
+++ b/packages/octane/src/hooks/useDomWidth.ts
@@ -0,0 +1,74 @@
+import { getElementRoot } from "@git-diff-view/utils";
+import { useEffect, useState } from "octane";
+
+import { useDiffViewContext } from "../components/DiffViewContext";
+
+export type ObserveElement = HTMLElement & {
+ __observeCallback?: Set<() => void>;
+ __observeInstance?: ResizeObserver;
+};
+
+export const useDomWidth = ({ selector, enable }: { selector: string; enable: boolean }) => {
+ const [width, setWidth] = useState(0);
+
+ const { useDiffContext } = useDiffViewContext();
+
+ const { id, mounted, dom } = useDiffContext.useShallowStableSelector((s) => ({
+ id: s.id,
+ mounted: s.mounted,
+ dom: s.dom,
+ }));
+
+ useEffect(() => {
+ if (enable) {
+ const rootDocument = getElementRoot(dom as HTMLDivElement);
+
+ const container = rootDocument.querySelector(`#diff-root${id}`);
+
+ const wrapper = container?.querySelector(selector);
+
+ if (!wrapper) return;
+
+ const typedWrapper = wrapper as ObserveElement;
+
+ const cb = () => {
+ const rect = wrapper?.getBoundingClientRect();
+ setWidth(rect?.width ?? 0);
+ };
+
+ cb();
+
+ const cleanCb = () => {
+ typedWrapper?.__observeCallback?.delete(cb);
+ if (typedWrapper?.__observeCallback?.size === 0) {
+ typedWrapper.__observeInstance?.disconnect();
+ typedWrapper.removeAttribute("data-observe");
+ delete typedWrapper.__observeCallback;
+ delete typedWrapper.__observeInstance;
+ }
+ };
+
+ if (typedWrapper.__observeCallback) {
+ typedWrapper.__observeCallback.add(cb);
+
+ return () => cleanCb();
+ }
+
+ typedWrapper.__observeCallback = new Set();
+
+ typedWrapper.__observeCallback.add(cb);
+
+ const observer = new ResizeObserver(() => typedWrapper?.__observeCallback?.forEach((cb) => cb()));
+
+ typedWrapper.__observeInstance = observer;
+
+ observer.observe(typedWrapper);
+
+ typedWrapper.setAttribute("data-observe", "height");
+
+ return () => cleanCb();
+ }
+ }, [selector, enable, id, mounted, dom]);
+
+ return width;
+};
diff --git a/packages/octane/src/hooks/useIsMounted.ts b/packages/octane/src/hooks/useIsMounted.ts
new file mode 100644
index 0000000..70f68e9
--- /dev/null
+++ b/packages/octane/src/hooks/useIsMounted.ts
@@ -0,0 +1,11 @@
+import { useEffect, useState } from "octane";
+
+export const useIsMounted = () => {
+ const [isMounted, setIsMounted] = useState(false);
+
+ useEffect(() => {
+ setIsMounted(true);
+ }, []);
+
+ return isMounted;
+};
diff --git a/packages/octane/src/hooks/useSafeLayout.ts b/packages/octane/src/hooks/useSafeLayout.ts
new file mode 100644
index 0000000..c303456
--- /dev/null
+++ b/packages/octane/src/hooks/useSafeLayout.ts
@@ -0,0 +1,5 @@
+import { useEffect, useLayoutEffect } from "octane";
+
+const isClient = typeof window !== "undefined";
+
+export const useSafeLayout = isClient ? useLayoutEffect : useEffect;
diff --git a/packages/octane/src/hooks/useSyncHeight.ts b/packages/octane/src/hooks/useSyncHeight.ts
new file mode 100644
index 0000000..0db003a
--- /dev/null
+++ b/packages/octane/src/hooks/useSyncHeight.ts
@@ -0,0 +1,94 @@
+import { getElementRoot } from "@git-diff-view/utils";
+import { useEffect } from "octane";
+
+import { useDiffViewContext } from "../components/DiffViewContext";
+
+import type { ObserveElement } from "./useDomWidth";
+
+export const useSyncHeight = ({
+ selector,
+ wrapper,
+ side,
+ enable,
+}: {
+ selector: string;
+ wrapper?: string;
+ side: string;
+ enable: boolean;
+}) => {
+ const { useDiffContext } = useDiffViewContext();
+
+ const { id, mounted, dom } = useDiffContext.useShallowStableSelector((s) => ({
+ id: s.id,
+ mounted: s.mounted,
+ dom: s.dom,
+ }));
+
+ useEffect(() => {
+ if (enable) {
+ const rootDocument = getElementRoot(dom as HTMLDivElement);
+
+ const container = rootDocument.querySelector(`#diff-root${id}`);
+
+ const elements = Array.from(container?.querySelectorAll(selector) || []);
+
+ const wrappers = wrapper ? Array.from(container?.querySelectorAll(wrapper) || []) : elements;
+
+ if (elements.length === 2 && wrappers.length === 2) {
+ const ele1 = elements[0] as HTMLElement;
+ const ele2 = elements[1] as HTMLElement;
+
+ const wrapper1 = wrappers[0] as HTMLElement;
+ const wrapper2 = wrappers[1] as HTMLElement;
+
+ const target = ele1.getAttribute("data-side") === side ? ele1 : ele2;
+
+ const typedTarget = target as ObserveElement;
+
+ const cb = () => {
+ ele1.style.height = "auto";
+ ele2.style.height = "auto";
+ const rect1 = ele1.getBoundingClientRect();
+ const rect2 = ele2.getBoundingClientRect();
+ const maxHeight = Math.max(rect1.height, rect2.height);
+ wrapper1.style.height = maxHeight + "px";
+ wrapper2.style.height = maxHeight + "px";
+ wrapper1.setAttribute("data-sync-height", String(maxHeight));
+ wrapper2.setAttribute("data-sync-height", String(maxHeight));
+ };
+
+ cb();
+
+ const cleanCb = () => {
+ typedTarget?.__observeCallback?.delete(cb);
+ if (typedTarget?.__observeCallback?.size === 0) {
+ typedTarget.__observeInstance?.disconnect();
+ typedTarget.removeAttribute("data-observe");
+ delete typedTarget.__observeCallback;
+ delete typedTarget.__observeInstance;
+ }
+ };
+
+ if (typedTarget.__observeCallback) {
+ typedTarget.__observeCallback.add(cb);
+
+ return () => cleanCb();
+ }
+
+ typedTarget.__observeCallback = new Set();
+
+ typedTarget.__observeCallback.add(cb);
+
+ const observer = new ResizeObserver(() => typedTarget?.__observeCallback?.forEach((cb) => cb()));
+
+ typedTarget.__observeInstance = observer;
+
+ observer.observe(target);
+
+ target.setAttribute("data-observe", "height");
+
+ return () => cleanCb();
+ }
+ }
+ }, [selector, enable, side, id, wrapper, mounted, dom]);
+};
diff --git a/packages/octane/src/hooks/useTextWidth.ts b/packages/octane/src/hooks/useTextWidth.ts
new file mode 100644
index 0000000..5b70acf
--- /dev/null
+++ b/packages/octane/src/hooks/useTextWidth.ts
@@ -0,0 +1,27 @@
+import { getTextMeasureInstance } from "@git-diff-view/utils";
+import { useState } from "octane";
+
+import { useSafeLayout } from "./useSafeLayout";
+
+export const useTextWidth = ({
+ text,
+ font,
+}: {
+ text: string;
+ font: { fontFamily?: string; fontStyle?: string; fontSize?: string };
+}) => {
+ const [width, setWidth] = useState(() => {
+ const fontSize = parseInt(font.fontSize || "13");
+ let baseSize = 6;
+ baseSize += fontSize > 10 ? (fontSize - 10) * 0.6 : 0;
+ return baseSize * text.length;
+ });
+
+ useSafeLayout(() => {
+ const width = getTextMeasureInstance().measure(text, font);
+
+ setWidth(width);
+ }, [text, font]);
+
+ return width;
+};
diff --git a/packages/octane/src/hooks/useUnmount.ts b/packages/octane/src/hooks/useUnmount.ts
new file mode 100644
index 0000000..72beadb
--- /dev/null
+++ b/packages/octane/src/hooks/useUnmount.ts
@@ -0,0 +1,9 @@
+import { useEffect, useRef } from "octane";
+
+export const useUnmount = (cb: () => void, deps: any[]) => {
+ const ref = useRef(cb);
+
+ ref.current = cb;
+
+ useEffect(() => ref.current, deps);
+};
diff --git a/packages/octane/src/hooks/useUpdateEffect.ts b/packages/octane/src/hooks/useUpdateEffect.ts
new file mode 100644
index 0000000..9d40b20
--- /dev/null
+++ b/packages/octane/src/hooks/useUpdateEffect.ts
@@ -0,0 +1,15 @@
+import { useEffect, useRef } from "octane";
+
+type DependencyList = unknown[];
+type EffectCallback = () => void | (() => void);
+
+export const useUpdateEffect = (effect: EffectCallback, deps: DependencyList) => {
+ const isMounted = useRef(false);
+
+ useEffect(() => {
+ if (isMounted.current) {
+ return effect();
+ }
+ isMounted.current = true;
+ }, deps);
+};
diff --git a/packages/octane/src/index.ts b/packages/octane/src/index.ts
new file mode 100644
index 0000000..9938403
--- /dev/null
+++ b/packages/octane/src/index.ts
@@ -0,0 +1,4 @@
+export * from "./components/DiffView.tsrx";
+export * from "./components/DiffViewWithMultiSelect.tsrx";
+
+export * from "@git-diff-view/core";
diff --git a/packages/octane/src/octane-types.ts b/packages/octane/src/octane-types.ts
new file mode 100644
index 0000000..a188ac4
--- /dev/null
+++ b/packages/octane/src/octane-types.ts
@@ -0,0 +1,15 @@
+import type { OctaneNode } from "octane";
+import type { Octane } from "octane/jsx-runtime";
+
+export type { OctaneNode };
+
+export type OctaneElement = Octane.JSX.Element;
+export type OctaneImperativeRef = { current: T | null } | ((value: T | null) => void);
+
+export interface OctaneRefObject {
+ current: T;
+}
+
+export type OctaneStyle = Exclude;
+
+export type NativeMouseEventHandler = (event: MouseEvent & { currentTarget: T }) => void;
diff --git a/packages/octane/src/tailwind.css b/packages/octane/src/tailwind.css
new file mode 100644
index 0000000..60012bc
--- /dev/null
+++ b/packages/octane/src/tailwind.css
@@ -0,0 +1,3 @@
+@import url(./_base.css);
+@import url(./_com.css);
+@import url(./_theme.css);
diff --git a/packages/octane/tailwind.config.cjs b/packages/octane/tailwind.config.cjs
new file mode 100644
index 0000000..f3db03c
--- /dev/null
+++ b/packages/octane/tailwind.config.cjs
@@ -0,0 +1,8 @@
+/** @type {import('tailwindcss').Config} */
+module.exports = {
+ content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx,tsrx}"],
+ theme: {
+ extend: {},
+ },
+ plugins: [],
+};
diff --git a/packages/octane/tests/client/diff-view.test.ts b/packages/octane/tests/client/diff-view.test.ts
new file mode 100644
index 0000000..321fcc3
--- /dev/null
+++ b/packages/octane/tests/client/diff-view.test.ts
@@ -0,0 +1,163 @@
+import { render, waitFor } from "@octanejs/testing-library";
+import { describe, expect, it, vi } from "vitest";
+
+import { DiffModeEnum, DiffView, DiffViewWithMultiSelect, type DiffViewWithMultiSelectRef } from "../../src";
+import { representativeDiff } from "../fixtures";
+
+import { DualDiffViews, HookLifecycleFixture, type DiffViewHandle } from "./fixtures.tsrx";
+
+describe("@git-diff-view/octane DiffView", () => {
+ it("renders the representative unified diff with theme, wrapping and font configuration", async () => {
+ const view = render(DiffView, {
+ props: {
+ data: representativeDiff,
+ diffViewFontSize: 12,
+ diffViewHighlight: false,
+ diffViewMode: DiffModeEnum.Unified,
+ diffViewTheme: "dark" as const,
+ diffViewWrap: true,
+ },
+ });
+
+ await waitFor(() => expect(view.container.querySelector(".unified-diff-view")).not.toBeNull());
+
+ const root = view.container.querySelector('[data-component="git-diff-view"]');
+ expect(root?.getAttribute("data-theme")).toBe("dark");
+ expect(view.container.querySelector(".unified-diff-view-wrap")).not.toBeNull();
+ expect(view.container.querySelector(".diff-style-root")?.getAttribute("style")).toContain("12px");
+ expect(view.container.textContent).toContain("export const value");
+ expect(view.container.textContent).toContain("stable");
+ });
+
+ it("updates from unified to split mode without replacing the public component", async () => {
+ const baseProps = {
+ data: representativeDiff,
+ diffViewHighlight: false,
+ diffViewMode: DiffModeEnum.Unified,
+ };
+ const view = render(DiffView, { props: baseProps });
+
+ await waitFor(() => expect(view.container.querySelector(".unified-diff-view")).not.toBeNull());
+ view.rerender({ props: { ...baseProps, diffViewMode: DiffModeEnum.Split } });
+
+ await waitFor(() => expect(view.container.querySelector(".split-diff-view")).not.toBeNull());
+ expect(view.container.querySelector(".unified-diff-view")).toBeNull();
+ expect(view.container.querySelector(".old-diff-table")).not.toBeNull();
+ expect(view.container.querySelector(".new-diff-table")).not.toBeNull();
+ });
+
+ it("exposes and clears the imperative DiffFile handle", async () => {
+ let handle: { getDiffFileInstance: () => unknown } | null = null;
+ const view = render(DiffView, {
+ props: {
+ data: representativeDiff,
+ diffViewHighlight: false,
+ diffViewMode: DiffModeEnum.Unified,
+ ref: (value: typeof handle) => {
+ handle = value;
+ },
+ },
+ });
+
+ await waitFor(() => expect(handle?.getDiffFileInstance()).not.toBeNull());
+ view.unmount();
+ expect(handle).toBeNull();
+ });
+
+ it("renders the multi-select adapter and exposes its complete imperative surface", async () => {
+ const handle: { current: DiffViewWithMultiSelectRef | null } = { current: null };
+ const view = render(DiffViewWithMultiSelect, {
+ props: {
+ data: representativeDiff,
+ diffViewHighlight: false,
+ diffViewMode: DiffModeEnum.Unified,
+ ref: (value: DiffViewWithMultiSelectRef | null) => {
+ handle.current = value;
+ },
+ },
+ });
+
+ await waitFor(() => expect(handle.current?.getDiffFileInstance()).not.toBeNull());
+ expect(view.container.querySelector(".diff-multiselect-wrapper")).not.toBeNull();
+ expect(handle.current?.getSelectionResult()).toBeNull();
+ expect(handle.current?.getSelectionState()).toMatchObject({ isSelecting: false });
+ handle.current?.clearSelection();
+ handle.current?.setPreselectedLines({ old: [1], new: [1] });
+ });
+
+ it("isolates contexts, resize observers and state across sibling instances and remounts", async () => {
+ const firstHandle: { current: DiffViewHandle | null } = { current: null };
+ const secondHandle: { current: DiffViewHandle | null } = { current: null };
+ const props = {
+ firstMode: DiffModeEnum.Unified,
+ onFirstRef: (value: DiffViewHandle | null) => {
+ firstHandle.current = value;
+ },
+ onSecondRef: (value: DiffViewHandle | null) => {
+ secondHandle.current = value;
+ },
+ showFirst: true,
+ };
+ const view = render(DualDiffViews, { props });
+
+ await waitFor(() => {
+ expect(view.container.querySelector('[data-instance="first"] [data-extension="first-extension"]')).not.toBeNull();
+ expect(
+ view.container.querySelector('[data-instance="second"] [data-extension="second-extension"]')
+ ).not.toBeNull();
+ });
+
+ const first = view.container.querySelector('[data-instance="first"]')!;
+ const second = view.container.querySelector('[data-instance="second"]')!;
+ expect(first.querySelector('[data-component="git-diff-view"]')?.getAttribute("data-theme")).toBe("dark");
+ expect(second.querySelector('[data-component="git-diff-view"]')?.getAttribute("data-theme")).toBe("light");
+ expect(first.querySelector(".unified-diff-view")).not.toBeNull();
+ expect(second.querySelector(".split-diff-view")).not.toBeNull();
+ expect(first.querySelector("[data-observe]")).not.toBeNull();
+ expect(second.querySelector("[data-observe]")).not.toBeNull();
+
+ const originalFirstFile = firstHandle.current?.getDiffFileInstance();
+ const originalSecondFile = secondHandle.current?.getDiffFileInstance();
+ expect(originalFirstFile).not.toBe(originalSecondFile);
+
+ view.rerender({ props: { ...props, firstMode: DiffModeEnum.Split } });
+ await waitFor(() =>
+ expect(view.container.querySelector('[data-instance="first"] .split-diff-view')).not.toBeNull()
+ );
+ expect(view.container.querySelector('[data-instance="second"] .split-diff-view')).not.toBeNull();
+ expect(secondHandle.current?.getDiffFileInstance()).toBe(originalSecondFile);
+
+ view.rerender({ props: { ...props, firstMode: DiffModeEnum.Split, showFirst: false } });
+ await waitFor(() => expect(firstHandle.current).toBeNull());
+ expect(view.container.querySelector('[data-instance="first"]')).toBeNull();
+ expect(view.container.querySelector('[data-instance="second"] [data-observe]')).not.toBeNull();
+ expect(secondHandle.current?.getDiffFileInstance()).toBe(originalSecondFile);
+
+ view.rerender({ props });
+ await waitFor(() => expect(firstHandle.current?.getDiffFileInstance()).not.toBeNull());
+ expect(firstHandle.current?.getDiffFileInstance()).not.toBe(originalFirstFile);
+ expect(secondHandle.current?.getDiffFileInstance()).toBe(originalSecondFile);
+ });
+
+ it("keeps callback, update-effect and unmount hook state independent", async () => {
+ const onUpdate = vi.fn<(id: string, value: number) => void>();
+ const onUnmount = vi.fn<(id: string) => void>();
+ const props = { firstValue: 1, onUnmount, onUpdate, showFirst: true };
+ const view = render(HookLifecycleFixture, { props });
+
+ expect(onUpdate).not.toHaveBeenCalled();
+ view.rerender({ props: { ...props, firstValue: 2 } });
+ await waitFor(() => expect(onUpdate).toHaveBeenCalledWith("first", 2));
+ expect(onUpdate).not.toHaveBeenCalledWith("second", expect.anything());
+
+ view.rerender({ props: { ...props, firstValue: 2, showFirst: false } });
+ await waitFor(() => expect(onUnmount).toHaveBeenCalledWith("first"));
+ expect(view.container.querySelector('[data-hook-probe="second"]')?.textContent).toBe("10");
+ expect(onUnmount).not.toHaveBeenCalledWith("second");
+
+ view.rerender({ props });
+ view.rerender({ props: { ...props, firstValue: 3 } });
+ await waitFor(() => expect(onUpdate).toHaveBeenCalledWith("first", 3));
+ expect(onUpdate.mock.calls.filter(([id]) => id === "second")).toHaveLength(0);
+ });
+});
diff --git a/packages/octane/tests/client/fixtures.tsrx b/packages/octane/tests/client/fixtures.tsrx
new file mode 100644
index 0000000..55104e2
--- /dev/null
+++ b/packages/octane/tests/client/fixtures.tsrx
@@ -0,0 +1,93 @@
+import { DiffModeEnum, DiffView, type DiffViewWithMultiSelectRef } from "../../src/index";
+import { useCallbackRef } from "../../src/hooks/useCallbackRef";
+import { useUnmount } from "../../src/hooks/useUnmount";
+import { useUpdateEffect } from "../../src/hooks/useUpdateEffect";
+import { representativeDiff } from "../fixtures";
+
+export type DiffViewHandle = Pick;
+
+type DualDiffViewsProps = {
+ firstMode: DiffModeEnum;
+ onFirstRef: (value: DiffViewHandle | null) => void;
+ onSecondRef: (value: DiffViewHandle | null) => void;
+ showFirst: boolean;
+};
+
+const renderExtension = ({ data }: { data: string }) => {data};
+
+export function DualDiffViews({ firstMode, onFirstRef, onSecondRef, showFirst }: DualDiffViewsProps) {
+ return (
+
+ {showFirst ? (
+
+ ) : null}
+
+
+ );
+}
+
+type HookLifecycleFixtureProps = {
+ firstValue: number;
+ onUnmount: (id: string) => void;
+ onUpdate: (id: string, value: number) => void;
+ showFirst: boolean;
+};
+
+function HookLifecycleProbe({
+ id,
+ onUnmount,
+ onUpdate,
+ value,
+}: {
+ id: string;
+ onUnmount: (id: string) => void;
+ onUpdate: (id: string, value: number) => void;
+ value: number;
+}) {
+ const notifyUpdate = useCallbackRef(onUpdate);
+
+ useUpdateEffect(() => notifyUpdate(id, value), [value]);
+ useUnmount(() => onUnmount(id), [id]);
+
+ return {value};
+}
+
+export function HookLifecycleFixture({
+ firstValue,
+ onUnmount,
+ onUpdate,
+ showFirst,
+}: HookLifecycleFixtureProps) {
+ return (
+
+ {showFirst ? (
+
+ ) : null}
+
+
+ );
+}
diff --git a/packages/octane/tests/fixtures.ts b/packages/octane/tests/fixtures.ts
new file mode 100644
index 0000000..2b1c2a3
--- /dev/null
+++ b/packages/octane/tests/fixtures.ts
@@ -0,0 +1,22 @@
+export const representativeDiff = {
+ oldFile: {
+ fileName: "src/example.ts",
+ fileLang: "typescript",
+ content: "export const value = 1;\nexport const stable = true;\n",
+ },
+ newFile: {
+ fileName: "src/example.ts",
+ fileLang: "typescript",
+ content: "export const value = 2;\nexport const stable = true;\n",
+ },
+ hunks: [
+ [
+ "--- a/src/example.ts",
+ "+++ b/src/example.ts",
+ "@@ -1,2 +1,2 @@",
+ "-export const value = 1;",
+ "+export const value = 2;",
+ " export const stable = true;",
+ ].join("\n"),
+ ],
+};
diff --git a/packages/octane/tests/setup.ts b/packages/octane/tests/setup.ts
new file mode 100644
index 0000000..f9dc994
--- /dev/null
+++ b/packages/octane/tests/setup.ts
@@ -0,0 +1,49 @@
+import { cleanup } from "@octanejs/testing-library";
+import { afterEach, vi } from "vitest";
+
+class TestResizeObserver implements ResizeObserver {
+ readonly observed = new Set();
+
+ constructor(private readonly callback: ResizeObserverCallback) {}
+
+ observe(target: Element) {
+ this.observed.add(target);
+ this.callback([{ target, contentRect: target.getBoundingClientRect() } as ResizeObserverEntry], this);
+ }
+
+ unobserve(target: Element) {
+ this.observed.delete(target);
+ }
+
+ disconnect() {
+ this.observed.clear();
+ }
+}
+
+globalThis.ResizeObserver = TestResizeObserver;
+
+// Reason: jsdom does not perform layout; non-zero geometry lets width/height
+// observer hooks execute the same rendering and cleanup paths used in browsers.
+HTMLElement.prototype.getBoundingClientRect = vi.fn(() => ({
+ bottom: 24,
+ height: 24,
+ left: 0,
+ right: 640,
+ toJSON: () => ({}),
+ top: 0,
+ width: 640,
+ x: 0,
+ y: 0,
+})) as unknown as typeof HTMLElement.prototype.getBoundingClientRect;
+
+// Reason: jsdom has no canvas implementation, while the production component
+// measures line-number text through a 2D canvas context.
+HTMLCanvasElement.prototype.getContext = vi.fn(() => ({
+ font: "",
+ measureText: (text: string) => ({ width: text.length * 8 }),
+})) as unknown as typeof HTMLCanvasElement.prototype.getContext;
+
+afterEach(() => {
+ cleanup();
+ document.body.innerHTML = "";
+});
diff --git a/packages/octane/tests/ssr/diff-view.test.ts b/packages/octane/tests/ssr/diff-view.test.ts
new file mode 100644
index 0000000..0820d54
--- /dev/null
+++ b/packages/octane/tests/ssr/diff-view.test.ts
@@ -0,0 +1,26 @@
+import { renderToStaticMarkup, renderToString } from "octane/server";
+import { describe, expect, it } from "vitest";
+
+import { DiffModeEnum, DiffView } from "../../src";
+import { representativeDiff } from "../fixtures";
+
+describe("@git-diff-view/octane SSR", () => {
+ it("renders a deterministic server shell without a browser runtime", () => {
+ const props = {
+ data: representativeDiff,
+ diffViewFontSize: 12,
+ diffViewHighlight: false,
+ diffViewMode: DiffModeEnum.Unified,
+ diffViewTheme: "light" as const,
+ diffViewWrap: true,
+ };
+ const first = renderToString(DiffView, props);
+ const second = renderToStaticMarkup(DiffView, props);
+
+ expect(first.html).toContain('data-component="git-diff-view"');
+ expect(first.html).toContain('data-theme="light"');
+ expect(first.html).toContain("unified-diff-view");
+ expect(second.html).toContain("unified-diff-view");
+ expect(first.html).not.toContain("reactroot");
+ });
+});
diff --git a/packages/octane/tests/types/public-api.tsrx b/packages/octane/tests/types/public-api.tsrx
new file mode 100644
index 0000000..ea90a74
--- /dev/null
+++ b/packages/octane/tests/types/public-api.tsrx
@@ -0,0 +1,30 @@
+import { useRef } from "octane";
+
+import {
+ type DiffFile,
+ DiffModeEnum,
+ DiffView,
+ DiffViewWithMultiSelect,
+ type DiffViewWithMultiSelectRef,
+} from "../../src/index";
+import { representativeDiff } from "../fixtures";
+
+export function PublicApiFixture() {
+ const diffRef = useRef<{ getDiffFileInstance: () => DiffFile | null } | null>(null);
+ const multiSelectRef = useRef(null);
+
+ return (
+ <>
+
+
+ >
+ );
+}
diff --git a/packages/octane/tsconfig.json b/packages/octane/tsconfig.json
new file mode 100644
index 0000000..e2af6b3
--- /dev/null
+++ b/packages/octane/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "tsrx": {
+ "compiler": "octane/compiler"
+ },
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "jsx": "react-jsx",
+ "jsxImportSource": "octane",
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
+ "strict": true,
+ "noEmit": true,
+ "skipLibCheck": true,
+ "types": ["node", "vite/client", "vitest/globals"]
+ },
+ "include": ["src/**/*.ts", "src/**/*.tsrx", "src/**/*.d.ts", "tests/**/*.ts", "tests/**/*.tsrx"],
+ "exclude": ["dist", "node_modules", "src/components/v2"]
+}
diff --git a/packages/octane/vite.config.ts b/packages/octane/vite.config.ts
new file mode 100644
index 0000000..a04e7a0
--- /dev/null
+++ b/packages/octane/vite.config.ts
@@ -0,0 +1,56 @@
+import { resolve } from "node:path";
+import { octane } from "octane/compiler/vite";
+import { defineConfig } from "vite";
+
+import pkg from "./package.json" with { type: "json" };
+
+const external = [
+ "@git-diff-view/core",
+ "@types/hast",
+ "fast-diff",
+ "highlight.js",
+ "lowlight",
+ "reactivity-store/octane",
+];
+
+export default defineConfig(({ mode }) => {
+ const server = mode === "npm-server";
+
+ return {
+ plugins: [octane({ ssr: server })],
+ resolve: {
+ alias: [
+ {
+ find: /^@git-diff-view\/utils$/,
+ replacement: resolve(import.meta.dirname, "../utils/src/index.ts"),
+ },
+ ...(server ? [{ find: /^octane$/, replacement: "octane/server" }] : []),
+ ],
+ extensions: [".tsrx", ".ts", ".mjs", ".js", ".json"],
+ },
+ build: {
+ target: "esnext",
+ emptyOutDir: true,
+ outDir: server ? "dist/server" : "dist/client",
+ copyPublicDir: false,
+ sourcemap: true,
+ minify: false,
+ lib: {
+ entry: resolve(import.meta.dirname, "src/index.ts"),
+ name: "GitDiffViewOctane",
+ fileName: () => "index.js",
+ formats: ["es"],
+ },
+ rollupOptions: {
+ external: [...external, server ? "octane/server" : "octane"],
+ output: {
+ banner: "// octane-no-slot: compiler-assigned hook slots are already present.",
+ },
+ },
+ },
+ define: {
+ __DEV__: "false",
+ __VERSION__: JSON.stringify(pkg.version),
+ },
+ };
+});
diff --git a/packages/octane/vitest.config.ts b/packages/octane/vitest.config.ts
new file mode 100644
index 0000000..07f1a12
--- /dev/null
+++ b/packages/octane/vitest.config.ts
@@ -0,0 +1,35 @@
+import { resolve } from "node:path";
+import { octane } from "octane/compiler/vite";
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ plugins: [octane()],
+ resolve: {
+ alias: [
+ {
+ find: /^@git-diff-view\/core$/,
+ replacement: resolve(import.meta.dirname, "../core/src/index.ts"),
+ },
+ {
+ find: /^@git-diff-view\/lowlight$/,
+ replacement: resolve(import.meta.dirname, "../lowlight/src/index.ts"),
+ },
+ {
+ find: /^@git-diff-view\/utils$/,
+ replacement: resolve(import.meta.dirname, "../utils/src/index.ts"),
+ },
+ ],
+ extensions: [".tsrx", ".ts", ".mjs", ".js", ".json"],
+ },
+ define: {
+ __DEV__: "false",
+ __VERSION__: JSON.stringify("test"),
+ __LOWLIGHT_VERSION__: JSON.stringify("test"),
+ },
+ test: {
+ environment: "jsdom",
+ include: ["tests/client/**/*.test.ts"],
+ setupFiles: ["./tests/setup.ts"],
+ restoreMocks: true,
+ },
+});
diff --git a/packages/octane/vitest.ssr.config.ts b/packages/octane/vitest.ssr.config.ts
new file mode 100644
index 0000000..2cdd81b
--- /dev/null
+++ b/packages/octane/vitest.ssr.config.ts
@@ -0,0 +1,38 @@
+import { resolve } from "node:path";
+import { octane } from "octane/compiler/vite";
+import { defineConfig } from "vitest/config";
+
+export default defineConfig({
+ plugins: [octane({ ssr: true })],
+ resolve: {
+ alias: [
+ {
+ find: /^octane$/,
+ replacement: resolve(import.meta.dirname, "node_modules/octane/dist/server/index.js"),
+ },
+ {
+ find: /^@git-diff-view\/core$/,
+ replacement: resolve(import.meta.dirname, "../core/src/index.ts"),
+ },
+ {
+ find: /^@git-diff-view\/lowlight$/,
+ replacement: resolve(import.meta.dirname, "../lowlight/src/index.ts"),
+ },
+ {
+ find: /^@git-diff-view\/utils$/,
+ replacement: resolve(import.meta.dirname, "../utils/src/index.ts"),
+ },
+ ],
+ extensions: [".tsrx", ".ts", ".mjs", ".js", ".json"],
+ },
+ define: {
+ __DEV__: "false",
+ __VERSION__: JSON.stringify("test"),
+ __LOWLIGHT_VERSION__: JSON.stringify("test"),
+ },
+ test: {
+ environment: "node",
+ include: ["tests/ssr/**/*.test.ts"],
+ restoreMocks: true,
+ },
+});
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 6f411bd..35de5db 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -95,6 +95,9 @@ importers:
'@git-diff-view/lynx':
specifier: workspace:*
version: link:packages/lynx
+ '@git-diff-view/octane':
+ specifier: workspace:*
+ version: link:packages/octane
'@git-diff-view/react':
specifier: workspace:*
version: link:packages/react
@@ -392,6 +395,64 @@ importers:
specifier: '3'
version: 3.4.19(yaml@2.8.1)
+ packages/octane:
+ dependencies:
+ '@git-diff-view/core':
+ specifier: ^0.1.7
+ version: link:../core
+ '@types/hast':
+ specifier: ^3.0.0
+ version: 3.0.4
+ fast-diff:
+ specifier: ^1.3.0
+ version: 1.3.0
+ highlight.js:
+ specifier: ^11.11.0
+ version: 11.11.1
+ lowlight:
+ specifier: ^3.3.0
+ version: 3.3.0
+ reactivity-store:
+ specifier: ^0.4.0
+ version: 0.4.0(react@19.2.0)
+ devDependencies:
+ '@octanejs/testing-library':
+ specifier: ^0.1.18
+ version: 0.1.33(octane@0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)))
+ '@tsrx/typescript-plugin':
+ specifier: ^0.3.118
+ version: 0.3.120(octane@0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)))(typescript@5.9.3)
+ autoprefixer:
+ specifier: ^10.4.27
+ version: 10.5.4(postcss@8.5.25)
+ jsdom:
+ specifier: ^24.1.3
+ version: 24.1.3
+ octane:
+ specifier: ^0.1.36
+ version: 0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1))
+ postcss:
+ specifier: ^8.5.8
+ version: 8.5.25
+ rollup:
+ specifier: ^4.50.0
+ version: 4.60.2
+ rollup-plugin-dts:
+ specifier: ^6.2.3
+ version: 6.5.1(rollup@4.60.2)(typescript@5.9.3)
+ tailwindcss:
+ specifier: ^3.4.19
+ version: 3.4.19(yaml@2.8.1)
+ typescript:
+ specifier: ^5.9.3
+ version: 5.9.3
+ vite:
+ specifier: ^8.0.16
+ version: 8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)
+ vitest:
+ specifier: ^3.2.4
+ version: 3.2.7(@types/node@22.19.17)(jiti@1.21.7)(jsdom@24.1.3)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)
+
packages/react:
dependencies:
'@git-diff-view/core':
@@ -482,13 +543,13 @@ importers:
version: 3.4.18(yaml@2.8.1)
vite:
specifier: ^5.4.20
- version: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
+ version: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
vite-plugin-dts:
specifier: ^4.5.4
- version: 4.5.4(@types/node@22.19.17)(rollup@4.60.2)(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
+ version: 4.5.4(@types/node@22.19.17)(rollup@4.60.2)(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
vite-plugin-solid:
specifier: ^2.11.0
- version: 2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
+ version: 2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
packages/svelte:
dependencies:
@@ -516,16 +577,16 @@ importers:
version: 9.37.0
'@sveltejs/adapter-auto':
specifier: ^6.0.0
- version: 6.1.1(@sveltejs/kit@2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))
+ version: 6.1.1(@sveltejs/kit@2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))
'@sveltejs/kit':
specifier: ^2.16.0
- version: 2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ version: 2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
'@sveltejs/package':
specifier: ^2.0.0
version: 2.5.4(svelte@5.39.12)(typescript@5.9.3)
'@sveltejs/vite-plugin-svelte':
specifier: ^5.0.0
- version: 5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ version: 5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
autoprefixer:
specifier: ^10.4.21
version: 10.4.21(postcss@8.5.6)
@@ -567,10 +628,10 @@ importers:
version: 8.46.1(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3)
vite:
specifier: ^6.2.6
- version: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
+ version: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
vite-plugin-devtools-json:
specifier: ^1.0.0
- version: 1.0.0(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ version: 1.0.0(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
packages/utils:
devDependencies:
@@ -598,10 +659,10 @@ importers:
devDependencies:
'@vitejs/plugin-vue':
specifier: ^6.0.1
- version: 6.0.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
+ version: 6.0.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
'@vitejs/plugin-vue-jsx':
specifier: ^5.1.1
- version: 5.1.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
+ version: 5.1.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
autoprefixer:
specifier: ^10.4.21
version: 10.4.21(postcss@8.5.6)
@@ -613,10 +674,10 @@ importers:
version: 3.4.18(yaml@2.8.1)
vite:
specifier: ^5.4.20
- version: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
+ version: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
vite-plugin-dts:
specifier: ^4.5.4
- version: 4.5.4(@types/node@22.19.17)(rollup@4.60.2)(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
+ version: 4.5.4(@types/node@22.19.17)(rollup@4.60.2)(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
vue:
specifier: ^3.5.22
version: 3.5.22(typescript@5.9.3)
@@ -634,11 +695,11 @@ importers:
version: link:../../packages/lynx
'@lynx-js/react':
specifier: ^0.123.0
- version: 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2)
+ version: 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18)
devDependencies:
'@lynx-js/react-rsbuild-plugin':
specifier: '*'
- version: 0.18.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))(tslib@2.8.1)
+ version: 0.18.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))(tslib@2.8.1)
'@lynx-js/rspeedy':
specifier: '*'
version: 0.16.2(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)(@rspack/core@2.1.7(@swc/helpers@0.5.23))(typescript@5.9.3)(webpack@5.109.2(@swc/core@1.15.30(@swc/helpers@0.5.23))(postcss@8.5.25))
@@ -803,7 +864,7 @@ importers:
version: 0.3.30(@my-react/react@0.3.30(react@19.2.0))
'@my-react/react-vite':
specifier: ^0.0.36
- version: 0.0.36(@my-react/react-refresh@0.3.30(@my-react/react@0.3.30(react@19.2.0)))(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
+ version: 0.0.36(@my-react/react-refresh@0.3.30(@my-react/react@0.3.30(react@19.2.0)))(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
'@types/react':
specifier: 'catalog:'
version: 19.2.2
@@ -812,7 +873,7 @@ importers:
version: 19.2.2(@types/react@19.2.2)
'@vitejs/plugin-react':
specifier: 'catalog:'
- version: 5.2.0(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
+ version: 5.2.0(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
'@xterm/addon-fit':
specifier: 0.11.0
version: 0.11.0
@@ -833,10 +894,10 @@ importers:
version: 3.4.19(yaml@2.8.1)
vite:
specifier: ^5.4.20
- version: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ version: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
vite-tsconfig-paths:
specifier: ^5.1.4
- version: 5.1.4(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
+ version: 5.1.4(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
ui/solid-example:
dependencies:
@@ -855,10 +916,10 @@ importers:
version: 3.4.19(yaml@2.8.1)
vite:
specifier: ^5.4.20
- version: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ version: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
vite-plugin-solid:
specifier: ^2.11.9
- version: 2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
+ version: 2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
ui/vue-example:
dependencies:
@@ -871,7 +932,7 @@ importers:
devDependencies:
'@vitejs/plugin-vue':
specifier: 'catalog:'
- version: 6.0.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
+ version: 6.0.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
autoprefixer:
specifier: 'catalog:'
version: 10.5.4(postcss@8.5.25)
@@ -883,7 +944,7 @@ importers:
version: 3.4.19(yaml@2.8.1)
vite:
specifier: ^5.4.20
- version: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ version: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
vue-tsc:
specifier: ^3.1.1
version: 3.1.1(typescript@5.9.3)
@@ -914,13 +975,13 @@ importers:
version: 22.19.17
'@vitejs/plugin-vue':
specifier: 'catalog:'
- version: 6.0.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
+ version: 6.0.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))
cross-env:
specifier: 'catalog:'
version: 10.1.0
vite:
specifier: ^5.4.20
- version: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ version: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
vue-tsc:
specifier: ^3.1.1
version: 3.1.1(typescript@5.9.3)
@@ -935,6 +996,9 @@ packages:
resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==}
engines: {node: '>=10'}
+ '@asamuzakjp/css-color@3.2.0':
+ resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==}
+
'@babel/code-frame@7.26.2':
resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==}
engines: {node: '>=6.9.0'}
@@ -947,6 +1011,10 @@ packages:
resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
engines: {node: '>=6.9.0'}
+ '@babel/code-frame@8.0.0':
+ resolution: {integrity: sha512-dYYg153EyN2Ekbqw2zAsbd6/JR+9N2SEoC7YV2GyyqMM7x9bLDTjBD6XBhSMLH0wtIVyJj03jWNriQhaN+eoCw==}
+ engines: {node: ^22.18.0 || >=24.11.0}
+
'@babel/compat-data@7.28.4':
resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==}
engines: {node: '>=6.9.0'}
@@ -1051,6 +1119,10 @@ packages:
resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
engines: {node: '>=6.9.0'}
+ '@babel/helper-validator-identifier@8.0.4':
+ resolution: {integrity: sha512-4wFaiLd0bVo4cIoTXI3zKI038NIWE/cr3jvBjejOVYVxV/m8Ltav1USiGzG1fmS5J2RhgEOgXNNK46cRPnRsrg==}
+ engines: {node: ^22.18.0 || >=24.11.0}
+
'@babel/helper-validator-option@7.27.1':
resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
engines: {node: '>=6.9.0'}
@@ -1183,6 +1255,17 @@ packages:
resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==}
engines: {node: '>=12'}
+ '@csstools/color-helpers@5.1.0':
+ resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==}
+ engines: {node: '>=18'}
+
+ '@csstools/css-calc@2.1.4':
+ resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
'@csstools/css-calc@3.2.0':
resolution: {integrity: sha512-bR9e6o2BDB12jzN/gIbjHa5wLJ4UjD1CB9pM7ehlc0ddk6EBz+yYS1EV2MF55/HUxrHcB/hehAyt5vhsA3hx7w==}
engines: {node: '>=20.19.0'}
@@ -1190,6 +1273,19 @@ packages:
'@csstools/css-parser-algorithms': ^4.0.0
'@csstools/css-tokenizer': ^4.0.0
+ '@csstools/css-color-parser@3.1.0':
+ resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-parser-algorithms': ^3.0.5
+ '@csstools/css-tokenizer': ^3.0.4
+
+ '@csstools/css-parser-algorithms@3.0.5':
+ resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ '@csstools/css-tokenizer': ^3.0.4
+
'@csstools/css-parser-algorithms@4.0.0':
resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==}
engines: {node: '>=20.19.0'}
@@ -1204,6 +1300,10 @@ packages:
css-tree:
optional: true
+ '@csstools/css-tokenizer@3.0.4':
+ resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==}
+ engines: {node: '>=18'}
+
'@csstools/css-tokenizer@4.0.0':
resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==}
engines: {node: '>=20.19.0'}
@@ -2168,6 +2268,10 @@ packages:
cpu: [x64]
os: [win32]
+ '@noble/hashes@2.3.0':
+ resolution: {integrity: sha512-oN+QwyX7VSHotibwubG3kpzbwKrfnyR6OOO+3Nk/53ADL7FmgHHz4TgrbaYKvvOw09u6QTx0oiH1cNCIOuN0CQ==}
+ engines: {node: '>= 20.19.0'}
+
'@nodelib/fs.scandir@2.1.5':
resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
engines: {node: '>= 8'}
@@ -2184,9 +2288,18 @@ packages:
resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==}
engines: {node: '>=12.4.0'}
+ '@octanejs/testing-library@0.1.33':
+ resolution: {integrity: sha512-AxiZIkZt7/wRUHo3q2U+Yb+aAUiGhVkajJyH90MaHf8zPpmYXYwHiDcg7qGDg8zOWi82QBpfTgnk1Oq3R4oBcg==}
+ engines: {node: '>=22.22.2'}
+ peerDependencies:
+ octane: 0.1.36
+
'@open-draft/deferred-promise@2.2.0':
resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==}
+ '@oxc-project/types@0.144.0':
+ resolution: {integrity: sha512-nuhZIOLuI6TFQ32I/WnUx+SCPY7SdSKwgnFHydAuoS1+Z4BRcaP+RRJmGzl9lw+0OFF7UmaESf7KQRXaNLHypg==}
+
'@pinojs/redact@0.4.0':
resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==}
@@ -2215,6 +2328,90 @@ packages:
peerDependencies:
react: '>=16.8'
+ '@rolldown/binding-android-arm64@1.2.4':
+ resolution: {integrity: sha512-jHC2cnyKz5xU2fhECtFl8OZ83cYNt13GZQD+0uMJ/X3o+ijmd56okHhTUwxVSHPx1IRVIJEZ1/1pPzeLCU6XKA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@rolldown/binding-darwin-arm64@1.2.4':
+ resolution: {integrity: sha512-Dc5mPD8F5F/FS8i01syd7FTF6yB2fVthH/TRkjwJkzUK6EpoxHtqvZQP5Zwq80/5z19TWYHIg1KOHboCgVx/aQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@rolldown/binding-darwin-x64@1.2.4':
+ resolution: {integrity: sha512-fpDm4oBo6SqLvWUYCmFhdde3U9KH2fRNNMeAnAPAIwxRL345xutL0EtEUcuoxsoazdJGv/MuDBQHlCDrtbvqOg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@rolldown/binding-freebsd-x64@1.2.4':
+ resolution: {integrity: sha512-rSJoreDE/HoIzoaib6MTp5jQtCTdMHKIvItAKT/ImS6Y6Ww76oUaeMyp4Vc/fAgd/ehji068IxetHXAnqUwN9A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.2.4':
+ resolution: {integrity: sha512-/jm8OGHgn7oGaJu3i/qZI9spUGcJ+y/lk43ttQ/iO1tOd9NissG6o97bighBCiL+BKRngmcDuR6ikfwYdJmVuQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-gnu@1.2.4':
+ resolution: {integrity: sha512-tIP06BeD9EqvECBrPZ+sqdPlYrT+aYaAiu1wYziVx5elRK/ftm33JxVDy2bXGbr6J0CrtirCkR87/X5a2euEng==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-arm64-musl@1.2.4':
+ resolution: {integrity: sha512-Ql1Q0EQqVThvn9VAVlwNzsUvbSFtCMGjLpRRi4pk5i7NZZ4n5ISiLMjHYtus4VQ2PvkSw24zyaCVsiS+sXPj1w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+
+ '@rolldown/binding-linux-ppc64-gnu@1.2.4':
+ resolution: {integrity: sha512-GjbjXD4XXfN19D0LZNbmiCBUoDiRACsYHr0yaIbbn8aFsXjHZifcYqu/W5Er5X2X990WjHXFrxarn5chzItorQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+
+ '@rolldown/binding-linux-s390x-gnu@1.2.4':
+ resolution: {integrity: sha512-p5WR0NOwaRmJ/B1b6IjEFLLivwEsf3PrdBIhRbhTCQisbo2SvHHpG4ELB/+FgQNnB88LTOF86upmJmbvZdQ2lw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-gnu@1.2.4':
+ resolution: {integrity: sha512-4/GyVjmhR+Tc6HLJvwc1sOhPqAZtySiSMesOZyX6JQ5XBxoTDEMKQzvo07NIK6nTon/SivlZqvhzvuVBNQhObQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-linux-x64-musl@1.2.4':
+ resolution: {integrity: sha512-l9eeLsCNvPpmSXUej0etw/J1eqV0Jj1D5G/xG6YTijmE6dkv6E2QezgWbTfQk63v952DPqrjOCoiqxq7Bw0YUQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+
+ '@rolldown/binding-openharmony-arm64@1.2.4':
+ resolution: {integrity: sha512-e0F355MSTMm3+UOqtV3L24gFUp2N5m1f8L/7d56deik6va+AXdrt9F8LbzGpeWGWRbZEDq4m8NVnJDeBtf9DZg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@rolldown/binding-win32-arm64-msvc@1.2.4':
+ resolution: {integrity: sha512-AWLi0uBRYh6QlE7OKhiz+phZC0qwtij2QZmhmOdsLdFn64m7oMpooE9ICE3lhm9xMb4SpDo2WbHcxX1iFLFtqw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@rolldown/binding-win32-x64-msvc@1.2.4':
+ resolution: {integrity: sha512-UwSDJOg3dqCAejWdxclJjCsh3Qq4vLYMDxmyHqo1btz3stK2VqgwNd3mm5tuIwzSlGIQ/1H9Hr+Zn09mrezNqQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
'@rolldown/pluginutils@1.0.0-beta.29':
resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==}
@@ -2227,6 +2424,9 @@ packages:
'@rolldown/pluginutils@1.0.0-rc.6':
resolution: {integrity: sha512-Y0+JT8Mi1mmW08K6HieG315XNRu4L0rkfCpA364HtytjgiqYnMYRdFPcxRl+BQQqNXzecL2S9nii+RUpO93XIA==}
+ '@rolldown/pluginutils@1.0.1':
+ resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==}
+
'@rollup/plugin-alias@5.1.1':
resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==}
engines: {node: '>=14.0.0'}
@@ -2798,6 +2998,11 @@ packages:
'@stitches/core@1.2.8':
resolution: {integrity: sha512-Gfkvwk9o9kE9r9XNBmJRfV8zONvXThnm1tcuojL04Uy5uRyqg93DC83lDebl0rocZCfKSjUv+fWYtMQmEDJldg==}
+ '@sveltejs/acorn-typescript@1.0.13':
+ resolution: {integrity: sha512-wgKggnhZVL9Bfx1OaKKTrYY9BFRk6C8UAkQNUcIv1+llzYrIqy+RZm5HPKzn0NpEBvTVhTqB4kQyllZywsRBRQ==}
+ peerDependencies:
+ acorn: ^8.9.0
+
'@sveltejs/acorn-typescript@1.0.6':
resolution: {integrity: sha512-4awhxtMh4cx9blePWl10HRHj8Iivtqj+2QdDCSMDzxG+XKa9+VCNupQuCuvzEhYPzZSrX+0gC+0lHA/0fFKKQQ==}
peerDependencies:
@@ -2944,6 +3149,10 @@ packages:
'@tabler/icons@3.35.0':
resolution: {integrity: sha512-yYXe+gJ56xlZFiXwV9zVoe3FWCGuZ/D7/G4ZIlDtGxSx5CGQK110wrnT29gUj52kEZoxqF7oURTk97GQxELOFQ==}
+ '@testing-library/dom@10.4.1':
+ resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==}
+ engines: {node: '>=18'}
+
'@trysound/sax@0.2.0':
resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
engines: {node: '>=10.13.0'}
@@ -2960,6 +3169,34 @@ packages:
'@tsconfig/node16@1.0.4':
resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==}
+ '@tsrx/core@0.1.58':
+ resolution: {integrity: sha512-2dq/PYJZ5XDZ8nshfC4QHO/UACEivKegPQ4kmyse6sgxmE7Udsh56zX4v2KlNd2DjWaR34SELS3JnVr0XQzX8A==}
+
+ '@tsrx/typescript-plugin@0.3.120':
+ resolution: {integrity: sha512-sQJ+vHyteSX4EBrMzu/GrVX1ADKuTlTNOBo096aSYQDUDKQSqVtCAiIwVXdPXNk7YUtrsDLnPUoWv/ruW9Wz7w==}
+ hasBin: true
+ peerDependencies:
+ '@tsrx/preact': 0.1.58
+ '@tsrx/react': 0.2.58
+ '@tsrx/ripple': 0.1.59
+ '@tsrx/solid': 0.1.58
+ '@tsrx/vue': 0.1.58
+ octane: '*'
+ typescript: ^5.9.3
+ peerDependenciesMeta:
+ '@tsrx/preact':
+ optional: true
+ '@tsrx/react':
+ optional: true
+ '@tsrx/ripple':
+ optional: true
+ '@tsrx/solid':
+ optional: true
+ '@tsrx/vue':
+ optional: true
+ octane:
+ optional: true
+
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
@@ -2969,6 +3206,9 @@ packages:
'@types/argparse@1.0.38':
resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==}
+ '@types/aria-query@5.0.4':
+ resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==}
+
'@types/babel__core@7.20.5':
resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==}
@@ -2984,6 +3224,9 @@ packages:
'@types/body-parser@1.19.6':
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
+ '@types/chai@5.2.3':
+ resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==}
+
'@types/connect@3.4.38':
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
@@ -2993,9 +3236,15 @@ packages:
'@types/cors@2.8.19':
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
+ '@types/deep-eql@4.0.2':
+ resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
+
'@types/diff@6.0.0':
resolution: {integrity: sha512-dhVCYGv3ZSbzmQaBSagrv1WJ6rXCdkyTcDyoNu1MD8JohI7pR7k8wdZEm+mvdxRKXyHVwckFzWU1vJc+Z29MlA==}
+ '@types/estree-jsx@1.0.5':
+ resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==}
+
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
@@ -3058,6 +3307,9 @@ packages:
'@types/react@18.3.31':
resolution: {integrity: sha512-vfEqpXTvwT91yhmwdfouStN2hSKwTvyRs8qpLfADyrq/kxDw0hZM7Wk9Ug1FELj8hIby+S/+kQCSRFF32nv2Qw==}
+ '@types/react@19.2.18':
+ resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==}
+
'@types/react@19.2.2':
resolution: {integrity: sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==}
@@ -3331,15 +3583,53 @@ packages:
vite: ^5.0.0 || ^6.0.0 || ^7.0.0
vue: ^3.2.25
+ '@vitest/expect@3.2.7':
+ resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==}
+
+ '@vitest/mocker@3.2.7':
+ resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==}
+ peerDependencies:
+ msw: ^2.4.9
+ vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0
+ peerDependenciesMeta:
+ msw:
+ optional: true
+ vite:
+ optional: true
+
+ '@vitest/pretty-format@3.2.7':
+ resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==}
+
+ '@vitest/runner@3.2.7':
+ resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==}
+
+ '@vitest/snapshot@3.2.7':
+ resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==}
+
+ '@vitest/spy@3.2.7':
+ resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==}
+
+ '@vitest/utils@3.2.7':
+ resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==}
+
'@volar/language-core@2.4.23':
resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==}
+ '@volar/language-core@2.4.28':
+ resolution: {integrity: sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==}
+
'@volar/source-map@2.4.23':
resolution: {integrity: sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==}
+ '@volar/source-map@2.4.28':
+ resolution: {integrity: sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==}
+
'@volar/typescript@2.4.23':
resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==}
+ '@volar/typescript@2.4.28':
+ resolution: {integrity: sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==}
+
'@vue/babel-helper-vue-transform-on@1.5.0':
resolution: {integrity: sha512-0dAYkerNhhHutHZ34JtTl2czVQHUNWv6xEbkdF5W+Yrv5pCWsqjeORdOgbtW2I9gWlt+wBmVn+ttqN9ZxR5tzA==}
@@ -3499,6 +3789,10 @@ packages:
engines: {node: '>=0.4.0'}
hasBin: true
+ agent-base@7.1.4:
+ resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==}
+ engines: {node: '>= 14'}
+
ajv-draft-04@1.0.0:
resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==}
peerDependencies:
@@ -3569,6 +3863,10 @@ packages:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
engines: {node: '>=8'}
+ ansi-styles@5.2.0:
+ resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==}
+ engines: {node: '>=10'}
+
ansi-styles@6.2.3:
resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==}
engines: {node: '>=12'}
@@ -3592,6 +3890,9 @@ packages:
argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
+ aria-query@5.3.0:
+ resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==}
+
aria-query@5.3.2:
resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==}
engines: {node: '>= 0.4'}
@@ -3628,6 +3929,10 @@ packages:
resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==}
engines: {node: '>= 0.4'}
+ assertion-error@2.0.1:
+ resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==}
+ engines: {node: '>=12'}
+
ast-types-flow@0.0.8:
resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==}
@@ -3781,6 +4086,10 @@ packages:
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
engines: {node: '>= 0.8'}
+ cac@6.7.14:
+ resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
+ engines: {node: '>=8'}
+
cacheable@2.3.4:
resolution: {integrity: sha512-djgxybDbw9fL/ZWMI3+CE8ZilNxcwFkVtDc1gJ+IlOSSWkSMPQabhV/XCHTQ6pwwN6aivXPZ43omTooZiX06Ew==}
@@ -3819,6 +4128,10 @@ packages:
ccount@2.0.1:
resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==}
+ chai@5.3.3:
+ resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==}
+ engines: {node: '>=18'}
+
chalk@4.1.2:
resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
engines: {node: '>=10'}
@@ -3833,6 +4146,10 @@ packages:
character-entities-legacy@3.0.0:
resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==}
+ check-error@2.1.3:
+ resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==}
+ engines: {node: '>= 16'}
+
chokidar@3.6.0:
resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==}
engines: {node: '>= 8.10.0'}
@@ -4111,6 +4428,10 @@ packages:
resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+ cssstyle@4.6.0:
+ resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==}
+ engines: {node: '>=18'}
+
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@@ -4124,6 +4445,10 @@ packages:
damerau-levenshtein@1.0.8:
resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==}
+ data-urls@5.0.0:
+ resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==}
+ engines: {node: '>=18'}
+
data-view-buffer@1.0.2:
resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==}
engines: {node: '>= 0.4'}
@@ -4176,6 +4501,9 @@ packages:
supports-color:
optional: true
+ decimal.js@10.6.0:
+ resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==}
+
dedent-js@1.0.1:
resolution: {integrity: sha512-OUepMozQULMLUmhxS95Vudo0jb0UchLimi3+pQ2plj61Fcy8axbP9hbiD4Sz6DPqn6XG3kfmziVfQ1rSys5AJQ==}
@@ -4183,6 +4511,10 @@ packages:
resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==}
engines: {node: '>=6'}
+ deep-eql@5.0.2:
+ resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==}
+ engines: {node: '>=6'}
+
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
@@ -4224,6 +4556,9 @@ packages:
devalue@5.3.2:
resolution: {integrity: sha512-UDsjUbpQn9kvm68slnrs+mfxwFkIflOhkanmyabZ8zOYk8SMEIbJ3TK+88g70hSIeytu4y18f0z/hYHMTrXIWw==}
+ devalue@5.9.0:
+ resolution: {integrity: sha512-RWrqdArjvPbsATEhOPUo6Wndc/iWnkWKlhIrdlF3zMMYo/c3CVtoaVAyLtWxz5h8nSlkHzxnzV2uLydPXmtF+A==}
+
devlop@1.1.0:
resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==}
@@ -4245,6 +4580,9 @@ packages:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
+ dom-accessibility-api@0.5.16:
+ resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==}
+
dom-serializer@1.4.1:
resolution: {integrity: sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==}
@@ -4621,6 +4959,14 @@ packages:
esrap@2.1.0:
resolution: {integrity: sha512-yzmPNpl7TBbMRC5Lj2JlJZNPml0tzqoqP5B1JXycNUwtqma9AKCO0M2wHrdgsHcy1WRW7S9rJknAMtByg3usgA==}
+ esrap@2.3.3:
+ resolution: {integrity: sha512-OETBYYsX6L8btUkOyi8AcdtlfpsyNO9nCmP92U/Cxm07epHeLo5we1ck6z0HsbB/jxWlfmEBF9oobZKqSBWD4Q==}
+ peerDependencies:
+ '@typescript-eslint/types': ^8.2.0
+ peerDependenciesMeta:
+ '@typescript-eslint/types':
+ optional: true
+
esrecurse@4.3.0:
resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==}
engines: {node: '>=4.0'}
@@ -4663,6 +5009,10 @@ packages:
resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==}
engines: {node: '>=0.8.x'}
+ expect-type@1.4.0:
+ resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==}
+ engines: {node: '>=12.0.0'}
+
express@5.1.0:
resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==}
engines: {node: '>= 18'}
@@ -4971,6 +5321,10 @@ packages:
hookified@2.1.1:
resolution: {integrity: sha512-AHb76R16GB5EsPBE2J7Ko5kiEyXwviB9P5SMrAKcuAu4vJPZttViAbj9+tZeaQE5zjDme+1vcHP78Yj/WoAveA==}
+ html-encoding-sniffer@4.0.0:
+ resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==}
+ engines: {node: '>=18'}
+
html-entities@2.3.3:
resolution: {integrity: sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==}
@@ -4992,6 +5346,14 @@ packages:
resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==}
engines: {node: '>= 0.8'}
+ http-proxy-agent@7.0.2:
+ resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==}
+ engines: {node: '>= 14'}
+
+ https-proxy-agent@7.0.6:
+ resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==}
+ engines: {node: '>= 14'}
+
husky@9.1.7:
resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==}
engines: {node: '>=18'}
@@ -5192,6 +5554,9 @@ packages:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
+ is-potential-custom-element-name@1.0.1:
+ resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
+
is-promise@4.0.0:
resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==}
@@ -5281,13 +5646,28 @@ packages:
resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
engines: {node: '>=10'}
+ js-tokens@10.0.0:
+ resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+
js-tokens@4.0.0:
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+ js-tokens@9.0.1:
+ resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==}
+
js-yaml@4.1.0:
resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==}
hasBin: true
+ jsdom@24.1.3:
+ resolution: {integrity: sha512-MyL55p3Ut3cXbeBEG7Hcv0mVM8pp8PBNWxRqchZnSfAiES1v1mRnMeFfaHWIPULpwsYfvO+ZmMZz5tGCnjzDUQ==}
+ engines: {node: '>=18'}
+ peerDependencies:
+ canvas: ^2.11.2
+ peerDependenciesMeta:
+ canvas:
+ optional: true
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
@@ -5367,6 +5747,76 @@ packages:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
+ lightningcss-android-arm64@1.33.0:
+ resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [android]
+
+ lightningcss-darwin-arm64@1.33.0:
+ resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [darwin]
+
+ lightningcss-darwin-x64@1.33.0:
+ resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [darwin]
+
+ lightningcss-freebsd-x64@1.33.0:
+ resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [freebsd]
+
+ lightningcss-linux-arm-gnueabihf@1.33.0:
+ resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm]
+ os: [linux]
+
+ lightningcss-linux-arm64-gnu@1.33.0:
+ resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-arm64-musl@1.33.0:
+ resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [linux]
+
+ lightningcss-linux-x64-gnu@1.33.0:
+ resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-linux-x64-musl@1.33.0:
+ resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [linux]
+
+ lightningcss-win32-arm64-msvc@1.33.0:
+ resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [arm64]
+ os: [win32]
+
+ lightningcss-win32-x64-msvc@1.33.0:
+ resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==}
+ engines: {node: '>= 12.0.0'}
+ cpu: [x64]
+ os: [win32]
+
+ lightningcss@1.33.0:
+ resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==}
+ engines: {node: '>= 12.0.0'}
+
lilconfig@2.1.0:
resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
engines: {node: '>=10'}
@@ -5425,6 +5875,9 @@ packages:
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
hasBin: true
+ loupe@3.2.1:
+ resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==}
+
lowlight@3.3.0:
resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==}
@@ -5445,6 +5898,9 @@ packages:
magic-string@0.30.19:
resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==}
+ magic-string@0.30.21:
+ resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
+
make-error@1.3.6:
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
@@ -5715,6 +6171,9 @@ packages:
nth-check@2.1.1:
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
+ nwsapi@2.2.24:
+ resolution: {integrity: sha512-7YRhZ3jS45LwmSCT4b2sVFHt/WuovaktDU07QrtOBY2PXskss5a9jfmR9jptyumwXST+rFjrmppMY1KT/yn35A==}
+
object-assign@4.1.1:
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
engines: {node: '>=0.10.0'}
@@ -5754,6 +6213,21 @@ packages:
obliterator@2.0.5:
resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==}
+ octane@0.1.36:
+ resolution: {integrity: sha512-egscdNROPtLh0Kd4TijYXr3/rVdjyDVCr7r4/mArAAjAuvqhRVsYcLDGr88MT4JSvZwDtISsOALNZY2crLETjg==}
+ engines: {node: '>=22.22.2'}
+ peerDependencies:
+ react: ^19.0.0
+ react-dom: ^19.0.0
+ vite: ^8.0.16
+ peerDependenciesMeta:
+ react:
+ optional: true
+ react-dom:
+ optional: true
+ vite:
+ optional: true
+
on-exit-leak-free@2.1.2:
resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==}
engines: {node: '>=14.0.0'}
@@ -5862,6 +6336,10 @@ packages:
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
+ pathval@2.0.1:
+ resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==}
+ engines: {node: '>= 14.16'}
+
periscopic@3.1.0:
resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
@@ -5876,6 +6354,10 @@ packages:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
+ picomatch@4.0.5:
+ resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==}
+ engines: {node: '>=12'}
+
pify@2.3.0:
resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==}
engines: {node: '>=0.10.0'}
@@ -6509,6 +6991,10 @@ packages:
engines: {node: '>=14'}
hasBin: true
+ pretty-format@27.5.1:
+ resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==}
+ engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0}
+
pretty-hrtime@1.0.3:
resolution: {integrity: sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==}
engines: {node: '>= 0.8'}
@@ -6541,6 +7027,9 @@ packages:
resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==}
engines: {node: '>=10'}
+ psl@1.15.0:
+ resolution: {integrity: sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==}
+
publint@0.3.14:
resolution: {integrity: sha512-14/VNBvWsrBeqWNDw8c/DK5ERcZBUwL1rnkVx18cQnF3zadr3GfoYtvD8mxi1dhkWpaPHp8kfi92MDbjMeW3qw==}
engines: {node: '>=18'}
@@ -6568,6 +7057,9 @@ packages:
quansync@0.2.11:
resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==}
+ querystringify@2.2.0:
+ resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
+
queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
@@ -6708,6 +7200,9 @@ packages:
resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==}
engines: {node: '>=0.10.0'}
+ requires-port@1.0.0:
+ resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
+
resolve-from@4.0.0:
resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
engines: {node: '>=4'}
@@ -6736,6 +7231,22 @@ packages:
resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
+ rolldown@1.2.4:
+ resolution: {integrity: sha512-rSr7irW0K7QRWzjdJXqZowkcRdDtjRduh43rBltnVKd0VFq839l1lJoDvGJb6gl7+4rTTCrPWu+YfujUL8Ug7w==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+
+ rollup-plugin-dts@6.5.1:
+ resolution: {integrity: sha512-jODTXp3H7MK/Ur/ErtsrQ0G1GvaCmc3du+y5pNrdBMf6d7HlL2Nd/N6TkEr+f75CkUj01zEoEd7y2elH0eHi1Q==}
+ engines: {node: '>=20'}
+ peerDependencies:
+ '@typescript/typescript6': ^6
+ rollup: ^3 || ^4
+ typescript: ^4.5 || ^5 || ^6 || ^7
+ peerDependenciesMeta:
+ '@typescript/typescript6':
+ optional: true
+
rollup-plugin-postcss@4.0.2:
resolution: {integrity: sha512-05EaY6zvZdmvPUDi3uCcAQoESDcYnv8ogJJQRp6V5kZ6J6P7uAVJlrTZcaaA20wTH527YTnKfkAoPxWI/jPp4w==}
engines: {node: '>=10'}
@@ -6759,6 +7270,12 @@ packages:
resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==}
engines: {node: '>= 18'}
+ rrweb-cssom@0.7.1:
+ resolution: {integrity: sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg==}
+
+ rrweb-cssom@0.8.0:
+ resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==}
+
rsbuild-plugin-tailwindcss@0.2.4:
resolution: {integrity: sha512-coLf2Rn5QeXkCrW4zlyPej+ezQ1sNFwwagrlpITqo/Yz78bLeNWrMbA1WqHNLtr5IwM0lL/SEc4ZVglw9M13pw==}
peerDependencies:
@@ -6811,6 +7328,10 @@ packages:
resolution: {integrity: sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==}
engines: {node: '>=11.0.0'}
+ saxes@6.0.0:
+ resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==}
+ engines: {node: '>=v12.22.7'}
+
scheduler@0.26.0:
resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==}
@@ -6924,6 +7445,9 @@ packages:
resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==}
engines: {node: '>= 0.4'}
+ siginfo@2.0.0:
+ resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==}
+
signal-exit@3.0.7:
resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
@@ -7016,6 +7540,9 @@ packages:
resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==}
engines: {node: '>=10'}
+ stackback@0.0.2:
+ resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==}
+
static-browser-server@1.0.3:
resolution: {integrity: sha512-ZUyfgGDdFRbZGGJQ1YhiM930Yczz5VlbJObrQLlk24+qNHVQx4OlLcYswEUo3bIyNAbQUIUR9Yr5/Hqjzqb4zA==}
@@ -7027,6 +7554,9 @@ packages:
resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==}
engines: {node: '>= 0.8'}
+ std-env@3.10.0:
+ resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==}
+
stop-iteration-iterator@1.1.0:
resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==}
engines: {node: '>= 0.4'}
@@ -7107,6 +7637,9 @@ packages:
resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==}
engines: {node: '>=14.16'}
+ strip-literal@3.1.0:
+ resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==}
+
style-inject@0.3.0:
resolution: {integrity: sha512-IezA2qp+vcdlhJaVm5SOdPPTUu0FCEqfNSli2vRuSIBbu5Nq5UvygTk/VzeCqfLz2Atj3dVII5QBKGZRZ0edzw==}
@@ -7268,6 +7801,9 @@ packages:
engines: {node: '>=16'}
hasBin: true
+ symbol-tree@3.2.4:
+ resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
+
synckit@0.11.12:
resolution: {integrity: sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ==}
engines: {node: ^14.18.0 || >=16.0.0}
@@ -7314,14 +7850,36 @@ packages:
tiny-invariant@1.3.3:
resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==}
+ tinybench@2.9.0:
+ resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
+
+ tinyexec@0.3.2:
+ resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==}
+
tinyglobby@0.2.15:
resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==}
engines: {node: '>=12.0.0'}
+ tinyglobby@0.2.17:
+ resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==}
+ engines: {node: '>=12.0.0'}
+
+ tinypool@1.1.1:
+ resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==}
+ engines: {node: ^18.0.0 || >=20.0.0}
+
tinypool@2.1.0:
resolution: {integrity: sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==}
engines: {node: ^20.0.0 || >=22.0.0}
+ tinyrainbow@2.0.0:
+ resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==}
+ engines: {node: '>=14.0.0'}
+
+ tinyspy@4.0.4:
+ resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==}
+ engines: {node: '>=14.0.0'}
+
to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'}
@@ -7334,6 +7892,14 @@ packages:
resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==}
engines: {node: '>=6'}
+ tough-cookie@4.1.4:
+ resolution: {integrity: sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==}
+ engines: {node: '>=6'}
+
+ tr46@5.1.1:
+ resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==}
+ engines: {node: '>=18'}
+
trim-lines@3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
@@ -7474,6 +8040,10 @@ packages:
unist-util-visit@5.0.0:
resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==}
+ universalify@0.2.0:
+ resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
+ engines: {node: '>= 4.0.0'}
+
universalify@2.0.1:
resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==}
engines: {node: '>= 10.0.0'}
@@ -7500,6 +8070,9 @@ packages:
uri-js@4.4.1:
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
+ url-parse@1.5.10:
+ resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
+
use-callback-ref@1.3.3:
resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==}
engines: {node: '>=10'}
@@ -7575,6 +8148,11 @@ packages:
vfile@6.0.3:
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
+ vite-node@3.2.4:
+ resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+
vite-plugin-devtools-json@1.0.0:
resolution: {integrity: sha512-MobvwqX76Vqt/O4AbnNMNWoXWGrKUqZbphCUle/J2KXH82yKQiunOeKnz/nqEPosPsoWWPP9FtNuPBSYpiiwkw==}
peerDependencies:
@@ -7678,6 +8256,49 @@ packages:
yaml:
optional: true
+ vite@8.2.1:
+ resolution: {integrity: sha512-EU/eS7BH3XROHh2YnBefjM6DBKA6ZeMZEYQbj7NLWg5wHYlhB8B/Mayd5XsgWq+NFYccDOTemRpdETWR6Ka/lw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ hasBin: true
+ peerDependencies:
+ '@types/node': ^20.19.0 || >=22.12.0
+ '@vitejs/devtools': ^0.4.0
+ esbuild: ^0.27.0 || ^0.28.0
+ jiti: '>=1.21.0'
+ less: ^4.0.0
+ sass: ^1.70.0
+ sass-embedded: ^1.70.0
+ stylus: '>=0.54.8'
+ sugarss: ^5.0.0
+ terser: ^5.16.0
+ tsx: ^4.8.1
+ yaml: ^2.4.2
+ peerDependenciesMeta:
+ '@types/node':
+ optional: true
+ '@vitejs/devtools':
+ optional: true
+ esbuild:
+ optional: true
+ jiti:
+ optional: true
+ less:
+ optional: true
+ sass:
+ optional: true
+ sass-embedded:
+ optional: true
+ stylus:
+ optional: true
+ sugarss:
+ optional: true
+ terser:
+ optional: true
+ tsx:
+ optional: true
+ yaml:
+ optional: true
+
vitefu@1.1.1:
resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==}
peerDependencies:
@@ -7686,6 +8307,34 @@ packages:
vite:
optional: true
+ vitest@3.2.7:
+ resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==}
+ engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
+ hasBin: true
+ peerDependencies:
+ '@edge-runtime/vm': '*'
+ '@types/debug': ^4.1.12
+ '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0
+ '@vitest/browser': 3.2.7
+ '@vitest/ui': 3.2.7
+ happy-dom: '*'
+ jsdom: '*'
+ peerDependenciesMeta:
+ '@edge-runtime/vm':
+ optional: true
+ '@types/debug':
+ optional: true
+ '@types/node':
+ optional: true
+ '@vitest/browser':
+ optional: true
+ '@vitest/ui':
+ optional: true
+ happy-dom:
+ optional: true
+ jsdom:
+ optional: true
+
vscode-uri@3.1.0:
resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==}
@@ -7706,6 +8355,10 @@ packages:
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
+ w3c-xmlserializer@5.0.0:
+ resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==}
+ engines: {node: '>=18'}
+
wasm-feature-detect@1.8.0:
resolution: {integrity: sha512-zksaLKM2fVlnB5jQQDqKXXwYHLQUVH9es+5TOOHwGOVJOCeRBCiPjwSg+3tN2AdTCzjgli4jijCH290kXb/zWQ==}
@@ -7713,6 +8366,10 @@ packages:
resolution: {integrity: sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==}
engines: {node: '>=10.13.0'}
+ webidl-conversions@7.0.0:
+ resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
+ engines: {node: '>=12'}
+
webpack-sources@3.5.1:
resolution: {integrity: sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==}
engines: {node: '>=10.13.0'}
@@ -7727,6 +8384,19 @@ packages:
webpack-cli:
optional: true
+ whatwg-encoding@3.1.1:
+ resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==}
+ engines: {node: '>=18'}
+ deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation
+
+ whatwg-mimetype@4.0.0:
+ resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==}
+ engines: {node: '>=18'}
+
+ whatwg-url@14.2.0:
+ resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==}
+ engines: {node: '>=18'}
+
which-boxed-primitive@1.1.1:
resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==}
engines: {node: '>= 0.4'}
@@ -7752,6 +8422,11 @@ packages:
engines: {node: '>= 8'}
hasBin: true
+ why-is-node-running@2.3.0:
+ resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==}
+ engines: {node: '>=8'}
+ hasBin: true
+
widest-line@5.0.0:
resolution: {integrity: sha512-c9bZp7b5YtRj2wOe6dlj32MK+Bx/M/d+9VB2SHM1OtsUHR0aV0tdP6DWh/iMt0kWi1t5g1Iudu6hQRNd1A4PVA==}
engines: {node: '>=18'}
@@ -7803,6 +8478,13 @@ packages:
utf-8-validate:
optional: true
+ xml-name-validator@5.0.0:
+ resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==}
+ engines: {node: '>=18'}
+
+ xmlchars@2.2.0:
+ resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
+
y18n@5.0.8:
resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==}
engines: {node: '>=10'}
@@ -7865,6 +8547,14 @@ snapshots:
'@alloc/quick-lru@5.2.0': {}
+ '@asamuzakjp/css-color@3.2.0':
+ dependencies:
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+ lru-cache: 10.4.3
+
'@babel/code-frame@7.26.2':
dependencies:
'@babel/helper-validator-identifier': 7.28.5
@@ -7883,6 +8573,12 @@ snapshots:
js-tokens: 4.0.0
picocolors: 1.1.1
+ '@babel/code-frame@8.0.0':
+ dependencies:
+ '@babel/helper-validator-identifier': 8.0.4
+ js-tokens: 10.0.0
+ optional: true
+
'@babel/compat-data@7.28.4': {}
'@babel/compat-data@7.29.0': {}
@@ -8049,6 +8745,9 @@ snapshots:
'@babel/helper-validator-identifier@7.28.5': {}
+ '@babel/helper-validator-identifier@8.0.4':
+ optional: true
+
'@babel/helper-validator-option@7.27.1': {}
'@babel/helpers@7.28.4':
@@ -8104,7 +8803,7 @@ snapshots:
'@babel/template@7.27.2':
dependencies:
- '@babel/code-frame': 7.27.1
+ '@babel/code-frame': 7.29.0
'@babel/parser': 7.28.4
'@babel/types': 7.28.4
@@ -8116,7 +8815,7 @@ snapshots:
'@babel/traverse@7.28.4':
dependencies:
- '@babel/code-frame': 7.27.1
+ '@babel/code-frame': 7.29.0
'@babel/generator': 7.28.3
'@babel/helper-globals': 7.28.0
'@babel/parser': 7.28.4
@@ -8274,11 +8973,29 @@ snapshots:
dependencies:
'@jridgewell/trace-mapping': 0.3.9
+ '@csstools/color-helpers@5.1.0': {}
+
+ '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+
'@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
dependencies:
'@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0)
'@csstools/css-tokenizer': 4.0.0
+ '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/color-helpers': 5.1.0
+ '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4)
+ '@csstools/css-tokenizer': 3.0.4
+
+ '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)':
+ dependencies:
+ '@csstools/css-tokenizer': 3.0.4
+
'@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)':
dependencies:
'@csstools/css-tokenizer': 4.0.0
@@ -8287,6 +9004,8 @@ snapshots:
optionalDependencies:
css-tree: 3.2.1
+ '@csstools/css-tokenizer@3.0.4': {}
+
'@csstools/css-tokenizer@4.0.0': {}
'@csstools/media-query-list-parser@5.0.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)':
@@ -8870,35 +9589,35 @@ snapshots:
'@lynx-js/react-alias-rsbuild-plugin@0.18.2': {}
- '@lynx-js/react-refresh-webpack-plugin@0.4.1(@lynx-js/react-webpack-plugin@0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1)))':
+ '@lynx-js/react-refresh-webpack-plugin@0.4.1(@lynx-js/react-webpack-plugin@0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1)))':
dependencies:
- '@lynx-js/react-webpack-plugin': 0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1))
+ '@lynx-js/react-webpack-plugin': 0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1))
- '@lynx-js/react-rsbuild-plugin@0.18.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))(tslib@2.8.1)':
+ '@lynx-js/react-rsbuild-plugin@0.18.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))(tslib@2.8.1)':
dependencies:
'@lynx-js/css-extract-webpack-plugin': 0.10.0(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1))
'@lynx-js/react-alias-rsbuild-plugin': 0.18.2
- '@lynx-js/react-refresh-webpack-plugin': 0.4.1(@lynx-js/react-webpack-plugin@0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1)))
- '@lynx-js/react-webpack-plugin': 0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1))
+ '@lynx-js/react-refresh-webpack-plugin': 0.4.1(@lynx-js/react-webpack-plugin@0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1)))
+ '@lynx-js/react-webpack-plugin': 0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1))
'@lynx-js/runtime-wrapper-webpack-plugin': 0.2.3
'@lynx-js/template-webpack-plugin': 0.14.1(tslib@2.8.1)
- '@lynx-js/use-sync-external-store': 1.5.0(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))
+ '@lynx-js/use-sync-external-store': 1.5.0(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))
background-only: 0.0.1
tiny-invariant: 1.3.3
optionalDependencies:
- '@lynx-js/react': 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2)
+ '@lynx-js/react': 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18)
transitivePeerDependencies:
- '@lynx-js/lynx-core'
- tslib
- '@lynx-js/react-webpack-plugin@0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1))':
+ '@lynx-js/react-webpack-plugin@0.10.2(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))(@lynx-js/template-webpack-plugin@0.14.1(tslib@2.8.1))':
dependencies:
'@lynx-js/debug-metadata': 0.1.0
'@lynx-js/template-webpack-plugin': 0.14.1(tslib@2.8.1)
'@lynx-js/webpack-runtime-globals': 0.0.7
tiny-invariant: 1.3.3
optionalDependencies:
- '@lynx-js/react': 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2)
+ '@lynx-js/react': 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18)
'@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@18.3.31)':
dependencies:
@@ -8907,9 +9626,9 @@ snapshots:
optionalDependencies:
'@lynx-js/types': 4.1.0
- '@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2)':
+ '@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18)':
dependencies:
- '@types/react': 19.2.2
+ '@types/react': 19.2.18
preact: '@lynx-js/internal-preact@10.29.1-20260519060144-e6da44c'
optionalDependencies:
'@lynx-js/types': 4.1.0
@@ -8978,9 +9697,9 @@ snapshots:
dependencies:
csstype: 3.1.3
- '@lynx-js/use-sync-external-store@1.5.0(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2))':
+ '@lynx-js/use-sync-external-store@1.5.0(@lynx-js/react@0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18))':
dependencies:
- '@lynx-js/react': 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.2)
+ '@lynx-js/react': 0.123.2(@lynx-js/types@4.1.0)(@types/react@19.2.18)
'@lynx-js/web-core@0.23.1(@lynx-js/css-serializer@0.1.7)(tslib@2.8.1)':
dependencies:
@@ -9107,7 +9826,7 @@ snapshots:
'@xterm/addon-fit': 0.11.0
'@xterm/xterm': 6.0.0
- '@my-react/react-vite@0.0.36(@my-react/react-refresh@0.3.30(@my-react/react@0.3.30(react@19.2.0)))(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))':
+ '@my-react/react-vite@0.0.36(@my-react/react-refresh@0.3.30(@my-react/react@0.3.30(react@19.2.0)))(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
@@ -9119,7 +9838,7 @@ snapshots:
magic-string: 0.30.19
periscopic: 3.1.0
rsc-html-stream: 0.0.7
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
transitivePeerDependencies:
- supports-color
@@ -9180,6 +9899,8 @@ snapshots:
'@next/swc-win32-x64-msvc@16.2.4':
optional: true
+ '@noble/hashes@2.3.0': {}
+
'@nodelib/fs.scandir@2.1.5':
dependencies:
'@nodelib/fs.stat': 2.0.5
@@ -9194,8 +9915,15 @@ snapshots:
'@nolyfill/is-core-module@1.0.39': {}
+ '@octanejs/testing-library@0.1.33(octane@0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)))':
+ dependencies:
+ '@testing-library/dom': 10.4.1
+ octane: 0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1))
+
'@open-draft/deferred-promise@2.2.0': {}
+ '@oxc-project/types@0.144.0': {}
+
'@pinojs/redact@0.4.0': {}
'@pkgjs/parseargs@0.11.0':
@@ -9217,6 +9945,48 @@ snapshots:
dependencies:
react: 19.2.0
+ '@rolldown/binding-android-arm64@1.2.4':
+ optional: true
+
+ '@rolldown/binding-darwin-arm64@1.2.4':
+ optional: true
+
+ '@rolldown/binding-darwin-x64@1.2.4':
+ optional: true
+
+ '@rolldown/binding-freebsd-x64@1.2.4':
+ optional: true
+
+ '@rolldown/binding-linux-arm-gnueabihf@1.2.4':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-gnu@1.2.4':
+ optional: true
+
+ '@rolldown/binding-linux-arm64-musl@1.2.4':
+ optional: true
+
+ '@rolldown/binding-linux-ppc64-gnu@1.2.4':
+ optional: true
+
+ '@rolldown/binding-linux-s390x-gnu@1.2.4':
+ optional: true
+
+ '@rolldown/binding-linux-x64-gnu@1.2.4':
+ optional: true
+
+ '@rolldown/binding-linux-x64-musl@1.2.4':
+ optional: true
+
+ '@rolldown/binding-openharmony-arm64@1.2.4':
+ optional: true
+
+ '@rolldown/binding-win32-arm64-msvc@1.2.4':
+ optional: true
+
+ '@rolldown/binding-win32-x64-msvc@1.2.4':
+ optional: true
+
'@rolldown/pluginutils@1.0.0-beta.29': {}
'@rolldown/pluginutils@1.0.0-beta.43': {}
@@ -9225,6 +9995,8 @@ snapshots:
'@rolldown/pluginutils@1.0.0-rc.6': {}
+ '@rolldown/pluginutils@1.0.1': {}
+
'@rollup/plugin-alias@5.1.1(rollup@4.60.2)':
optionalDependencies:
rollup: 4.60.2
@@ -9439,7 +10211,7 @@ snapshots:
'@rsbuild/plugin-check-syntax@1.6.1(@rsbuild/core@2.1.7)':
dependencies:
- acorn: 8.15.0
+ acorn: 8.18.0
browserslist-to-es-version: 1.4.2
htmlparser2: 10.0.0
picocolors: 1.1.1
@@ -9549,8 +10321,8 @@ snapshots:
'@babel/code-frame': 7.26.2
'@rsdoctor/types': 1.6.1(@rspack/core@2.1.7(@swc/helpers@0.5.23))(webpack@5.109.2(@swc/core@1.15.30(@swc/helpers@0.5.23))(postcss@8.5.25))
'@types/estree': 1.0.5
- acorn: 8.15.0
- acorn-import-attributes: 1.9.5(acorn@8.15.0)
+ acorn: 8.18.0
+ acorn-import-attributes: 1.9.5(acorn@8.18.0)
acorn-walk: 8.3.5
deep-eql: 4.1.4
envinfo: 7.21.0
@@ -9763,19 +10535,23 @@ snapshots:
'@stitches/core@1.2.8': {}
+ '@sveltejs/acorn-typescript@1.0.13(acorn@8.18.0)':
+ dependencies:
+ acorn: 8.18.0
+
'@sveltejs/acorn-typescript@1.0.6(acorn@8.15.0)':
dependencies:
acorn: 8.15.0
- '@sveltejs/adapter-auto@6.1.1(@sveltejs/kit@2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))':
+ '@sveltejs/adapter-auto@6.1.1(@sveltejs/kit@2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))':
dependencies:
- '@sveltejs/kit': 2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ '@sveltejs/kit': 2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
- '@sveltejs/kit@2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))':
+ '@sveltejs/kit@2.46.5(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))':
dependencies:
'@standard-schema/spec': 1.0.0
'@sveltejs/acorn-typescript': 1.0.6(acorn@8.15.0)
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
'@types/cookie': 0.6.0
acorn: 8.15.0
cookie: 0.6.0
@@ -9788,7 +10564,7 @@ snapshots:
set-cookie-parser: 2.7.1
sirv: 3.0.2
svelte: 5.39.12
- vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
'@sveltejs/package@2.5.4(svelte@5.39.12)(typescript@5.9.3)':
dependencies:
@@ -9801,25 +10577,25 @@ snapshots:
transitivePeerDependencies:
- typescript
- '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))':
+ '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))':
dependencies:
- '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
debug: 4.4.3
svelte: 5.39.12
- vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
transitivePeerDependencies:
- supports-color
- '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))':
+ '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))':
dependencies:
- '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)))(svelte@5.39.12)(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
debug: 4.4.3
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.19
svelte: 5.39.12
- vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
- vitefu: 1.1.1(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
+ vitefu: 1.1.1(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1))
transitivePeerDependencies:
- supports-color
@@ -9899,6 +10675,17 @@ snapshots:
'@tabler/icons@3.35.0': {}
+ '@testing-library/dom@10.4.1':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/runtime': 7.28.4
+ '@types/aria-query': 5.0.4
+ aria-query: 5.3.0
+ dom-accessibility-api: 0.5.16
+ lz-string: 1.5.0
+ picocolors: 1.1.1
+ pretty-format: 27.5.1
+
'@trysound/sax@0.2.0': {}
'@tsconfig/node10@1.0.11': {}
@@ -9909,6 +10696,29 @@ snapshots:
'@tsconfig/node16@1.0.4': {}
+ '@tsrx/core@0.1.58(@typescript-eslint/types@8.59.0)':
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ '@noble/hashes': 2.3.0
+ '@sveltejs/acorn-typescript': 1.0.13(acorn@8.18.0)
+ '@types/estree': 1.0.8
+ '@types/estree-jsx': 1.0.5
+ acorn: 8.18.0
+ esrap: 2.3.3(@typescript-eslint/types@8.59.0)
+ is-reference: 3.0.3
+ magic-string: 0.30.19
+ zimmerframe: 1.1.4
+ transitivePeerDependencies:
+ - '@typescript-eslint/types'
+
+ '@tsrx/typescript-plugin@0.3.120(octane@0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)))(typescript@5.9.3)':
+ dependencies:
+ '@volar/language-core': 2.4.28
+ '@volar/typescript': 2.4.28
+ typescript: 5.9.3
+ optionalDependencies:
+ octane: 0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1))
+
'@tybys/wasm-util@0.10.1':
dependencies:
tslib: 2.8.1
@@ -9921,6 +10731,8 @@ snapshots:
'@types/argparse@1.0.38': {}
+ '@types/aria-query@5.0.4': {}
+
'@types/babel__core@7.20.5':
dependencies:
'@babel/parser': 7.29.2
@@ -9947,6 +10759,11 @@ snapshots:
'@types/connect': 3.4.38
'@types/node': 22.19.17
+ '@types/chai@5.2.3':
+ dependencies:
+ '@types/deep-eql': 4.0.2
+ assertion-error: 2.0.1
+
'@types/connect@3.4.38':
dependencies:
'@types/node': 22.19.17
@@ -9957,8 +10774,14 @@ snapshots:
dependencies:
'@types/node': 22.19.17
+ '@types/deep-eql@4.0.2': {}
+
'@types/diff@6.0.0': {}
+ '@types/estree-jsx@1.0.5':
+ dependencies:
+ '@types/estree': 1.0.8
+
'@types/estree@1.0.5': {}
'@types/estree@1.0.8': {}
@@ -10023,6 +10846,10 @@ snapshots:
'@types/prop-types': 15.7.15
csstype: 3.2.3
+ '@types/react@19.2.18':
+ dependencies:
+ csstype: 3.2.3
+
'@types/react@19.2.2':
dependencies:
csstype: 3.1.3
@@ -10310,7 +11137,7 @@ snapshots:
'@unrs/resolver-binding-win32-x64-msvc@1.11.1':
optional: true
- '@vitejs/plugin-react@5.2.0(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))':
+ '@vitejs/plugin-react@5.2.0(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))':
dependencies:
'@babel/core': 7.29.0
'@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.29.0)
@@ -10318,46 +11145,100 @@ snapshots:
'@rolldown/pluginutils': 1.0.0-rc.3
'@types/babel__core': 7.20.5
react-refresh: 0.18.0
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
transitivePeerDependencies:
- supports-color
- '@vitejs/plugin-vue-jsx@5.1.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))':
+ '@vitejs/plugin-vue-jsx@5.1.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))':
dependencies:
'@babel/core': 7.28.4
'@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.4)
'@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.4)
'@rolldown/pluginutils': 1.0.0-beta.43
'@vue/babel-plugin-jsx': 1.5.0(@babel/core@7.28.4)
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
vue: 3.5.22(typescript@5.9.3)
transitivePeerDependencies:
- supports-color
- '@vitejs/plugin-vue@6.0.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))':
+ '@vitejs/plugin-vue@6.0.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.29
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
vue: 3.5.22(typescript@5.9.3)
- '@vitejs/plugin-vue@6.0.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))':
+ '@vitejs/plugin-vue@6.0.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))(vue@3.5.22(typescript@5.9.3))':
dependencies:
'@rolldown/pluginutils': 1.0.0-beta.29
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
vue: 3.5.22(typescript@5.9.3)
+ '@vitest/expect@3.2.7':
+ dependencies:
+ '@types/chai': 5.2.3
+ '@vitest/spy': 3.2.7
+ '@vitest/utils': 3.2.7
+ chai: 5.3.3
+ tinyrainbow: 2.0.0
+
+ '@vitest/mocker@3.2.7(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1))':
+ dependencies:
+ '@vitest/spy': 3.2.7
+ estree-walker: 3.0.3
+ magic-string: 0.30.19
+ optionalDependencies:
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)
+
+ '@vitest/pretty-format@3.2.7':
+ dependencies:
+ tinyrainbow: 2.0.0
+
+ '@vitest/runner@3.2.7':
+ dependencies:
+ '@vitest/utils': 3.2.7
+ pathe: 2.0.3
+ strip-literal: 3.1.0
+
+ '@vitest/snapshot@3.2.7':
+ dependencies:
+ '@vitest/pretty-format': 3.2.7
+ magic-string: 0.30.19
+ pathe: 2.0.3
+
+ '@vitest/spy@3.2.7':
+ dependencies:
+ tinyspy: 4.0.4
+
+ '@vitest/utils@3.2.7':
+ dependencies:
+ '@vitest/pretty-format': 3.2.7
+ loupe: 3.2.1
+ tinyrainbow: 2.0.0
+
'@volar/language-core@2.4.23':
dependencies:
'@volar/source-map': 2.4.23
+ '@volar/language-core@2.4.28':
+ dependencies:
+ '@volar/source-map': 2.4.28
+
'@volar/source-map@2.4.23': {}
+ '@volar/source-map@2.4.28': {}
+
'@volar/typescript@2.4.23':
dependencies:
'@volar/language-core': 2.4.23
path-browserify: 1.0.1
vscode-uri: 3.1.0
+ '@volar/typescript@2.4.28':
+ dependencies:
+ '@volar/language-core': 2.4.28
+ path-browserify: 1.0.1
+ vscode-uri: 3.1.0
+
'@vue/babel-helper-vue-transform-on@1.5.0': {}
'@vue/babel-plugin-jsx@1.5.0(@babel/core@7.28.4)':
@@ -10378,7 +11259,7 @@ snapshots:
'@vue/babel-plugin-resolve-type@1.5.0(@babel/core@7.28.4)':
dependencies:
- '@babel/code-frame': 7.27.1
+ '@babel/code-frame': 7.29.0
'@babel/core': 7.28.4
'@babel/helper-module-imports': 7.27.1
'@babel/helper-plugin-utils': 7.27.1
@@ -10571,9 +11452,9 @@ snapshots:
mime-types: 3.0.1
negotiator: 1.0.0
- acorn-import-attributes@1.9.5(acorn@8.15.0):
+ acorn-import-attributes@1.9.5(acorn@8.18.0):
dependencies:
- acorn: 8.15.0
+ acorn: 8.18.0
acorn-jsx@5.3.2(acorn@8.15.0):
dependencies:
@@ -10587,6 +11468,8 @@ snapshots:
acorn@8.18.0: {}
+ agent-base@7.1.4: {}
+
ajv-draft-04@1.0.0(ajv@8.13.0):
optionalDependencies:
ajv: 8.13.0
@@ -10654,6 +11537,8 @@ snapshots:
dependencies:
color-convert: 2.0.1
+ ansi-styles@5.2.0: {}
+
ansi-styles@6.2.3: {}
any-promise@1.3.0: {}
@@ -10673,6 +11558,10 @@ snapshots:
argparse@2.0.1: {}
+ aria-query@5.3.0:
+ dependencies:
+ dequal: 2.0.3
+
aria-query@5.3.2: {}
array-buffer-byte-length@1.0.2:
@@ -10742,6 +11631,8 @@ snapshots:
get-intrinsic: 1.3.0
is-array-buffer: 3.0.5
+ assertion-error@2.0.1: {}
+
ast-types-flow@0.0.8: {}
astral-regex@2.0.0: {}
@@ -10896,6 +11787,8 @@ snapshots:
bytes@3.1.2: {}
+ cac@6.7.14: {}
+
cacheable@2.3.4:
dependencies:
'@cacheable/memory': 2.0.8
@@ -10940,6 +11833,14 @@ snapshots:
ccount@2.0.1: {}
+ chai@5.3.3:
+ dependencies:
+ assertion-error: 2.0.1
+ check-error: 2.1.3
+ deep-eql: 5.0.2
+ loupe: 3.2.1
+ pathval: 2.0.1
+
chalk@4.1.2:
dependencies:
ansi-styles: 4.3.0
@@ -10951,6 +11852,8 @@ snapshots:
character-entities-legacy@3.0.0: {}
+ check-error@2.1.3: {}
+
chokidar@3.6.0:
dependencies:
anymatch: 3.1.3
@@ -11253,6 +12156,11 @@ snapshots:
dependencies:
css-tree: 2.2.1
+ cssstyle@4.6.0:
+ dependencies:
+ '@asamuzakjp/css-color': 3.2.0
+ rrweb-cssom: 0.8.0
+
csstype@3.1.3: {}
csstype@3.2.3: {}
@@ -11264,6 +12172,11 @@ snapshots:
damerau-levenshtein@1.0.8: {}
+ data-urls@5.0.0:
+ dependencies:
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.2.0
+
data-view-buffer@1.0.2:
dependencies:
call-bound: 1.0.4
@@ -11302,12 +12215,16 @@ snapshots:
dependencies:
ms: 2.1.3
+ decimal.js@10.6.0: {}
+
dedent-js@1.0.1: {}
deep-eql@4.1.4:
dependencies:
type-detect: 4.1.0
+ deep-eql@5.0.2: {}
+
deep-is@0.1.4: {}
deepmerge@4.3.1: {}
@@ -11332,13 +12249,14 @@ snapshots:
dequal@2.0.3: {}
- detect-libc@2.1.2:
- optional: true
+ detect-libc@2.1.2: {}
detect-node-es@1.1.0: {}
devalue@5.3.2: {}
+ devalue@5.9.0: {}
+
devlop@1.1.0:
dependencies:
dequal: 2.0.3
@@ -11355,6 +12273,8 @@ snapshots:
dependencies:
esutils: 2.0.3
+ dom-accessibility-api@0.5.16: {}
+
dom-serializer@1.4.1:
dependencies:
domelementtype: 2.3.0
@@ -11727,7 +12647,7 @@ snapshots:
tinyglobby: 0.2.15
unrs-resolver: 1.11.1
optionalDependencies:
- eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.37.0(jiti@1.21.7))
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7))
transitivePeerDependencies:
- supports-color
@@ -11753,7 +12673,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
- eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.37.0(jiti@1.21.7)):
+ eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7)):
dependencies:
'@rtsao/scc': 1.1.0
array-includes: 3.1.9
@@ -11984,6 +12904,12 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
+ esrap@2.3.3(@typescript-eslint/types@8.59.0):
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+ optionalDependencies:
+ '@typescript-eslint/types': 8.59.0
+
esrecurse@4.3.0:
dependencies:
estraverse: 5.3.0
@@ -12015,6 +12941,8 @@ snapshots:
events@3.3.0: {}
+ expect-type@1.4.0: {}
+
express@5.1.0:
dependencies:
accepts: 2.0.0
@@ -12093,6 +13021,10 @@ snapshots:
optionalDependencies:
picomatch: 4.0.3
+ fdir@6.5.0(picomatch@4.0.5):
+ optionalDependencies:
+ picomatch: 4.0.5
+
file-entry-cache@11.1.2:
dependencies:
flat-cache: 6.1.22
@@ -12350,6 +13282,10 @@ snapshots:
hookified@2.1.1: {}
+ html-encoding-sniffer@4.0.0:
+ dependencies:
+ whatwg-encoding: 3.1.1
+
html-entities@2.3.3: {}
html-tags@3.3.1: {}
@@ -12373,6 +13309,20 @@ snapshots:
statuses: 2.0.1
toidentifier: 1.0.1
+ http-proxy-agent@7.0.2:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
+ https-proxy-agent@7.0.6:
+ dependencies:
+ agent-base: 7.1.4
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
husky@9.1.7: {}
iconv-lite@0.6.3:
@@ -12563,6 +13513,8 @@ snapshots:
is-plain-object@5.0.0: {}
+ is-potential-custom-element-name@1.0.1: {}
+
is-promise@4.0.0: {}
is-reference@1.2.1:
@@ -12664,12 +13616,45 @@ snapshots:
joycon@3.1.1: {}
+ js-tokens@10.0.0:
+ optional: true
+
js-tokens@4.0.0: {}
+ js-tokens@9.0.1: {}
+
js-yaml@4.1.0:
dependencies:
argparse: 2.0.1
+ jsdom@24.1.3:
+ dependencies:
+ cssstyle: 4.6.0
+ data-urls: 5.0.0
+ decimal.js: 10.6.0
+ form-data: 4.0.5
+ html-encoding-sniffer: 4.0.0
+ http-proxy-agent: 7.0.2
+ https-proxy-agent: 7.0.6
+ is-potential-custom-element-name: 1.0.1
+ nwsapi: 2.2.24
+ parse5: 7.3.0
+ rrweb-cssom: 0.7.1
+ saxes: 6.0.0
+ symbol-tree: 3.2.4
+ tough-cookie: 4.1.4
+ w3c-xmlserializer: 5.0.0
+ webidl-conversions: 7.0.0
+ whatwg-encoding: 3.1.1
+ whatwg-mimetype: 4.0.0
+ whatwg-url: 14.2.0
+ ws: 8.21.1
+ xml-name-validator: 5.0.0
+ transitivePeerDependencies:
+ - bufferutil
+ - supports-color
+ - utf-8-validate
+
jsesc@3.1.0: {}
json-buffer@3.0.1: {}
@@ -12739,6 +13724,55 @@ snapshots:
prelude-ls: 1.2.1
type-check: 0.4.0
+ lightningcss-android-arm64@1.33.0:
+ optional: true
+
+ lightningcss-darwin-arm64@1.33.0:
+ optional: true
+
+ lightningcss-darwin-x64@1.33.0:
+ optional: true
+
+ lightningcss-freebsd-x64@1.33.0:
+ optional: true
+
+ lightningcss-linux-arm-gnueabihf@1.33.0:
+ optional: true
+
+ lightningcss-linux-arm64-gnu@1.33.0:
+ optional: true
+
+ lightningcss-linux-arm64-musl@1.33.0:
+ optional: true
+
+ lightningcss-linux-x64-gnu@1.33.0:
+ optional: true
+
+ lightningcss-linux-x64-musl@1.33.0:
+ optional: true
+
+ lightningcss-win32-arm64-msvc@1.33.0:
+ optional: true
+
+ lightningcss-win32-x64-msvc@1.33.0:
+ optional: true
+
+ lightningcss@1.33.0:
+ dependencies:
+ detect-libc: 2.1.2
+ optionalDependencies:
+ lightningcss-android-arm64: 1.33.0
+ lightningcss-darwin-arm64: 1.33.0
+ lightningcss-darwin-x64: 1.33.0
+ lightningcss-freebsd-x64: 1.33.0
+ lightningcss-linux-arm-gnueabihf: 1.33.0
+ lightningcss-linux-arm64-gnu: 1.33.0
+ lightningcss-linux-arm64-musl: 1.33.0
+ lightningcss-linux-x64-gnu: 1.33.0
+ lightningcss-linux-x64-musl: 1.33.0
+ lightningcss-win32-arm64-msvc: 1.33.0
+ lightningcss-win32-x64-msvc: 1.33.0
+
lilconfig@2.1.0: {}
lilconfig@3.1.3: {}
@@ -12783,6 +13817,8 @@ snapshots:
dependencies:
js-tokens: 4.0.0
+ loupe@3.2.1: {}
+
lowlight@3.3.0:
dependencies:
'@types/hast': 3.0.4
@@ -12805,6 +13841,10 @@ snapshots:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
+ magic-string@0.30.21:
+ dependencies:
+ '@jridgewell/sourcemap-codec': 1.5.5
+
make-error@1.3.6: {}
markdown-it@14.3.0:
@@ -13010,6 +14050,8 @@ snapshots:
dependencies:
boolbase: 1.0.0
+ nwsapi@2.2.24: {}
+
object-assign@4.1.1: {}
object-hash@3.0.0: {}
@@ -13056,6 +14098,20 @@ snapshots:
obliterator@2.0.5: {}
+ octane@0.1.36(@typescript-eslint/types@8.59.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)):
+ dependencies:
+ '@tsrx/core': 0.1.58(@typescript-eslint/types@8.59.0)
+ '@types/react': 19.2.18
+ devalue: 5.9.0
+ es-module-lexer: 1.7.0
+ esrap: 2.3.3(@typescript-eslint/types@8.59.0)
+ optionalDependencies:
+ react: 19.2.0
+ react-dom: 19.2.0(react@19.2.0)
+ vite: 8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)
+ transitivePeerDependencies:
+ - '@typescript-eslint/types'
+
on-exit-leak-free@2.1.2: {}
on-finished@2.4.1:
@@ -13128,7 +14184,7 @@ snapshots:
parse-json@5.2.0:
dependencies:
- '@babel/code-frame': 7.27.1
+ '@babel/code-frame': 7.29.0
error-ex: 1.3.4
json-parse-even-better-errors: 2.3.1
lines-and-columns: 1.2.4
@@ -13158,6 +14214,8 @@ snapshots:
pathe@2.0.3: {}
+ pathval@2.0.1: {}
+
periscopic@3.1.0:
dependencies:
'@types/estree': 1.0.8
@@ -13170,6 +14228,8 @@ snapshots:
picomatch@4.0.3: {}
+ picomatch@4.0.5: {}
+
pify@2.3.0: {}
pify@5.0.0: {}
@@ -13734,6 +14794,12 @@ snapshots:
prettier@3.8.3: {}
+ pretty-format@27.5.1:
+ dependencies:
+ ansi-regex: 5.0.1
+ ansi-styles: 5.2.0
+ react-is: 17.0.2
+
pretty-hrtime@1.0.3: {}
process-warning@5.0.0: {}
@@ -13753,7 +14819,7 @@ snapshots:
eslint: 9.37.0(jiti@1.21.7)
eslint-config-prettier: 10.1.8(eslint@9.37.0(jiti@1.21.7))
eslint-import-resolver-typescript: 4.4.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7))
- eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4)(eslint@9.37.0(jiti@1.21.7))
+ eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint-import-resolver-typescript@4.4.4(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.59.0(eslint@9.37.0(jiti@1.21.7))(typescript@5.9.3))(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7))
eslint-plugin-jsx-a11y: 6.10.2(eslint@9.37.0(jiti@1.21.7))
eslint-plugin-prettier: 5.5.5(eslint-config-prettier@10.1.8(eslint@9.37.0(jiti@1.21.7)))(eslint@9.37.0(jiti@1.21.7))(prettier@3.8.3)
eslint-plugin-react: 7.37.5(eslint@9.37.0(jiti@1.21.7))
@@ -13798,6 +14864,10 @@ snapshots:
proxy-from-env@2.1.0: {}
+ psl@1.15.0:
+ dependencies:
+ punycode: 2.3.1
+
publint@0.3.14:
dependencies:
'@publint/pack': 0.1.2
@@ -13824,6 +14894,8 @@ snapshots:
quansync@0.2.11: {}
+ querystringify@2.2.0: {}
+
queue-microtask@1.2.3: {}
quick-format-unescaped@4.0.4: {}
@@ -13963,6 +15035,8 @@ snapshots:
require-from-string@2.0.2: {}
+ requires-port@1.0.0: {}
+
resolve-from@4.0.0: {}
resolve-from@5.0.0: {}
@@ -13988,6 +15062,37 @@ snapshots:
reusify@1.1.0: {}
+ rolldown@1.2.4:
+ dependencies:
+ '@oxc-project/types': 0.144.0
+ '@rolldown/pluginutils': 1.0.1
+ optionalDependencies:
+ '@rolldown/binding-android-arm64': 1.2.4
+ '@rolldown/binding-darwin-arm64': 1.2.4
+ '@rolldown/binding-darwin-x64': 1.2.4
+ '@rolldown/binding-freebsd-x64': 1.2.4
+ '@rolldown/binding-linux-arm-gnueabihf': 1.2.4
+ '@rolldown/binding-linux-arm64-gnu': 1.2.4
+ '@rolldown/binding-linux-arm64-musl': 1.2.4
+ '@rolldown/binding-linux-ppc64-gnu': 1.2.4
+ '@rolldown/binding-linux-s390x-gnu': 1.2.4
+ '@rolldown/binding-linux-x64-gnu': 1.2.4
+ '@rolldown/binding-linux-x64-musl': 1.2.4
+ '@rolldown/binding-openharmony-arm64': 1.2.4
+ '@rolldown/binding-win32-arm64-msvc': 1.2.4
+ '@rolldown/binding-win32-x64-msvc': 1.2.4
+
+ rollup-plugin-dts@6.5.1(rollup@4.60.2)(typescript@5.9.3):
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ '@jridgewell/sourcemap-codec': 1.5.5
+ convert-source-map: 2.0.0
+ magic-string: 0.30.21
+ rollup: 4.60.2
+ typescript: 5.9.3
+ optionalDependencies:
+ '@babel/code-frame': 8.0.0
+
rollup-plugin-postcss@4.0.2(postcss@8.5.25)(ts-node@10.9.2(@swc/core@1.15.30(@swc/helpers@0.5.23))(@types/node@22.19.17)(typescript@5.9.3)):
dependencies:
chalk: 4.1.2
@@ -14080,6 +15185,10 @@ snapshots:
transitivePeerDependencies:
- supports-color
+ rrweb-cssom@0.7.1: {}
+
+ rrweb-cssom@0.8.0: {}
+
rsbuild-plugin-tailwindcss@0.2.4(@rsbuild/core@2.1.7)(tailwindcss@3.4.19(yaml@2.8.1)):
dependencies:
tailwindcss: 3.4.19(yaml@2.8.1)
@@ -14127,6 +15236,10 @@ snapshots:
sax@1.6.1: {}
+ saxes@6.0.0:
+ dependencies:
+ xmlchars: 2.2.0
+
scheduler@0.26.0: {}
scheduler@0.27.0: {}
@@ -14294,6 +15407,8 @@ snapshots:
side-channel-map: 1.0.1
side-channel-weakmap: 1.0.2
+ siginfo@2.0.0: {}
+
signal-exit@3.0.7: {}
signal-exit@4.1.0: {}
@@ -14400,6 +15515,8 @@ snapshots:
dependencies:
escape-string-regexp: 2.0.0
+ stackback@0.0.2: {}
+
static-browser-server@1.0.3:
dependencies:
'@open-draft/deferred-promise': 2.2.0
@@ -14411,6 +15528,8 @@ snapshots:
statuses@2.0.2: {}
+ std-env@3.10.0: {}
+
stop-iteration-iterator@1.1.0:
dependencies:
es-errors: 1.3.0
@@ -14518,6 +15637,10 @@ snapshots:
strip-json-comments@5.0.3: {}
+ strip-literal@3.1.0:
+ dependencies:
+ js-tokens: 9.0.1
+
style-inject@0.3.0: {}
style-mod@4.1.2: {}
@@ -14740,6 +15863,8 @@ snapshots:
picocolors: 1.1.1
sax: 1.6.1
+ symbol-tree@3.2.4: {}
+
synckit@0.11.12:
dependencies:
'@pkgr/core': 0.2.9
@@ -14815,7 +15940,7 @@ snapshots:
terser@5.44.0:
dependencies:
'@jridgewell/source-map': 0.3.11
- acorn: 8.15.0
+ acorn: 8.18.0
commander: 2.20.3
source-map-support: 0.5.21
@@ -14835,13 +15960,28 @@ snapshots:
tiny-invariant@1.3.3: {}
+ tinybench@2.9.0: {}
+
+ tinyexec@0.3.2: {}
+
tinyglobby@0.2.15:
dependencies:
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
+ tinyglobby@0.2.17:
+ dependencies:
+ fdir: 6.5.0(picomatch@4.0.5)
+ picomatch: 4.0.5
+
+ tinypool@1.1.1: {}
+
tinypool@2.1.0: {}
+ tinyrainbow@2.0.0: {}
+
+ tinyspy@4.0.4: {}
+
to-regex-range@5.0.1:
dependencies:
is-number: 7.0.0
@@ -14850,6 +15990,17 @@ snapshots:
totalist@3.0.1: {}
+ tough-cookie@4.1.4:
+ dependencies:
+ psl: 1.15.0
+ punycode: 2.3.1
+ universalify: 0.2.0
+ url-parse: 1.5.10
+
+ tr46@5.1.1:
+ dependencies:
+ punycode: 2.3.1
+
trim-lines@3.0.1: {}
ts-api-utils@2.1.0(typescript@5.9.3):
@@ -15008,6 +16159,8 @@ snapshots:
unist-util-is: 6.0.0
unist-util-visit-parents: 6.0.1
+ universalify@0.2.0: {}
+
universalify@2.0.1: {}
unpipe@1.0.0: {}
@@ -15058,6 +16211,11 @@ snapshots:
dependencies:
punycode: 2.3.1
+ url-parse@1.5.10:
+ dependencies:
+ querystringify: 2.2.0
+ requires-port: 1.0.0
+
use-callback-ref@1.3.3(@types/react@19.2.2)(react@19.2.0):
dependencies:
react: 19.2.0
@@ -15116,12 +16274,33 @@ snapshots:
'@types/unist': 3.0.3
vfile-message: 4.0.3
- vite-plugin-devtools-json@1.0.0(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)):
+ vite-node@3.2.4(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1):
+ dependencies:
+ cac: 6.7.14
+ debug: 4.4.3
+ es-module-lexer: 1.7.0
+ pathe: 2.0.3
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)
+ transitivePeerDependencies:
+ - '@types/node'
+ - jiti
+ - less
+ - lightningcss
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
+
+ vite-plugin-devtools-json@1.0.0(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)):
dependencies:
uuid: 11.1.0
- vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
- vite-plugin-dts@4.5.4(@types/node@22.19.17)(rollup@4.60.2)(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)):
+ vite-plugin-dts@4.5.4(@types/node@22.19.17)(rollup@4.60.2)(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)):
dependencies:
'@microsoft/api-extractor': 7.53.1(@types/node@22.19.17)
'@rollup/pluginutils': 5.3.0(rollup@4.60.2)
@@ -15134,13 +16313,13 @@ snapshots:
magic-string: 0.30.19
typescript: 5.9.3
optionalDependencies:
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
transitivePeerDependencies:
- '@types/node'
- rollup
- supports-color
- vite-plugin-solid@2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)):
+ vite-plugin-solid@2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)):
dependencies:
'@babel/core': 7.28.4
'@types/babel__core': 7.20.5
@@ -15148,12 +16327,12 @@ snapshots:
merge-anything: 5.1.7
solid-js: 1.9.9
solid-refresh: 0.6.3(solid-js@1.9.9)
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
- vitefu: 1.1.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ vitefu: 1.1.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0))
transitivePeerDependencies:
- supports-color
- vite-plugin-solid@2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)):
+ vite-plugin-solid@2.11.9(solid-js@1.9.9)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)):
dependencies:
'@babel/core': 7.28.4
'@types/babel__core': 7.20.5
@@ -15161,23 +16340,23 @@ snapshots:
merge-anything: 5.1.7
solid-js: 1.9.9
solid-refresh: 0.6.3(solid-js@1.9.9)
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
- vitefu: 1.1.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
+ vitefu: 1.1.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0))
transitivePeerDependencies:
- supports-color
- vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)):
+ vite-tsconfig-paths@5.1.4(typescript@5.9.3)(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)):
dependencies:
debug: 4.4.3
globrex: 0.1.2
tsconfck: 3.1.6(typescript@5.9.3)
optionalDependencies:
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
transitivePeerDependencies:
- supports-color
- typescript
- vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0):
+ vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0):
dependencies:
esbuild: 0.21.5
postcss: 8.5.25
@@ -15185,10 +16364,11 @@ snapshots:
optionalDependencies:
'@types/node': 22.19.17
fsevents: 2.3.3
+ lightningcss: 1.33.0
sugarss: 5.0.1(postcss@8.5.25)
terser: 5.44.0
- vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0):
+ vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0):
dependencies:
esbuild: 0.21.5
postcss: 8.5.25
@@ -15196,36 +16376,112 @@ snapshots:
optionalDependencies:
'@types/node': 22.19.17
fsevents: 2.3.3
+ lightningcss: 1.33.0
sugarss: 5.0.1(postcss@8.5.6)
terser: 5.44.0
- vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1):
+ vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1):
dependencies:
esbuild: 0.25.10
fdir: 6.5.0(picomatch@4.0.3)
picomatch: 4.0.3
postcss: 8.5.25
- rollup: 4.52.4
+ rollup: 4.60.2
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ '@types/node': 22.19.17
+ fsevents: 2.3.3
+ jiti: 1.21.7
+ lightningcss: 1.33.0
+ sugarss: 5.0.1(postcss@8.5.25)
+ terser: 5.44.0
+ yaml: 2.8.1
+
+ vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1):
+ dependencies:
+ esbuild: 0.25.10
+ fdir: 6.5.0(picomatch@4.0.3)
+ picomatch: 4.0.3
+ postcss: 8.5.25
+ rollup: 4.60.2
tinyglobby: 0.2.15
optionalDependencies:
'@types/node': 22.19.17
fsevents: 2.3.3
jiti: 1.21.7
+ lightningcss: 1.33.0
sugarss: 5.0.1(postcss@8.5.6)
terser: 5.44.0
yaml: 2.8.1
- vitefu@1.1.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)):
+ vite@8.2.1(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1):
+ dependencies:
+ lightningcss: 1.33.0
+ picomatch: 4.0.5
+ postcss: 8.5.25
+ rolldown: 1.2.4
+ tinyglobby: 0.2.17
+ optionalDependencies:
+ '@types/node': 22.19.17
+ fsevents: 2.3.3
+ jiti: 1.21.7
+ sugarss: 5.0.1(postcss@8.5.25)
+ terser: 5.44.0
+ yaml: 2.8.1
+
+ vitefu@1.1.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)):
optionalDependencies:
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)
- vitefu@1.1.1(vite@5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)):
+ vitefu@1.1.1(vite@5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)):
optionalDependencies:
- vite: 5.4.20(@types/node@22.19.17)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
+ vite: 5.4.20(@types/node@22.19.17)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)
- vitefu@1.1.1(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)):
+ vitefu@1.1.1(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)):
optionalDependencies:
- vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.6))(terser@5.44.0)(yaml@2.8.1)
+
+ vitest@3.2.7(@types/node@22.19.17)(jiti@1.21.7)(jsdom@24.1.3)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1):
+ dependencies:
+ '@types/chai': 5.2.3
+ '@vitest/expect': 3.2.7
+ '@vitest/mocker': 3.2.7(vite@6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1))
+ '@vitest/pretty-format': 3.2.7
+ '@vitest/runner': 3.2.7
+ '@vitest/snapshot': 3.2.7
+ '@vitest/spy': 3.2.7
+ '@vitest/utils': 3.2.7
+ chai: 5.3.3
+ debug: 4.4.3
+ expect-type: 1.4.0
+ magic-string: 0.30.19
+ pathe: 2.0.3
+ picomatch: 4.0.3
+ std-env: 3.10.0
+ tinybench: 2.9.0
+ tinyexec: 0.3.2
+ tinyglobby: 0.2.15
+ tinypool: 1.1.1
+ tinyrainbow: 2.0.0
+ vite: 6.3.6(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)
+ vite-node: 3.2.4(@types/node@22.19.17)(jiti@1.21.7)(lightningcss@1.33.0)(sugarss@5.0.1(postcss@8.5.25))(terser@5.44.0)(yaml@2.8.1)
+ why-is-node-running: 2.3.0
+ optionalDependencies:
+ '@types/node': 22.19.17
+ jsdom: 24.1.3
+ transitivePeerDependencies:
+ - jiti
+ - less
+ - lightningcss
+ - msw
+ - sass
+ - sass-embedded
+ - stylus
+ - sugarss
+ - supports-color
+ - terser
+ - tsx
+ - yaml
vscode-uri@3.1.0: {}
@@ -15247,12 +16503,18 @@ snapshots:
w3c-keyname@2.2.8: {}
+ w3c-xmlserializer@5.0.0:
+ dependencies:
+ xml-name-validator: 5.0.0
+
wasm-feature-detect@1.8.0: {}
watchpack@2.5.2:
dependencies:
graceful-fs: 4.2.11
+ webidl-conversions@7.0.0: {}
+
webpack-sources@3.5.1: {}
webpack@5.109.2(@swc/core@1.15.30(@swc/helpers@0.5.23))(postcss@8.5.25):
@@ -15291,6 +16553,17 @@ snapshots:
- postcss
- uglify-js
+ whatwg-encoding@3.1.1:
+ dependencies:
+ iconv-lite: 0.6.3
+
+ whatwg-mimetype@4.0.0: {}
+
+ whatwg-url@14.2.0:
+ dependencies:
+ tr46: 5.1.1
+ webidl-conversions: 7.0.0
+
which-boxed-primitive@1.1.1:
dependencies:
is-bigint: 1.1.0
@@ -15340,6 +16613,11 @@ snapshots:
dependencies:
isexe: 2.0.0
+ why-is-node-running@2.3.0:
+ dependencies:
+ siginfo: 2.0.0
+ stackback: 0.0.2
+
widest-line@5.0.0:
dependencies:
string-width: 7.2.0
@@ -15374,6 +16652,10 @@ snapshots:
ws@8.21.1: {}
+ xml-name-validator@5.0.0: {}
+
+ xmlchars@2.2.0: {}
+
y18n@5.0.8: {}
yallist@3.1.1: {}
diff --git a/scripts/build.ts b/scripts/build.ts
index 8169e73..eb79c90 100644
--- a/scripts/build.ts
+++ b/scripts/build.ts
@@ -90,6 +90,18 @@ const buildLynx = async () => {
await copyCss("lynx", "diff-view.css");
};
+const buildOctane = async () => {
+ await new Promise((resolve, reject) => {
+ const process = spawn("pnpm", ["run", "build"], {
+ cwd: "packages/octane",
+ shell: true,
+ stdio: "inherit",
+ });
+ process.on("close", (code) => (code === 0 ? resolve() : reject(new Error(`Octane build exited with ${code}`))));
+ process.on("error", reject);
+ });
+};
+
const buildSolid = async () => {
await new Promise((r, j) => {
const ls = spawn(`cd packages/solid && pnpm run build`, { shell: true, stdio: "inherit" });
@@ -139,6 +151,7 @@ const start = async () => {
await buildCli();
await buildReact();
await buildLynx();
+ await buildOctane();
await buildSolid();
await buildSvelte();
await buildVue();
diff --git a/scripts/release.ts b/scripts/release.ts
index ce340f3..a66226d 100644
--- a/scripts/release.ts
+++ b/scripts/release.ts
@@ -7,6 +7,7 @@ const pkgNameAlias = {
"@git-diff-view/vue": "vue",
"@git-diff-view/file": "file",
"@git-diff-view/react": "react",
+ "@git-diff-view/octane": "octane",
"@git-diff-view/lowlight": "lowlight",
"@git-diff-view/shiki": "shiki",
"@git-diff-view/lezer": "lezer",
@@ -73,6 +74,7 @@ const run = async () => {
await release("@git-diff-view/core");
await release("@git-diff-view/file");
await release("@git-diff-view/react");
+ await release("@git-diff-view/octane");
await release("@git-diff-view/vue");
await release("@git-diff-view/solid");
await release("@git-diff-view/svelte");